mirror of https://github.com/jumpserver/jumpserver
modify some
parent
fdcaa358e5
commit
8d167baf46
297
connect.py
297
connect.py
|
@ -40,11 +40,10 @@ except ImportError:
|
||||||
|
|
||||||
CONF.read(os.path.join(BASE_DIR, 'jumpserver.conf'))
|
CONF.read(os.path.join(BASE_DIR, 'jumpserver.conf'))
|
||||||
log_dir = os.path.join(BASE_DIR, 'logs')
|
log_dir = os.path.join(BASE_DIR, 'logs')
|
||||||
login_name = getpass.getuser()
|
login_user = Juser(username=getpass.getuser())
|
||||||
user = Juser(username=login_name)
|
|
||||||
|
|
||||||
|
|
||||||
def color_print(msg, color='blue'):
|
def color_print(msg, color='red', exits=False):
|
||||||
"""
|
"""
|
||||||
Print colorful string.
|
Print colorful string.
|
||||||
颜色打印
|
颜色打印
|
||||||
|
@ -54,199 +53,133 @@ def color_print(msg, color='blue'):
|
||||||
'red': '\033[1;31m%s\033[0m'}
|
'red': '\033[1;31m%s\033[0m'}
|
||||||
|
|
||||||
print color_msg.get(color, 'blue') % msg
|
print color_msg.get(color, 'blue') % msg
|
||||||
|
if exits:
|
||||||
|
time.sleep(2)
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
def color_print_exit(msg, color='red'):
|
class Jtty(object):
|
||||||
"""
|
def __init__(self, chan, user, asset):
|
||||||
Print colorful string and exit.
|
self.chan = chan
|
||||||
颜色打印并推出
|
self.username = user.username
|
||||||
"""
|
self.ip = asset.ip
|
||||||
color_print(msg, color=color)
|
|
||||||
time.sleep(2)
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
|
@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():
|
def set_win_size(self, sig, data):
|
||||||
"""
|
"""
|
||||||
This function use to get the size of the windows!
|
This function use to set the window size of the terminal!
|
||||||
获得terminal窗口大小
|
设置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):
|
|
||||||
try:
|
try:
|
||||||
os.makedirs(today_connect_log_dir)
|
win_size = self.get_win_size()
|
||||||
os.chmod(today_connect_log_dir, 0777)
|
self.channel.resize_pty(height=win_size[0], width=win_size[1])
|
||||||
except OSError:
|
except Exception:
|
||||||
raise ServerError('Create %s failed, Please modify %s permission.' % (today_connect_log_dir, connect_log_dir))
|
pass
|
||||||
|
|
||||||
try:
|
def log_record(self):
|
||||||
log_file = open(log_file_path, 'a')
|
"""
|
||||||
except IOError:
|
Logging user command and output.
|
||||||
raise ServerError('Create logfile failed, Please modify %s permission.' % today_connect_log_dir)
|
记录用户的日志
|
||||||
|
"""
|
||||||
|
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,
|
pid = os.getpid()
|
||||||
log_path=log_file_path, start_time=datetime.datetime.now(), pid=pid)
|
pts = os.popen("ps axu | grep %s | grep -v grep | awk '{ print $7 }'" % pid).read().strip()
|
||||||
log_file.write('Start time is %s\n' % datetime.datetime.now())
|
remote_ip = os.popen("who | grep %s | awk '{ print $5 }'" % pts).read().strip('()\n')
|
||||||
log.save()
|
|
||||||
return log_file, log
|
|
||||||
|
|
||||||
|
if not os.path.isdir(today_connect_log_dir):
|
||||||
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:
|
try:
|
||||||
r, w, e = select.select([chan, sys.stdin], [], [])
|
os.makedirs(today_connect_log_dir)
|
||||||
except Exception:
|
os.chmod(today_connect_log_dir, 0777)
|
||||||
pass
|
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:
|
try:
|
||||||
x = chan.recv(1024)
|
r, w, e = select.select([chan, sys.stdin], [], [])
|
||||||
if len(x) == 0:
|
except Exception:
|
||||||
break
|
|
||||||
sys.stdout.write(x)
|
|
||||||
sys.stdout.flush()
|
|
||||||
log_file.write(x)
|
|
||||||
log_file.flush()
|
|
||||||
except socket.timeout:
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if sys.stdin in r:
|
if chan in r:
|
||||||
x = os.read(sys.stdin.fileno(), 1)
|
try:
|
||||||
if len(x) == 0:
|
x = chan.recv(1024)
|
||||||
break
|
if len(x) == 0:
|
||||||
chan.send(x)
|
break
|
||||||
|
sys.stdout.write(x)
|
||||||
|
sys.stdout.flush()
|
||||||
|
log_file.write(x)
|
||||||
|
log_file.flush()
|
||||||
|
except socket.timeout:
|
||||||
|
pass
|
||||||
|
|
||||||
finally:
|
if sys.stdin in r:
|
||||||
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
x = os.read(sys.stdin.fileno(), 1)
|
||||||
log_file.write('End time is %s' % datetime.datetime.now())
|
if len(x) == 0:
|
||||||
log_file.close()
|
break
|
||||||
log.is_finished = True
|
chan.send(x)
|
||||||
log.log_finished = False
|
|
||||||
log.end_time = datetime.datetime.now()
|
|
||||||
log.save()
|
|
||||||
|
|
||||||
|
finally:
|
||||||
# def get_user_host_group(username):
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
||||||
# """
|
log_file.write('End time is %s' % datetime.datetime.now())
|
||||||
# Get the host groups of under the user control.
|
log_file.close()
|
||||||
# 获取用户有权限的主机组
|
log.is_finished = True
|
||||||
# """
|
log.log_finished = False
|
||||||
# groups_attr = {}
|
log.end_time = datetime.datetime.now()
|
||||||
# group_all = get_host_groups(username)
|
log.save()
|
||||||
# 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
|
|
||||||
|
|
||||||
|
|
||||||
def verify_connect(username, part_ip):
|
def verify_connect(username, part_ip):
|
||||||
ip_matched = []
|
ip_matched = []
|
||||||
try:
|
try:
|
||||||
assets_info = user.get_asset_info()
|
assets_info = login_user.get_asset_info()
|
||||||
except ServerError, e:
|
except ServerError, e:
|
||||||
color_print(e, 'red')
|
color_print(e, 'red')
|
||||||
return False
|
return False
|
||||||
|
@ -260,7 +193,7 @@ def verify_connect(username, part_ip):
|
||||||
if part_ip in info:
|
if part_ip in info:
|
||||||
ip_matched.append(ip)
|
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))
|
ip_matched = list(set(ip_matched))
|
||||||
|
|
||||||
if len(ip_matched) > 1:
|
if len(ip_matched) > 1:
|
||||||
|
@ -385,7 +318,7 @@ def exec_cmd_servers(username):
|
||||||
inputs = raw_input('\033[1;32mip(s)>: \033[0m')
|
inputs = raw_input('\033[1;32mip(s)>: \033[0m')
|
||||||
if inputs in ['q', 'Q']:
|
if inputs in ['q', 'Q']:
|
||||||
break
|
break
|
||||||
get_hosts = user.get_asset_info().keys()
|
get_hosts = login_user.get_asset_info().keys()
|
||||||
|
|
||||||
if ',' in inputs:
|
if ',' in inputs:
|
||||||
ips_input = inputs.split(',')
|
ips_input = inputs.split(',')
|
||||||
|
@ -419,8 +352,8 @@ def exec_cmd_servers(username):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if not user.validate():
|
if not login_user.validate():
|
||||||
color_print_exit(u'没有该用户 No that user.')
|
color_print(u'没有该用户 No that user.', exits=True)
|
||||||
|
|
||||||
print_prompt()
|
print_prompt()
|
||||||
gid_pattern = re.compile(r'^g\d+$')
|
gid_pattern = re.compile(r'^g\d+$')
|
||||||
|
@ -434,10 +367,10 @@ if __name__ == '__main__':
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
if option in ['P', 'p']:
|
if option in ['P', 'p']:
|
||||||
user.get_asset_info(printable=True)
|
login_user.get_asset_info(printable=True)
|
||||||
continue
|
continue
|
||||||
elif option in ['G', 'g']:
|
elif option in ['G', 'g']:
|
||||||
user.get_asset_group_info(printable=True)
|
login_user.get_asset_group_info(printable=True)
|
||||||
continue
|
continue
|
||||||
elif gid_pattern.match(option):
|
elif gid_pattern.match(option):
|
||||||
gid = option[1:].strip()
|
gid = option[1:].strip()
|
||||||
|
|
|
@ -12,6 +12,7 @@ import ldap
|
||||||
from ldap import modlist
|
from ldap import modlist
|
||||||
import hashlib
|
import hashlib
|
||||||
import datetime
|
import datetime
|
||||||
|
import random
|
||||||
import subprocess
|
import subprocess
|
||||||
from django.core.paginator import Paginator, EmptyPage, InvalidPage
|
from django.core.paginator import Paginator, EmptyPage, InvalidPage
|
||||||
from django.http import HttpResponse, Http404
|
from django.http import HttpResponse, Http404
|
||||||
|
@ -150,34 +151,57 @@ def pages(posts, r):
|
||||||
|
|
||||||
|
|
||||||
class PyCrypt(object):
|
class PyCrypt(object):
|
||||||
"""This class used to encrypt and decrypt password."""
|
"""
|
||||||
|
This class used to encrypt and decrypt password.
|
||||||
|
对称加密库
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, key):
|
def __init__(self, key):
|
||||||
self.key = key
|
self.key = key
|
||||||
self.mode = AES.MODE_CBC
|
self.mode = AES.MODE_CBC
|
||||||
|
|
||||||
def encrypt(self, text):
|
def _random_pass(self):
|
||||||
cryptor = AES.new(self.key, self.mode, b'0000000000000000')
|
"""
|
||||||
length = 16
|
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:
|
try:
|
||||||
count = len(text)
|
count = len(self.salt)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
raise ServerError('Encrypt password error, TYpe error.')
|
# raise ServerError('Encrypt password error, TYpe error.')
|
||||||
|
pass
|
||||||
add = (length - (count % length))
|
add = (length - (count % length))
|
||||||
text += ('\0' * add)
|
self.salt += ('\0' * add)
|
||||||
ciphertext = cryptor.encrypt(text)
|
cipher_text = cryptor.encrypt(self.salt)
|
||||||
return b2a_hex(ciphertext)
|
return b2a_hex(cipher_text)
|
||||||
|
|
||||||
def decrypt(self, text):
|
def decrypt(self, text):
|
||||||
cryptor = AES.new(self.key, self.mode, b'0000000000000000')
|
cryptor = AES.new(self.key, self.mode, b'8122ca7d906ad5e1')
|
||||||
try:
|
try:
|
||||||
plain_text = cryptor.decrypt(a2b_hex(text))
|
plain_text = cryptor.decrypt(a2b_hex(text))
|
||||||
except TypeError:
|
except TypeError:
|
||||||
raise ServerError('Decrypt password error, TYpe error.')
|
# raise ServerError('Decrypt password error, TYpe error.')
|
||||||
|
pass
|
||||||
return plain_text.rstrip('\0')
|
return plain_text.rstrip('\0')
|
||||||
|
|
||||||
|
|
||||||
CRYPTOR = PyCrypt(KEY)
|
|
||||||
|
|
||||||
|
|
||||||
class ServerError(Exception):
|
class ServerError(Exception):
|
||||||
|
@ -595,17 +619,15 @@ def asset_perm_api(asset):
|
||||||
return user_permed_list
|
return user_permed_list
|
||||||
|
|
||||||
|
|
||||||
def get_connect_item(username, ip):
|
def get_connect_item(user, ip):
|
||||||
asset = get_object(Asset, ip=ip)
|
asset = get_object(Asset, ip=ip)
|
||||||
port = int(asset.port)
|
port = int(asset.port)
|
||||||
|
|
||||||
if not asset.is_active:
|
if not asset.is_active:
|
||||||
raise ServerError('Host %s is not active.' % ip)
|
raise ServerError('Host %s is not active.' % ip)
|
||||||
|
|
||||||
user = get_object(User, username=username)
|
|
||||||
|
|
||||||
if not user.is_active:
|
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 = {
|
login_type_dict = {
|
||||||
'L': user.ldap_pwd,
|
'L': user.ldap_pwd,
|
||||||
|
@ -613,7 +635,7 @@ def get_connect_item(username, ip):
|
||||||
|
|
||||||
if asset.login_type in login_type_dict:
|
if asset.login_type in login_type_dict:
|
||||||
password = CRYPTOR.decrypt(login_type_dict[asset.login_type])
|
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':
|
elif asset.login_type == 'M':
|
||||||
username = asset.username
|
username = asset.username
|
||||||
|
@ -749,4 +771,7 @@ def node_auth(request):
|
||||||
else:
|
else:
|
||||||
result = {'auth': {'username': username, 'result': 'failed'}}
|
result = {'auth': {'username': username, 'result': 'failed'}}
|
||||||
|
|
||||||
return HttpResponse(json.dumps(result, sort_keys=True, indent=2), content_type='application/json')
|
return HttpResponse(json.dumps(result, sort_keys=True, indent=2), content_type='application/json')
|
||||||
|
|
||||||
|
|
||||||
|
CRYPTOR = PyCrypt(KEY)
|
Loading…
Reference in New Issue