From 6c2b7829644a9f66bd599ba330e39e5d7112ab9f Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 29 Dec 2014 23:50:56 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E6=94=AF=E6=8C=81ssh-key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- connect.py | 21 ++++++++++++++++----- jasset/models.py | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/connect.py b/connect.py index e3396ff0c..dce1a9c70 100755 --- a/connect.py +++ b/connect.py @@ -36,6 +36,8 @@ CURRENT_DIR = os.path.abspath('.') CONF = ConfigParser() CONF.read(os.path.join(CURRENT_DIR, 'jumpserver.conf')) LOG_DIR = os.path.join(CURRENT_DIR, 'logs') +SSH_KEY_DIR = os.path.join(CURRENT_DIR, 'keys') +SERVER_KEY_DIR = os.path.join(SSH_KEY_DIR, 'server') KEY = CONF.get('web', 'key') LOGIN_NAME = getpass.getuser() #LOGIN_NAME = os.getlogin() @@ -195,10 +197,13 @@ def get_connect_item(username, ip): red_print("Host %s isn't exist." % ip) return + user = User.objects.get(username=username) if asset.ldap_enable: - user = User.objects.get(username=username) ldap_pwd = cryptor.decrypt(user.ldap_pwd) return username, ldap_pwd, ip, port + elif asset.ssh_key_enable: + ssh_key_pwd = cryptor.decrypt(user.ssh_key_pwd) + return username, ssh_key_pwd, ip, port else: perms = asset.permission_set.all() perm = perms[0] @@ -229,7 +234,7 @@ def verify_connect(username, part_ip): red_print('No Permission or No host.') else: try: - username, password, host, port = get_connect_item(username, ip_matched[0]) + username, password, host, port, key_filename = get_connect_item(username, ip_matched[0]) except (ObjectDoesNotExist, IndexError): red_print('Get get_connect_item Error.') else: @@ -258,13 +263,19 @@ def connect(username, password, host, port, login_name): """ ps1 = "PS1='[\u@%s \W]\$ '\n" % host login_msg = "clear;echo -e '\\033[32mLogin %s done. Enjoy it.\\033[0m'\n" % host + user_key_file = os.path.join(SERVER_KEY_DIR, username) + + if os.path.isfile(user_key_file): + key_filename = user_key_file + else: + key_filename = None # Make a ssh connection ssh = paramiko.SSHClient() ssh.load_system_host_keys() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: - ssh.connect(host, port=port, username=username, password=password, compress=True) + ssh.connect(host, port=port, username=username, password=password, key_filename=key_filename, compress=True) except paramiko.ssh_exception.AuthenticationException: alert_print('Host Password Error, Please Correct it.') except socket.error: @@ -272,9 +283,9 @@ def connect(username, password, host, port, login_name): # Make a channel and set windows size global channel - channel = ssh.invoke_shell() win_size = get_win_size() - channel.resize_pty(height=win_size[0], width=win_size[1]) + channel = ssh.invoke_shell(height=win_size[0], width=win_size[1]) + #channel.resize_pty(height=win_size[0], width=win_size[1]) try: signal.signal(signal.SIGWINCH, set_win_size) except: diff --git a/jasset/models.py b/jasset/models.py index ad32eb982..084e0368b 100644 --- a/jasset/models.py +++ b/jasset/models.py @@ -16,6 +16,7 @@ class Asset(models.Model): idc = models.ForeignKey(IDC) group = models.ManyToManyField(Group) ldap_enable = models.BooleanField(default=True) + ssh_key_enable = models.BooleanField(default=False) username_common = models.CharField(max_length=80, blank=True, null=True) password_common = models.CharField(max_length=160, blank=True, null=True) username_super = models.CharField(max_length=80, blank=True, null=True) From d316b08b6d469abbaacbe65b0ab83a644fc12c55 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 30 Dec 2014 00:05:03 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- connect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connect.py b/connect.py index dce1a9c70..ee6cff315 100755 --- a/connect.py +++ b/connect.py @@ -234,7 +234,7 @@ def verify_connect(username, part_ip): red_print('No Permission or No host.') else: try: - username, password, host, port, key_filename = get_connect_item(username, ip_matched[0]) + username, password, host, port = get_connect_item(username, ip_matched[0]) except (ObjectDoesNotExist, IndexError): red_print('Get get_connect_item Error.') else: From 3f4a7225b1e6e2735f91f5de0898e6357a7ea411 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 30 Dec 2014 22:48:39 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0ssh=5Fkey=E5=92=8C=E6=99=AE=E9=80=9A=E5=AF=86=E7=A0=81?= =?UTF-8?q?=E7=99=BB=E9=99=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- connect.py | 114 ++++++++++++++++++++++++++++++++--------------- jasset/models.py | 26 ++++++----- juser/models.py | 4 +- 3 files changed, 98 insertions(+), 46 deletions(-) diff --git a/connect.py b/connect.py index ee6cff315..d20026757 100755 --- a/connect.py +++ b/connect.py @@ -57,6 +57,16 @@ def alert_print(string): sys.exit() +class ServerError(Exception): + def __init__(self, error): + self.error = error + + def __str__(self): + return self.error + + __repr__ = __str__ + + class PyCrypt(object): """It's used to encrypt and decrypt password.""" def __init__(self, key): @@ -114,21 +124,25 @@ def posix_shell(chan, username, host): today_connect_log_dir = os.path.join(connect_log_dir, today) log_filename = '%s_%s_%s.log' % (username, host, date_now) log_file_path = os.path.join(today_connect_log_dir, log_filename) - user = User.objects.get(username=username) - asset = Asset.objects.get(ip=host) - pid = os.getpid() + try: + user = User.objects.get(username=username) + asset = Asset.objects.get(ip=host) + except ObjectDoesNotExist: + raise ServerError('user %s or asset %s does not exist.' % (username, host)) + + pid = os.getpid() if not os.path.isdir(today_connect_log_dir): try: os.makedirs(today_connect_log_dir) os.chmod(today_connect_log_dir, 0777) except OSError: - alert_print('Create %s failed, Please modify %s permission.' % (today_connect_log_dir, connect_log_dir)) + raise ServerError('Create %s failed, Please modify %s permission.' % (today_connect_log_dir, connect_log_dir)) try: log_file = open(log_file_path, 'a') except IOError: - alert_print('Create logfile failed, Please modify %s permission.' % today_connect_log_dir) + raise ServerError('Create logfile failed, Please modify %s permission.' % today_connect_log_dir) log = Log(user=user, asset=asset, log_path=log_file_path, start_time=timestamp_start, pid=pid) log.save() @@ -177,7 +191,7 @@ def get_user_host(username): try: user = User.objects.get(username=username) except ObjectDoesNotExist: - return {'Error': ['0', "Username \033[1;31m%s\033[0m doesn't exist on Jumpserver." % username]}, ['Error'] + raise ServerError("Username \033[1;31m%s\033[0m doesn't exist on Jumpserver." % username) else: perm_all = user.permission_set.all() for perm in perm_all: @@ -194,30 +208,58 @@ def get_connect_item(username, ip): asset = Asset.objects.get(ip=ip) port = asset.port except ObjectDoesNotExist: - red_print("Host %s isn't exist." % ip) - return + raise ServerError("Host %s does not exist." % ip) - user = User.objects.get(username=username) - if asset.ldap_enable: - ldap_pwd = cryptor.decrypt(user.ldap_pwd) - return username, ldap_pwd, ip, port - elif asset.ssh_key_enable: - ssh_key_pwd = cryptor.decrypt(user.ssh_key_pwd) - return username, ssh_key_pwd, ip, port - else: - perms = asset.permission_set.all() - perm = perms[0] + try: + user = User.objects.get(username=username) + except ObjectDoesNotExist: + raise ServerError('User %s does not exist.' % username) + + if asset.login_type == 'L': + try: + ldap_pwd = cryptor.decrypt(user.ldap_pwd) + except TypeError: + raise ServerError('Decrypt %s ldap password error.' % username) + return 'L', username, ldap_pwd, ip, port + elif asset.login_type == 'S': + try: + ssh_key_pwd = cryptor.decrypt(user.ssh_key_pwd2) + except TypeError: + raise ServerError('Decrypt %s ssh key password error.' % username) + return 'S', username, ssh_key_pwd, ip, port + elif asset.login_type == 'P': + try: + ssh_pwd = cryptor.decrypt(user.ssh_pwd) + except TypeError: + raise ServerError('Decrypt %s ssh password error.' % username) + return 'P', username, ssh_pwd, ip, port + elif asset.login_type == 'M': + perms = asset.permission_set.filter(user=user) + try: + perm = perms[0] + except IndexError: + raise ServerError('Permission %s to %s does not exist.' % (username, ip)) if perm.role == 'SU': + username_super = asset.username_super try: - return asset.username_super, cryptor.decrypt(asset.password_super), ip, port + password_super = cryptor.decrypt(asset.password_super) except TypeError: - red_print('User %s password error to decrypt.' % username) + raise ServerError('Decrypt %s map to %s password in %s error.' % (username, username_super, ip)) + return 'M', username_super, password_super, ip, port + + elif perm.role == 'CU': + username_common = asset.username_common + try: + password_common = asset.password_common + except TypeError: + raise ServerError('Decrypt %s map to %s password in %s error.' % (username, username_common, ip)) + return username_common, password_common, ip, port + else: - try: - return asset.username_common, cryptor.decrypt(asset.password_common), ip, port - except TypeError: - red_print('User %s password error to decrypt.' % username) + raise ServerError('Perm in %s for %s map role is not in ["SU", "CU"].' % (ip, username)) + else: + raise ServerError('Login type is not in ["L", "S", "P", "M"]') def verify_connect(username, part_ip): @@ -233,12 +275,8 @@ def verify_connect(username, part_ip): elif len(ip_matched) < 1: red_print('No Permission or No host.') else: - try: - username, password, host, port = get_connect_item(username, ip_matched[0]) - except (ObjectDoesNotExist, IndexError): - red_print('Get get_connect_item Error.') - else: - connect(username, password, host, port, LOGIN_NAME) + login_type, username, password, host, port = get_connect_item(username, ip_matched[0]) + connect(username, password, host, port, LOGIN_NAME, login_type=login_type) def print_prompt(): @@ -257,7 +295,7 @@ def print_user_host(username): print '[%s] %s -- %s' % (hosts_attr[ip][0], ip, hosts_attr[ip][1]) -def connect(username, password, host, port, login_name): +def connect(username, password, host, port, login_name, login_type='L'): """ Connect server. """ @@ -275,11 +313,14 @@ def connect(username, password, host, port, login_name): ssh.load_system_host_keys() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: - ssh.connect(host, port=port, username=username, password=password, key_filename=key_filename, compress=True) + if login_type == 'L': + ssh.connect(host, port=port, username=username, password=password, key_filename=key_filename, compress=True) + else: + ssh.connect(host, port=port, username=username, password=password, compress=True) except paramiko.ssh_exception.AuthenticationException: - alert_print('Host Password Error, Please Correct it.') + raise ServerError('Authentication Error.') except socket.error: - alert_print('Connect SSH Socket Port Error, Please Correct it.') + raise ServerError('Connect SSH Socket Port Error, Please Correct it.') # Make a channel and set windows size global channel @@ -320,6 +361,9 @@ if __name__ == '__main__': elif option in ['Q', 'q']: sys.exit() else: - verify_connect(LOGIN_NAME, option) + try: + verify_connect(LOGIN_NAME, option) + except ServerError, e: + red_print(e) except IndexError: pass \ No newline at end of file diff --git a/jasset/models.py b/jasset/models.py index 084e0368b..253fcbf70 100644 --- a/jasset/models.py +++ b/jasset/models.py @@ -3,25 +3,31 @@ from juser.models import Group, User class IDC(models.Model): - name = models.CharField(max_length=80, unique=True) - comment = models.CharField(max_length=100, blank=True, null=True) + name = models.CharField(max_length=40, unique=True) + comment = models.CharField(max_length=80, blank=True, null=True) def __unicode__(self): return self.name class Asset(models.Model): + LOGIN_TYPE_CHOICES = ( + ('L', 'LDAP'), + ('S', 'SSH_KEY'), + ('P', 'PASSWORD'), + ('M', 'MAP'), + ) ip = models.IPAddressField(unique=True) - port = models.SmallIntegerField(max_length=40) + port = models.SmallIntegerField(max_length=5) idc = models.ForeignKey(IDC) group = models.ManyToManyField(Group) - ldap_enable = models.BooleanField(default=True) - ssh_key_enable = models.BooleanField(default=False) - username_common = models.CharField(max_length=80, blank=True, null=True) - password_common = models.CharField(max_length=160, blank=True, null=True) - username_super = models.CharField(max_length=80, blank=True, null=True) - password_super = models.CharField(max_length=160, blank=True, null=True) - date_added = models.IntegerField(max_length=80) + login_type = models.CharField(max_length=1, choices=LOGIN_TYPE_CHOICES, default='L') + username_common = models.CharField(max_length=20, blank=True, null=True) + password_common = models.CharField(max_length=80, blank=True, null=True) + username_super = models.CharField(max_length=20, blank=True, null=True) + password_super = models.CharField(max_length=80, blank=True, null=True) + date_added = models.IntegerField(max_length=12) + is_active = models.BooleanField(default=True) comment = models.CharField(max_length=100, blank=True, null=True) def __unicode__(self): diff --git a/juser/models.py b/juser/models.py index 26cc6c5d4..3e2c9a529 100644 --- a/juser/models.py +++ b/juser/models.py @@ -22,7 +22,9 @@ class User(models.Model): role = models.CharField(max_length=2, choices=USER_ROLE_CHOICES, default='CU') group = models.ManyToManyField(Group) ldap_pwd = models.CharField(max_length=100) - ssh_key_pwd = models.CharField(max_length=100) + ssh_key_pwd1 = models.CharField(max_length=100) + ssh_key_pwd2 = models.CharField(max_length=100) + ssh_pwd = models.CharField(max_length=100) is_active = models.BooleanField(default=True) last_login = models.IntegerField(default=0) date_joined = models.IntegerField() From 89e2133341e49c8f2f47dfba25504dccfa143c57 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 30 Dec 2014 22:52:39 +0800 Subject: [PATCH 4/6] serve active and user active --- connect.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/connect.py b/connect.py index d20026757..c5741716a 100755 --- a/connect.py +++ b/connect.py @@ -210,11 +210,17 @@ def get_connect_item(username, ip): except ObjectDoesNotExist: raise ServerError("Host %s does not exist." % ip) + if not asset.is_active: + raise ServerError('Host %s is not active.' % ip) + try: user = User.objects.get(username=username) except ObjectDoesNotExist: raise ServerError('User %s does not exist.' % username) + if not user.is_active: + raise ServerError('User %s is not active.' % username) + if asset.login_type == 'L': try: ldap_pwd = cryptor.decrypt(user.ldap_pwd) From 0b97c19862f743938d54d07d4cd68358fb774b39 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 30 Dec 2014 23:22:57 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- connect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connect.py b/connect.py index c5741716a..648e434a1 100755 --- a/connect.py +++ b/connect.py @@ -260,7 +260,7 @@ def get_connect_item(username, ip): password_common = asset.password_common except TypeError: raise ServerError('Decrypt %s map to %s password in %s error.' % (username, username_common, ip)) - return username_common, password_common, ip, port + return 'CU', username_common, password_common, ip, port else: raise ServerError('Perm in %s for %s map role is not in ["SU", "CU"].' % (ip, username)) From 894911126bc3a025df94f6513ee96353f0b1d16a Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 30 Dec 2014 23:51:00 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- connect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connect.py b/connect.py index 648e434a1..74da06a74 100755 --- a/connect.py +++ b/connect.py @@ -323,7 +323,7 @@ def connect(username, password, host, port, login_name, login_type='L'): ssh.connect(host, port=port, username=username, password=password, key_filename=key_filename, compress=True) else: ssh.connect(host, port=port, username=username, password=password, compress=True) - except paramiko.ssh_exception.AuthenticationException: + except paramiko.ssh_exception.AuthenticationException, paramiko.ssh_exception.SSHException: raise ServerError('Authentication Error.') except socket.error: raise ServerError('Connect SSH Socket Port Error, Please Correct it.')