mirror of https://github.com/jumpserver/jumpserver
bug fix
parent
e408414631
commit
0309213ccc
69
connect.py
69
connect.py
|
@ -49,8 +49,10 @@ def color_print(msg, color='red', exits=False):
|
||||||
"""
|
"""
|
||||||
color_msg = {'blue': '\033[1;36m%s\033[0m',
|
color_msg = {'blue': '\033[1;36m%s\033[0m',
|
||||||
'green': '\033[1;32m%s\033[0m',
|
'green': '\033[1;32m%s\033[0m',
|
||||||
'red': '\033[1;31m%s\033[0m'}
|
'yellow': '\033[1;33m%s\033[0m',
|
||||||
msg = color_msg.get(color, 'blue') % msg
|
'red': '\033[1;31m%s\033[0m',
|
||||||
|
'info': '\033[32m%s\033[0m'}
|
||||||
|
msg = color_msg.get(color, 'red') % msg
|
||||||
print msg
|
print msg
|
||||||
if exits:
|
if exits:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
@ -69,7 +71,7 @@ class Tty(object):
|
||||||
A virtual tty class
|
A virtual tty class
|
||||||
一个虚拟终端类,实现连接ssh和记录日志,基类
|
一个虚拟终端类,实现连接ssh和记录日志,基类
|
||||||
"""
|
"""
|
||||||
def __init__(self, user, asset, role):
|
def __init__(self, user, asset, role, login_type='ssh'):
|
||||||
self.username = user.username
|
self.username = user.username
|
||||||
self.asset_name = asset.hostname
|
self.asset_name = asset.hostname
|
||||||
self.ip = None
|
self.ip = None
|
||||||
|
@ -78,10 +80,8 @@ class Tty(object):
|
||||||
self.asset = asset
|
self.asset = asset
|
||||||
self.user = user
|
self.user = user
|
||||||
self.role = role
|
self.role = role
|
||||||
self.ssh = None
|
|
||||||
self.remote_ip = ''
|
self.remote_ip = ''
|
||||||
self.connect_info = None
|
self.login_type = login_type
|
||||||
self.login_type = 'ssh'
|
|
||||||
self.vim_flag = False
|
self.vim_flag = False
|
||||||
self.ps1_pattern = re.compile('\[.*@.*\][\$#]')
|
self.ps1_pattern = re.compile('\[.*@.*\][\$#]')
|
||||||
self.vim_data = ''
|
self.vim_data = ''
|
||||||
|
@ -241,18 +241,18 @@ class Tty(object):
|
||||||
mkdir(today_connect_log_dir, mode=0777)
|
mkdir(today_connect_log_dir, mode=0777)
|
||||||
except OSError:
|
except OSError:
|
||||||
logger.debug('创建目录 %s 失败,请修改%s目录权限' % (today_connect_log_dir, tty_log_dir))
|
logger.debug('创建目录 %s 失败,请修改%s目录权限' % (today_connect_log_dir, tty_log_dir))
|
||||||
raise ServerError('Create %s failed, Please modify %s permission.' % (today_connect_log_dir, tty_log_dir))
|
raise ServerError('创建目录 %s 失败,请修改%s目录权限' % (today_connect_log_dir, tty_log_dir))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
log_file_f = open(log_file_path + '.log', 'a')
|
log_file_f = open(log_file_path + '.log', 'a')
|
||||||
log_time_f = open(log_file_path + '.time', 'a')
|
log_time_f = open(log_file_path + '.time', 'a')
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.debug('创建tty日志文件失败, 请修改目录%s权限' % today_connect_log_dir)
|
logger.debug('创建tty日志文件失败, 请修改目录%s权限' % today_connect_log_dir)
|
||||||
raise ServerError('Create logfile failed, Please modify %s permission.' % today_connect_log_dir)
|
raise ServerError('创建tty日志文件失败, 请修改目录%s权限' % today_connect_log_dir)
|
||||||
|
|
||||||
if self.login_type == 'ssh': # 如果是ssh连接过来,记录connect.py的pid,web terminal记录为日志的id
|
if self.login_type == 'ssh': # 如果是ssh连接过来,记录connect.py的pid,web terminal记录为日志的id
|
||||||
pid = os.getpid()
|
pid = os.getpid()
|
||||||
self.remote_ip = remote_ip # 获取远端IP
|
self.remote_ip = remote_ip # 获取远端IP
|
||||||
else:
|
else:
|
||||||
pid = 0
|
pid = 0
|
||||||
|
|
||||||
|
@ -260,7 +260,7 @@ class Tty(object):
|
||||||
log_path=log_file_path, start_time=date_today, pid=pid)
|
log_path=log_file_path, start_time=date_today, pid=pid)
|
||||||
log.save()
|
log.save()
|
||||||
if self.login_type == 'web':
|
if self.login_type == 'web':
|
||||||
log.pid = log.id
|
log.pid = log.id # 设置log id为websocket的id, 然后kill时干掉websocket
|
||||||
log.save()
|
log.save()
|
||||||
|
|
||||||
log_file_f.write('Start at %s\r\n' % datetime.datetime.now())
|
log_file_f.write('Start at %s\r\n' % datetime.datetime.now())
|
||||||
|
@ -271,17 +271,13 @@ class Tty(object):
|
||||||
获取需要登陆的主机的信息和映射用户的账号密码
|
获取需要登陆的主机的信息和映射用户的账号密码
|
||||||
"""
|
"""
|
||||||
asset_info = get_asset_info(self.asset)
|
asset_info = get_asset_info(self.asset)
|
||||||
role_key = get_role_key(self.user, self.role)
|
role_key = get_role_key(self.user, self.role) # 获取角色的key,因为ansible需要权限是600,所以统一生成用户_角色key
|
||||||
role_pass = CRYPTOR.decrypt(self.role.password)
|
role_pass = CRYPTOR.decrypt(self.role.password)
|
||||||
self.connect_info = {'user': self.user, 'asset': self.asset, 'ip': asset_info.get('ip'),
|
connect_info = {'user': self.user, 'asset': self.asset, 'ip': asset_info.get('ip'),
|
||||||
'port': int(asset_info.get('port')), 'role_name': self.role.name,
|
'port': int(asset_info.get('port')), 'role_name': self.role.name,
|
||||||
'role_pass': role_pass, 'role_key': role_key}
|
'role_pass': role_pass, 'role_key': role_key}
|
||||||
logger.debug("Connect: Host: %s Port: %s User: %s Pass: %s Key: %s" % (asset_info.get('ip'),
|
logger.debug(connect_info)
|
||||||
asset_info.get('port'),
|
return connect_info
|
||||||
self.role.name,
|
|
||||||
role_pass,
|
|
||||||
role_key))
|
|
||||||
return self.connect_info
|
|
||||||
|
|
||||||
def get_connection(self):
|
def get_connection(self):
|
||||||
"""
|
"""
|
||||||
|
@ -300,12 +296,13 @@ class Tty(object):
|
||||||
ssh.connect(connect_info.get('ip'),
|
ssh.connect(connect_info.get('ip'),
|
||||||
port=connect_info.get('port'),
|
port=connect_info.get('port'),
|
||||||
username=connect_info.get('role_name'),
|
username=connect_info.get('role_name'),
|
||||||
|
password=connect_info.get('role_pass'),
|
||||||
key_filename=role_key,
|
key_filename=role_key,
|
||||||
look_for_keys=False)
|
look_for_keys=False,
|
||||||
self.ssh = ssh
|
allow_agent=False)
|
||||||
return ssh
|
return ssh
|
||||||
except (paramiko.ssh_exception.AuthenticationException, paramiko.ssh_exception.SSHException):
|
except (paramiko.ssh_exception.AuthenticationException, paramiko.ssh_exception.SSHException):
|
||||||
logger.warning('Use ssh key %s Failed.' % role_key)
|
logger.warning(u'使用ssh key %s 失败, 尝试只使用密码' % role_key)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
ssh.connect(connect_info.get('ip'),
|
ssh.connect(connect_info.get('ip'),
|
||||||
|
@ -320,7 +317,6 @@ class Tty(object):
|
||||||
except socket.error:
|
except socket.error:
|
||||||
raise ServerError('端口可能不对 Connect SSH Socket Port Error, Please Correct it.')
|
raise ServerError('端口可能不对 Connect SSH Socket Port Error, Please Correct it.')
|
||||||
else:
|
else:
|
||||||
self.ssh = ssh
|
|
||||||
return ssh
|
return ssh
|
||||||
|
|
||||||
|
|
||||||
|
@ -455,6 +451,9 @@ class SshTty(Tty):
|
||||||
|
|
||||||
|
|
||||||
class Nav(object):
|
class Nav(object):
|
||||||
|
"""
|
||||||
|
导航提示类
|
||||||
|
"""
|
||||||
def __init__(self, user):
|
def __init__(self, user):
|
||||||
self.user = user
|
self.user = user
|
||||||
self.search_result = {}
|
self.search_result = {}
|
||||||
|
@ -466,9 +465,10 @@ class Nav(object):
|
||||||
Print prompt
|
Print prompt
|
||||||
打印提示导航
|
打印提示导航
|
||||||
"""
|
"""
|
||||||
msg = """\n\033[1;32m### 欢迎使用Jumpserver开源跳板机 ### \033[0m
|
msg = """\n\033[1;32m### 欢迎使用Jumpserver开源跳板机系统 ### \033[0m
|
||||||
|
|
||||||
1) 输入 \033[32mID\033[0m 直接登录.
|
1) 输入 \033[32mID\033[0m 直接登录.
|
||||||
2) 输入 \033[32m/\033[0m + \033[32mIP, 主机名, 主机别名 or 备注 \033[0m搜索.
|
2) 输入 \033[32m/\033[0m + \033[32mIP, 主机名 or 备注 \033[0m搜索.
|
||||||
3) 输入 \033[32mP/p\033[0m 显示您有权限的主机.
|
3) 输入 \033[32mP/p\033[0m 显示您有权限的主机.
|
||||||
4) 输入 \033[32mG/g\033[0m 显示您有权限的主机组.
|
4) 输入 \033[32mG/g\033[0m 显示您有权限的主机组.
|
||||||
5) 输入 \033[32mG/g\033[0m\033[0m + \033[32m组ID\033[0m 显示该组下主机.
|
5) 输入 \033[32mG/g\033[0m\033[0m + \033[32m组ID\033[0m 显示该组下主机.
|
||||||
|
@ -503,17 +503,14 @@ class Nav(object):
|
||||||
user_asset_search = user_asset_all
|
user_asset_search = user_asset_all
|
||||||
|
|
||||||
self.search_result = dict(zip(range(len(user_asset_search)), user_asset_search))
|
self.search_result = dict(zip(range(len(user_asset_search)), user_asset_search))
|
||||||
print '\033[32m[%-3s] %-15s %-15s %-5s %-10s %s \033[0m' % ('ID', 'AssetName', 'IP', 'Port', 'Role', 'Comment')
|
color_print('[%-3s] %-15s %-15s %-5s %-10s %s' % ('ID', 'AssetName', 'IP', 'Port', 'Role', 'Comment'), 'info')
|
||||||
for index, asset in self.search_result.items():
|
for index, asset in self.search_result.items():
|
||||||
# 获取该资产信息
|
# 获取该资产信息
|
||||||
asset_info = get_asset_info(asset)
|
asset_info = get_asset_info(asset)
|
||||||
# 获取该资产包含的角色
|
# 获取该资产包含的角色
|
||||||
role = [str(role.name) for role in self.user_perm.get('asset').get(asset).get('role')]
|
role = [str(role.name) for role in self.user_perm.get('asset').get(asset).get('role')]
|
||||||
if asset.comment:
|
print '[%-3s] %-15s %-15s %-5s %-10s %s' % (index, asset.hostname, asset.ip, asset_info.get('port'),
|
||||||
print '[%-3s] %-15s %-15s %-5s %-10s %s' % (index, asset.hostname, asset.ip, asset_info.get('port'),
|
role, asset.comment)
|
||||||
role, asset.comment)
|
|
||||||
else:
|
|
||||||
print '[%-3s] %-15s %-15s %-5s %-10s' % (index, asset.hostname, asset.ip, asset_info.get('port'), role)
|
|
||||||
print
|
print
|
||||||
|
|
||||||
def print_asset_group(self):
|
def print_asset_group(self):
|
||||||
|
@ -521,8 +518,7 @@ class Nav(object):
|
||||||
打印用户授权的资产组
|
打印用户授权的资产组
|
||||||
"""
|
"""
|
||||||
user_asset_group_all = get_group_user_perm(self.user).get('asset_group', [])
|
user_asset_group_all = get_group_user_perm(self.user).get('asset_group', [])
|
||||||
|
color_print('[%-3s] %-15s %s' % ('ID', 'GroupName', 'Comment'), 'info')
|
||||||
print '\033[32m[%-3s] %-15s %s \033[0m' % ('ID', 'GroupName', 'Comment')
|
|
||||||
for asset_group in user_asset_group_all:
|
for asset_group in user_asset_group_all:
|
||||||
if asset_group.comment:
|
if asset_group.comment:
|
||||||
print '[%-3s] %-15s %s' % (asset_group.id, asset_group.name, asset_group.comment)
|
print '[%-3s] %-15s %s' % (asset_group.id, asset_group.name, asset_group.comment)
|
||||||
|
@ -540,7 +536,7 @@ class Nav(object):
|
||||||
|
|
||||||
roles = self.user_perm.get('role').keys()
|
roles = self.user_perm.get('role').keys()
|
||||||
if len(roles) > 1: # 授权角色数大于1
|
if len(roles) > 1: # 授权角色数大于1
|
||||||
print '\033[32m[%-2s] %-15s \033[0m' % ('ID', '角色')
|
color_print('[%-2s] %-15s' % ('ID', '角色'), 'info')
|
||||||
role_check = dict(zip(range(len(roles)), roles))
|
role_check = dict(zip(range(len(roles)), roles))
|
||||||
|
|
||||||
for i, r in role_check.items():
|
for i, r in role_check.items():
|
||||||
|
@ -615,7 +611,7 @@ class Nav(object):
|
||||||
res = gen_resource({'user': self.user, 'asset': assets}, perm=self.user_perm)
|
res = gen_resource({'user': self.user, 'asset': assets}, perm=self.user_perm)
|
||||||
runner = MyRunner(res)
|
runner = MyRunner(res)
|
||||||
asset_name_str = ''
|
asset_name_str = ''
|
||||||
print "匹配主机:\n"
|
print "匹配主机:"
|
||||||
for inv in runner.inventory.get_hosts(pattern=pattern):
|
for inv in runner.inventory.get_hosts(pattern=pattern):
|
||||||
print inv.name
|
print inv.name
|
||||||
asset_name_str += '%s ' % inv.name
|
asset_name_str += '%s ' % inv.name
|
||||||
|
@ -667,7 +663,6 @@ class Nav(object):
|
||||||
assets = self.user_perm.get('asset').keys()
|
assets = self.user_perm.get('asset').keys()
|
||||||
res = gen_resource({'user': self.user, 'asset': assets}, perm=self.user_perm)
|
res = gen_resource({'user': self.user, 'asset': assets}, perm=self.user_perm)
|
||||||
runner = MyRunner(res)
|
runner = MyRunner(res)
|
||||||
logger.debug("Muti download file res: %s" % res)
|
|
||||||
asset_name_str = ''
|
asset_name_str = ''
|
||||||
print "匹配用户:\n"
|
print "匹配用户:\n"
|
||||||
for inv in runner.inventory.get_hosts(pattern=pattern):
|
for inv in runner.inventory.get_hosts(pattern=pattern):
|
||||||
|
|
|
@ -50,7 +50,7 @@ def set_log(level):
|
||||||
|
|
||||||
def get_asset_info(asset):
|
def get_asset_info(asset):
|
||||||
"""
|
"""
|
||||||
获取资产的相关账号端口信息
|
获取资产的相关管理账号端口等信息
|
||||||
"""
|
"""
|
||||||
default = get_object(Setting, name='default')
|
default = get_object(Setting, name='default')
|
||||||
info = {'hostname': asset.hostname, 'ip': asset.ip}
|
info = {'hostname': asset.hostname, 'ip': asset.ip}
|
||||||
|
|
|
@ -191,7 +191,6 @@ class MonitorHandler(tornado.websocket.WebSocketHandler):
|
||||||
class WebTty(Tty):
|
class WebTty(Tty):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(WebTty, self).__init__(*args, **kwargs)
|
super(WebTty, self).__init__(*args, **kwargs)
|
||||||
self.login_type = 'web'
|
|
||||||
self.ws = None
|
self.ws = None
|
||||||
self.data = ''
|
self.data = ''
|
||||||
self.input_mode = False
|
self.input_mode = False
|
||||||
|
@ -328,10 +327,10 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
|
||||||
return
|
return
|
||||||
logger.debug('Websocket: request web terminal Host: %s User: %s Role: %s' % (asset.hostname, self.user.username,
|
logger.debug('Websocket: request web terminal Host: %s User: %s Role: %s' % (asset.hostname, self.user.username,
|
||||||
login_role.name))
|
login_role.name))
|
||||||
self.term = WebTty(self.user, asset, login_role)
|
self.term = WebTty(self.user, asset, login_role, login_type='web')
|
||||||
self.term.remote_ip = self.request.remote_ip
|
self.term.remote_ip = self.request.remote_ip
|
||||||
self.term.get_connection()
|
ssh = self.term.get_connection()
|
||||||
self.term.channel = self.term.ssh.invoke_shell(term='xterm')
|
self.term.channel = ssh.invoke_shell(term='xterm')
|
||||||
WebTerminalHandler.tasks.append(MyThread(target=self.forward_outbound))
|
WebTerminalHandler.tasks.append(MyThread(target=self.forward_outbound))
|
||||||
WebTerminalHandler.clients.append(self)
|
WebTerminalHandler.clients.append(self)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue