def get_identities(self, *anything): """ Sends a message to the client with a list of the identities stored on the server for the current user. *anything* is just there because the client needs to send *something* along with the 'action'. """ self.ssh_log.debug('get_identities()') out_dict = {'result': 'Success'} users_ssh_dir = get_ssh_dir(self) out_dict['identities'] = [] ssh_keygen_path = '/opt/local/bin/ssh-keygen' # TODO: Switch this from using ssh-keygen to determine the keytype to using the string inside the public key. try: if os.path.exists(users_ssh_dir): ssh_files = os.listdir(users_ssh_dir) for f in ssh_files: if f.endswith('.pub'): # Double-check there's also a private key... identity = f[:-4] # Will be the same name minus '.pub' if identity in ssh_files: id_path = os.path.join(users_ssh_dir, identity) pub_key_path = os.path.join(users_ssh_dir, f) public_key_contents = open(pub_key_path).read() comment = ' '.join(public_key_contents.split(' ')[2:]) if public_key_contents.startswith('ecdsa'): keytype = 'ECDSA' elif public_key_contents.startswith('ssh-dss'): keytype = 'DSA' elif public_key_contents.startswith('ssh-rsa'): keytype = 'RSA' else: keytype = 'Unknown' keygen_cmd = "'%s' -vlf '%s'" % ( ssh_keygen_path, id_path) retcode, key_info = shell_command(keygen_cmd) # This will just wind up as an empty string if the # version of ssh doesn't support randomart: randomart = '\n'.join(key_info.splitlines()[1:]) bits = key_info.split()[0] fingerprint = key_info.split()[1] retcode, bubblebabble = shell_command( "'%s' -Bf '%s'" % (ssh_keygen_path, id_path)) bubblebabble = bubblebabble.split()[1] certinfo = '' cert_path = "'%s-cert.pub'" % id_path if os.path.exists(cert_path): retcode, certinfo = shell_command( "'%s' -Lf '%s'" % (ssh_keygen_path, cert_path)) certinfo = ' '.join(certinfo.split(' ')[1:]) fixed_certinfo = '' for i, line in enumerate(certinfo.splitlines()): if i == 0: line = line.lstrip() fixed_certinfo += line.replace(' ', ' ') fixed_certinfo += '\n' id_obj = { 'name': identity, 'public': public_key_contents, 'keytype': keytype, 'bubblebabble': bubblebabble, 'fingerprint': fingerprint, 'randomart': randomart, 'certinfo': fixed_certinfo, 'bits': bits, 'comment': comment.rstrip(), } out_dict['identities'].append(id_obj) # Figure out which identities are defaults default_ids = [] default_ids_exists = False users_ssh_dir = get_ssh_dir(self) default_ids_path = os.path.join(users_ssh_dir, '.default_ids') if os.path.exists(default_ids_path): default_ids_exists = True with open(default_ids_path) as f: default_ids = f.read().splitlines() # Why not readlines()? \n # Convert any absolute paths inside default_ids to just the short names default_ids = [os.path.split(a)[1] for a in default_ids] if default_ids_exists: for i, id_obj in enumerate(out_dict['identities']): if id_obj['name'] in default_ids: out_dict['identities'][i]['default'] = True else: out_dict['identities'][i]['default'] = False except Exception as e: error_msg = _("Error getting identities: %s" % e) self.ssh_log.error(error_msg) out_dict['result'] = error_msg message = { 'terminal:sshjs_identities_list': out_dict } self.write_message(message)
def openssh_generate_new_keypair(self, name, path, keytype=None, passphrase="", bits=None, comment=""): """ Generates a new private and public key pair--stored in the user's directory using the given *name* and other optional parameters (using OpenSSH). If *keytype* is given, it must be one of "ecdsa", "rsa" or "dsa" (case insensitive). If *keytype* is "rsa" or "ecdsa", *bits* may be specified to specify the size of the key. .. note:: Defaults to generating a 521-byte ecdsa key if OpenSSH is version 5.7+. Otherwise a 2048-bit rsa key will be used. """ self.ssh_log.debug('openssh_generate_new_keypair()') openssh_version = shell_command('ssh -V')[1] ssh_major_version = int( openssh_version.split()[0].split('_')[1].split('.')[0]) key_path = os.path.join(path, name) ssh_minor_version = int( openssh_version.split()[0].split('_')[1].split('.')[1][0]) ssh_version = "%s.%s" % (ssh_major_version, ssh_minor_version) ssh_version = float(ssh_version) if not keytype: if ssh_version >= 5.7: keytype = "ecdsa" else: keytype = "rsa" else: keytype = keytype.lower() if not bits and keytype == "ecdsa": bits = 521 # Not a typo: five-hundred-twenty-one bits elif not bits and keytype == "rsa": bits = 2048 if not passphrase: # This just makes sure False and None end up as '' passphrase = '' hostname = os.uname()[1] if not comment: now = datetime.now().isoformat() comment = "Generated by Gate One on %s %s" % (hostname, now) ssh_keygen_path = '/opt/local/bin/ssh-keygen' command = ( "%s " # Path to ssh-keygen "-b %s " # bits "-t %s " # keytype "-C '%s' " # comment "-f '%s'" # Key path % (ssh_keygen_path, bits, keytype, comment, key_path) ) self.ssh_log.debug("Keygen command: %s" % command) m = self.new_multiplex(command, "gen_ssh_keypair") call_errorback = partial(errorback, self) m.expect('^Overwrite.*', overwrite, optional=True, preprocess=False, timeout=10) passphrase_handler = partial(enter_passphrase, passphrase) m.expect('^Enter passphrase', passphrase_handler, errorback=call_errorback, preprocess=False, timeout=10) m.expect('^Enter same passphrase again', passphrase_handler, errorback=call_errorback, preprocess=False, timeout=10) finalize = partial(finished, self) # The regex below captures the md5 fingerprint which tells us the # operation was successful. m.expect( '(([0-9a-f][0-9a-f]\:){15}[0-9a-f][0-9a-f])', finalize, errorback=call_errorback, preprocess=False, timeout=15 # Key generation can take a little while ) m.spawn()
def get_identities(self, *anything): """ Sends a message to the client with a list of the identities stored on the server for the current user. *anything* is just there because the client needs to send *something* along with the 'action'. """ self.ssh_log.debug('get_identities()') out_dict = {'result': 'Success'} users_ssh_dir = get_ssh_dir(self) out_dict['identities'] = [] ssh_keygen_path = which('ssh-keygen') # TODO: Switch this from using ssh-keygen to determine the keytype to using the string inside the public key. try: if os.path.exists(users_ssh_dir): ssh_files = os.listdir(users_ssh_dir) for f in ssh_files: if f.endswith('.pub'): # Double-check there's also a private key... identity = f[:-4] # Will be the same name minus '.pub' if identity in ssh_files: id_path = os.path.join(users_ssh_dir, identity) pub_key_path = os.path.join(users_ssh_dir, f) public_key_contents = open(pub_key_path).read() comment = ' '.join(public_key_contents.split(' ')[2:]) if public_key_contents.startswith('ecdsa'): keytype = 'ECDSA' elif public_key_contents.startswith('ssh-dss'): keytype = 'DSA' elif public_key_contents.startswith('ssh-rsa'): keytype = 'RSA' else: keytype = 'Unknown' keygen_cmd = "'%s' -vlf '%s'" % ( ssh_keygen_path, id_path) retcode, key_info = shell_command(keygen_cmd) # This will just wind up as an empty string if the # version of ssh doesn't support randomart: randomart = '\n'.join(key_info.splitlines()[1:]) bits = key_info.split()[0] fingerprint = key_info.split()[1] retcode, bubblebabble = shell_command( "'%s' -Bf '%s'" % (ssh_keygen_path, id_path)) bubblebabble = bubblebabble.split()[1] certinfo = '' cert_path = "'%s-cert.pub'" % id_path if os.path.exists(cert_path): retcode, certinfo = shell_command( "'%s' -Lf '%s'" % (ssh_keygen_path, cert_path)) certinfo = ' '.join(certinfo.split(' ')[1:]) fixed_certinfo = '' for i, line in enumerate(certinfo.splitlines()): if i == 0: line = line.lstrip() fixed_certinfo += line.replace(' ', ' ') fixed_certinfo += '\n' id_obj = { 'name': identity, 'public': public_key_contents, 'keytype': keytype, 'bubblebabble': bubblebabble, 'fingerprint': fingerprint, 'randomart': randomart, 'certinfo': fixed_certinfo, 'bits': bits, 'comment': comment.rstrip(), } out_dict['identities'].append(id_obj) # Figure out which identities are defaults default_ids = [] default_ids_exists = False users_ssh_dir = get_ssh_dir(self) default_ids_path = os.path.join(users_ssh_dir, '.default_ids') if os.path.exists(default_ids_path): default_ids_exists = True with open(default_ids_path) as f: default_ids = f.read().splitlines() # Why not readlines()? \n # Convert any absolute paths inside default_ids to just the short names default_ids = [os.path.split(a)[1] for a in default_ids] if default_ids_exists: for i, id_obj in enumerate(out_dict['identities']): if id_obj['name'] in default_ids: out_dict['identities'][i]['default'] = True else: out_dict['identities'][i]['default'] = False except Exception as e: error_msg = _("Error getting identities: %s" % e) self.ssh_log.error(error_msg) out_dict['result'] = error_msg message = { 'terminal:sshjs_identities_list': out_dict } self.write_message(message)
def get_identities(self, *anything): """ Sends a message to the client with a list of the identities stored on the server for the current user. *anything* is just there because the client needs to send *something* along with the 'action'. """ self.ssh_log.debug("get_identities()") out_dict = {"result": "Success"} users_ssh_dir = get_ssh_dir(self) out_dict["identities"] = [] ssh_keygen_path = which("ssh-keygen") # TODO: Switch this from using ssh-keygen to determine the keytype to using the string inside the public key. try: if os.path.exists(users_ssh_dir): ssh_files = os.listdir(users_ssh_dir) for f in ssh_files: if f.endswith(".pub"): # Double-check there's also a private key... identity = f[:-4] # Will be the same name minus '.pub' if identity in ssh_files: id_path = os.path.join(users_ssh_dir, identity) pub_key_path = os.path.join(users_ssh_dir, f) public_key_contents = open(pub_key_path).read() comment = " ".join(public_key_contents.split(" ")[2:]) if public_key_contents.startswith("ecdsa"): keytype = "ECDSA" elif public_key_contents.startswith("ssh-dss"): keytype = "DSA" elif public_key_contents.startswith("ssh-rsa"): keytype = "RSA" else: keytype = "Unknown" keygen_cmd = "'%s' -vlf '%s'" % (ssh_keygen_path, id_path) retcode, key_info = shell_command(keygen_cmd) # This will just wind up as an empty string if the # version of ssh doesn't support randomart: randomart = "\n".join(key_info.splitlines()[1:]) bits = key_info.split()[0] fingerprint = key_info.split()[1] retcode, bubblebabble = shell_command("'%s' -Bf '%s'" % (ssh_keygen_path, id_path)) bubblebabble = bubblebabble.split()[1] certinfo = "" cert_path = "'%s-cert.pub'" % id_path if os.path.exists(cert_path): retcode, certinfo = shell_command("'%s' -Lf '%s'" % (ssh_keygen_path, cert_path)) certinfo = " ".join(certinfo.split(" ")[1:]) fixed_certinfo = "" for i, line in enumerate(certinfo.splitlines()): if i == 0: line = line.lstrip() fixed_certinfo += line.replace(" ", " ") fixed_certinfo += "\n" id_obj = { "name": identity, "public": public_key_contents, "keytype": keytype, "bubblebabble": bubblebabble, "fingerprint": fingerprint, "randomart": randomart, "certinfo": fixed_certinfo, "bits": bits, "comment": comment.rstrip(), } out_dict["identities"].append(id_obj) # Figure out which identities are defaults default_ids = [] default_ids_exists = False users_ssh_dir = get_ssh_dir(self) default_ids_path = os.path.join(users_ssh_dir, ".default_ids") if os.path.exists(default_ids_path): default_ids_exists = True with open(default_ids_path) as f: default_ids = f.read().splitlines() # Why not readlines()? \n # Convert any absolute paths inside default_ids to just the short names default_ids = [os.path.split(a)[1] for a in default_ids] if default_ids_exists: for i, id_obj in enumerate(out_dict["identities"]): if id_obj["name"] in default_ids: out_dict["identities"][i]["default"] = True else: out_dict["identities"][i]["default"] = False except Exception as e: error_msg = _("Error getting identities: %s" % e) self.ssh_log.error(error_msg) out_dict["result"] = error_msg message = {"terminal:sshjs_identities_list": out_dict} self.write_message(message)
def openssh_generate_new_keypair(self, name, path, keytype=None, passphrase="", bits=None, comment=""): """ Generates a new private and public key pair--stored in the user's directory using the given *name* and other optional parameters (using OpenSSH). If *keytype* is given, it must be one of "ecdsa", "rsa" or "dsa" (case insensitive). If *keytype* is "rsa" or "ecdsa", *bits* may be specified to specify the size of the key. .. note:: Defaults to generating a 521-byte ecdsa key if OpenSSH is version 5.7+. Otherwise a 2048-bit rsa key will be used. """ self.ssh_log.debug('openssh_generate_new_keypair()') openssh_version = shell_command('ssh -V')[1] ssh_major_version = int( openssh_version.split()[0].split('_')[1].split('.')[0]) key_path = os.path.join(path, name) ssh_minor_version = int( openssh_version.split()[0].split('_')[1].split('.')[1][0]) ssh_version = "%s.%s" % (ssh_major_version, ssh_minor_version) ssh_version = float(ssh_version) if not keytype: if ssh_version >= 5.7: keytype = "ecdsa" else: keytype = "rsa" else: keytype = keytype.lower() if not bits and keytype == "ecdsa": bits = 521 # Not a typo: five-hundred-twenty-one bits elif not bits and keytype == "rsa": bits = 2048 if not passphrase: # This just makes sure False and None end up as '' passphrase = '' hostname = os.uname()[1] if not comment: now = datetime.now().isoformat() comment = "Generated by Gate One on %s %s" % (hostname, now) ssh_keygen_path = which('ssh-keygen') command = ( "%s " # Path to ssh-keygen "-b %s " # bits "-t %s " # keytype "-C '%s' " # comment "-f '%s'" # Key path % (ssh_keygen_path, bits, keytype, comment, key_path) ) self.ssh_log.debug("Keygen command: %s" % command) m = self.new_multiplex(command, "gen_ssh_keypair") call_errorback = partial(errorback, self) m.expect('^Overwrite.*', overwrite, optional=True, preprocess=False, timeout=10) passphrase_handler = partial(enter_passphrase, passphrase) m.expect('^Enter passphrase', passphrase_handler, errorback=call_errorback, preprocess=False, timeout=10) m.expect('^Enter same passphrase again', passphrase_handler, errorback=call_errorback, preprocess=False, timeout=10) finalize = partial(finished, self) # The regex below captures the md5 fingerprint which tells us the # operation was successful. m.expect( '(([0-9a-f][0-9a-f]\:){15}[0-9a-f][0-9a-f])', finalize, errorback=call_errorback, preprocess=False, timeout=15 # Key generation can take a little while ) m.spawn()