diff --git a/connect.py b/connect.py index f8f1352f4..46b1da82b 100644 --- a/connect.py +++ b/connect.py @@ -40,11 +40,10 @@ except ImportError: CONF.read(os.path.join(BASE_DIR, 'jumpserver.conf')) log_dir = os.path.join(BASE_DIR, 'logs') -login_name = getpass.getuser() -user = Juser(username=login_name) +login_user = Juser(username=getpass.getuser()) -def color_print(msg, color='blue'): +def color_print(msg, color='red', exits=False): """ Print colorful string. 颜色打印 @@ -54,199 +53,133 @@ def color_print(msg, color='blue'): 'red': '\033[1;31m%s\033[0m'} print color_msg.get(color, 'blue') % msg + if exits: + time.sleep(2) + sys.exit() -def color_print_exit(msg, color='red'): - """ - Print colorful string and exit. - 颜色打印并推出 - """ - color_print(msg, color=color) - time.sleep(2) - sys.exit() +class Jtty(object): + def __init__(self, chan, user, asset): + self.chan = chan + self.username = user.username + self.ip = asset.ip + @staticmethod + def get_win_size(): + """ + This function use to get the size of the windows! + 获得terminal窗口大小 + """ + if 'TIOCGWINSZ' in dir(termios): + TIOCGWINSZ = termios.TIOCGWINSZ + else: + TIOCGWINSZ = 1074295912L + s = struct.pack('HHHH', 0, 0, 0, 0) + x = fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ, s) + return struct.unpack('HHHH', x)[0:2] -def get_win_size(): - """ - This function use to get the size of the windows! - 获得terminal窗口大小 - """ - if 'TIOCGWINSZ' in dir(termios): - TIOCGWINSZ = termios.TIOCGWINSZ - else: - TIOCGWINSZ = 1074295912L - s = struct.pack('HHHH', 0, 0, 0, 0) - x = fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ, s) - return struct.unpack('HHHH', x)[0:2] - - -def set_win_size(sig, data): - """ - This function use to set the window size of the terminal! - 设置terminal窗口大小 - """ - try: - win_size = get_win_size() - channel.resize_pty(height=win_size[0], width=win_size[1]) - except Exception: - pass - - -def log_record(username, host): - """ - Logging user command and output. - 记录用户的日志 - """ - connect_log_dir = os.path.join(log_dir, 'connect') - timestamp_start = int(time.time()) - today = time.strftime('%Y%m%d', time.localtime(timestamp_start)) - time_now = time.strftime('%H%M%S', time.localtime(timestamp_start)) - today_connect_log_dir = os.path.join(connect_log_dir, today) - log_filename = '%s_%s_%s.log' % (username, host, time_now) - log_file_path = os.path.join(today_connect_log_dir, log_filename) - dept = User.objects.filter(username=username) - if dept: - dept = dept[0] - dept_name = dept.name - else: - dept_name = 'None' - - pid = os.getpid() - pts = os.popen("ps axu | grep %s | grep -v grep | awk '{ print $7 }'" % pid).read().strip() - remote_ip = os.popen("who | grep %s | awk '{ print $5 }'" % pts).read().strip('()\n') - - if not os.path.isdir(today_connect_log_dir): + def set_win_size(self, sig, data): + """ + This function use to set the window size of the terminal! + 设置terminal窗口大小 + """ try: - os.makedirs(today_connect_log_dir) - os.chmod(today_connect_log_dir, 0777) - except OSError: - raise ServerError('Create %s failed, Please modify %s permission.' % (today_connect_log_dir, connect_log_dir)) + win_size = self.get_win_size() + self.channel.resize_pty(height=win_size[0], width=win_size[1]) + except Exception: + pass - try: - log_file = open(log_file_path, 'a') - except IOError: - raise ServerError('Create logfile failed, Please modify %s permission.' % today_connect_log_dir) + def log_record(self): + """ + Logging user command and output. + 记录用户的日志 + """ + tty_log_dir = os.path.join(log_dir, 'tty') + timestamp_start = int(time.time()) + date_start = time.strftime('%Y%m%d', time.localtime(timestamp_start)) + time_start = time.strftime('%H%M%S', time.localtime(timestamp_start)) + today_connect_log_dir = os.path.join(tty_log_dir, date_start) + log_filename = '%s_%s_%s.log' % (self.username, self.host, time_start) + log_file_path = os.path.join(today_connect_log_dir, log_filename) + dept = User.objects.filter(username=username) + if dept: + dept = dept[0] + dept_name = dept.name + else: + dept_name = 'None' - log = Log(user=username, host=host, remote_ip=remote_ip, dept_name=dept_name, - log_path=log_file_path, start_time=datetime.datetime.now(), pid=pid) - log_file.write('Start time is %s\n' % datetime.datetime.now()) - log.save() - return log_file, log + pid = os.getpid() + pts = os.popen("ps axu | grep %s | grep -v grep | awk '{ print $7 }'" % pid).read().strip() + remote_ip = os.popen("who | grep %s | awk '{ print $5 }'" % pts).read().strip('()\n') - -def posix_shell(chan, username, host): - """ - Use paramiko channel connect server interactive. - 使用paramiko模块的channel,连接后端,进入交互式 - """ - log_file, log = log_record(username, host) - old_tty = termios.tcgetattr(sys.stdin) - try: - tty.setraw(sys.stdin.fileno()) - tty.setcbreak(sys.stdin.fileno()) - chan.settimeout(0.0) - - while True: + if not os.path.isdir(today_connect_log_dir): try: - r, w, e = select.select([chan, sys.stdin], [], []) - except Exception: - pass + os.makedirs(today_connect_log_dir) + os.chmod(today_connect_log_dir, 0777) + except OSError: + raise ServerError('Create %s failed, Please modify %s permission.' % (today_connect_log_dir, connect_log_dir)) - if chan in r: + try: + log_file = open(log_file_path, 'a') + except IOError: + raise ServerError('Create logfile failed, Please modify %s permission.' % today_connect_log_dir) + + log = Log(user=username, host=host, remote_ip=remote_ip, dept_name=dept_name, + log_path=log_file_path, start_time=datetime.datetime.now(), pid=pid) + log_file.write('Start time is %s\n' % datetime.datetime.now()) + log.save() + return log_file, log + + def posix_shell(chan, username, host): + """ + Use paramiko channel connect server interactive. + 使用paramiko模块的channel,连接后端,进入交互式 + """ + log_file, log = log_record(username, host) + old_tty = termios.tcgetattr(sys.stdin) + try: + tty.setraw(sys.stdin.fileno()) + tty.setcbreak(sys.stdin.fileno()) + chan.settimeout(0.0) + + while True: try: - x = chan.recv(1024) - if len(x) == 0: - break - sys.stdout.write(x) - sys.stdout.flush() - log_file.write(x) - log_file.flush() - except socket.timeout: + r, w, e = select.select([chan, sys.stdin], [], []) + except Exception: pass - if sys.stdin in r: - x = os.read(sys.stdin.fileno(), 1) - if len(x) == 0: - break - chan.send(x) + if chan in r: + try: + x = chan.recv(1024) + if len(x) == 0: + break + sys.stdout.write(x) + sys.stdout.flush() + log_file.write(x) + log_file.flush() + except socket.timeout: + pass - finally: - termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty) - log_file.write('End time is %s' % datetime.datetime.now()) - log_file.close() - log.is_finished = True - log.log_finished = False - log.end_time = datetime.datetime.now() - log.save() + if sys.stdin in r: + x = os.read(sys.stdin.fileno(), 1) + if len(x) == 0: + break + chan.send(x) - -# def get_user_host_group(username): -# """ -# Get the host groups of under the user control. -# 获取用户有权限的主机组 -# """ -# groups_attr = {} -# group_all = get_host_groups(username) -# for group in group_all: -# groups_attr[group.name] = [group.id, group.comment] -# return groups_attr - - -# def get_user_host_group_member(username, gid): -# """ -# Get the host group hosts of under the user control. -# 获取用户有权限主机组下的主机 -# """ -# groups_attr = get_user_host_group(username) -# groups_ids = [attr[0] for name, attr in groups_attr.items()] -# hosts_attr = {} -# if int(gid) in groups_ids: -# user = User.objects.filter(username=username) -# if user: -# user = user[0] -# hosts = get_host_groups(gid) -# for host in hosts: -# alias = AssetAlias.objects.filter(user=user, host=host) -# if alias and alias[0].alias != '': -# hosts_attr[host.ip] = [host.id, host.ip, alias[0].alias] -# else: -# hosts_attr[host.ip] = [host.id, host.ip, host.comment] -# return hosts_attr - - -# def user_asset_info(user, printable=False): -# """ -# Get or Print asset info -# 获取或打印用户资产信息 -# """ -# assets_info = {} -# try: -# assets = get_asset(user) -# except ServerError, e: -# color_print(e, 'red') -# return -# -# for asset in assets: -# asset_alias = AssetAlias.objects.filter(user=user, asset=asset) -# if asset_alias and asset_alias[0].alias != '': -# assets_info[asset.ip] = [asset.id, asset.ip, asset_alias[0].alias] -# else: -# assets_info[asset.ip] = [asset.id, asset.ip, asset.comment] -# -# if printable: -# ips = assets_info.keys() -# ips.sort() -# for ip in ips: -# print '%-15s -- %s' % (ip, assets_info[ip][2]) -# print '' -# else: -# return assets_info + finally: + termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty) + log_file.write('End time is %s' % datetime.datetime.now()) + log_file.close() + log.is_finished = True + log.log_finished = False + log.end_time = datetime.datetime.now() + log.save() def verify_connect(username, part_ip): ip_matched = [] try: - assets_info = user.get_asset_info() + assets_info = login_user.get_asset_info() except ServerError, e: color_print(e, 'red') return False @@ -260,7 +193,7 @@ def verify_connect(username, part_ip): if part_ip in info: ip_matched.append(ip) - logger.debug('%s matched input %s: %s' % (user.username, part_ip, ip_matched)) + logger.debug('%s matched input %s: %s' % (login_user.username, part_ip, ip_matched)) ip_matched = list(set(ip_matched)) if len(ip_matched) > 1: @@ -385,7 +318,7 @@ def exec_cmd_servers(username): inputs = raw_input('\033[1;32mip(s)>: \033[0m') if inputs in ['q', 'Q']: break - get_hosts = user.get_asset_info().keys() + get_hosts = login_user.get_asset_info().keys() if ',' in inputs: ips_input = inputs.split(',') @@ -419,8 +352,8 @@ def exec_cmd_servers(username): if __name__ == '__main__': - if not user.validate(): - color_print_exit(u'没有该用户 No that user.') + if not login_user.validate(): + color_print(u'没有该用户 No that user.', exits=True) print_prompt() gid_pattern = re.compile(r'^g\d+$') @@ -434,10 +367,10 @@ if __name__ == '__main__': except KeyboardInterrupt: sys.exit(0) if option in ['P', 'p']: - user.get_asset_info(printable=True) + login_user.get_asset_info(printable=True) continue elif option in ['G', 'g']: - user.get_asset_group_info(printable=True) + login_user.get_asset_group_info(printable=True) continue elif gid_pattern.match(option): gid = option[1:].strip() diff --git a/jumpserver/api.py b/jumpserver/api.py index faebd2843..68831bcb0 100644 --- a/jumpserver/api.py +++ b/jumpserver/api.py @@ -12,6 +12,7 @@ import ldap from ldap import modlist import hashlib import datetime +import random import subprocess from django.core.paginator import Paginator, EmptyPage, InvalidPage from django.http import HttpResponse, Http404 @@ -150,34 +151,57 @@ def pages(posts, r): class PyCrypt(object): - """This class used to encrypt and decrypt password.""" + """ + This class used to encrypt and decrypt password. + 对称加密库 + """ def __init__(self, key): self.key = key self.mode = AES.MODE_CBC - def encrypt(self, text): - cryptor = AES.new(self.key, self.mode, b'0000000000000000') - length = 16 + def _random_pass(self): + """ + random password + 随机生成密码 + """ + salt_key = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@$%^&*()_' + symbol = '!@$%^&*()_' + salt_list = [] + for i in range(60): + salt_list.append(random.choice(salt_key)) + for i in range(4): + salt_list.append(random.choice(symbol)) + salt = ''.join(salt_list) + self.salt = salt + + def encrypt(self): + """ + encrypt gen password + 加密生成密码 + """ + cryptor = AES.new(self.key, self.mode, b'8122ca7d906ad5e1') + length = 64 try: - count = len(text) + count = len(self.salt) except TypeError: - raise ServerError('Encrypt password error, TYpe error.') + # raise ServerError('Encrypt password error, TYpe error.') + pass add = (length - (count % length)) - text += ('\0' * add) - ciphertext = cryptor.encrypt(text) - return b2a_hex(ciphertext) + self.salt += ('\0' * add) + cipher_text = cryptor.encrypt(self.salt) + return b2a_hex(cipher_text) def decrypt(self, text): - cryptor = AES.new(self.key, self.mode, b'0000000000000000') + cryptor = AES.new(self.key, self.mode, b'8122ca7d906ad5e1') try: plain_text = cryptor.decrypt(a2b_hex(text)) except TypeError: - raise ServerError('Decrypt password error, TYpe error.') + # raise ServerError('Decrypt password error, TYpe error.') + pass return plain_text.rstrip('\0') -CRYPTOR = PyCrypt(KEY) class ServerError(Exception): @@ -595,17 +619,15 @@ def asset_perm_api(asset): return user_permed_list -def get_connect_item(username, ip): +def get_connect_item(user, ip): asset = get_object(Asset, ip=ip) port = int(asset.port) if not asset.is_active: raise ServerError('Host %s is not active.' % ip) - user = get_object(User, username=username) - if not user.is_active: - raise ServerError('User %s is not active.' % username) + raise ServerError('User %s is not active.' % user.username) login_type_dict = { 'L': user.ldap_pwd, @@ -613,7 +635,7 @@ def get_connect_item(username, ip): if asset.login_type in login_type_dict: password = CRYPTOR.decrypt(login_type_dict[asset.login_type]) - return username, password, ip, port + return user.username, password, ip, port elif asset.login_type == 'M': username = asset.username @@ -749,4 +771,7 @@ def node_auth(request): else: result = {'auth': {'username': username, 'result': 'failed'}} - return HttpResponse(json.dumps(result, sort_keys=True, indent=2), content_type='application/json') \ No newline at end of file + return HttpResponse(json.dumps(result, sort_keys=True, indent=2), content_type='application/json') + + +CRYPTOR = PyCrypt(KEY) \ No newline at end of file