Source code for cloudmesh_client.common.SSHkey

from __future__ import print_function
import base64
import hashlib
import struct
from os.path import basename

from cloudmesh_client.common.ConfigDict import Config


# noinspection PyBroadException
[docs]class SSHkey(object): def __init__(self, file_path=None, keyname=None): self.__key__ = None self.read(file_path, keyname)
[docs] def get(self): return self.__key__
def __str__(self): return self.__key__['key'] def __repr__(self): return self.__key__['key']
[docs] def read(self, file_path, keyname=None): self.__key__ = {} if file_path is not None: orig_path = file_path file_path = Config.path_expand(file_path) uri = 'file://{}'.format(file_path) self.__key__ = { 'uri': uri, 'path': orig_path, 'string': open(file_path, "r").read().rstrip() } (self.__key__['type'], self.__key__['key'], self.__key__['comment']) = self._parse(self.__key__['string']) self.__key__['fingerprint'] = self._fingerprint(self.__key__['string']) # Workaround for multiple file entries in cloudmesh.yaml getting same name derived from file name (like id_rsa). # This caused the dict to have just 1 entry as the name is the key. # Change tracked in git issue #8 if keyname is None: name = basename(file_path).replace(".pub", "").replace("id_", "") else: name = keyname self.__key__['name'] = name self.__key__['comment'] = self.__key__['comment'] self.__key__['source'] = 'ssh' return self.__key__
@property def fingerprint(self): return self.__key__['fingerprint'] @property def key(self): return self.__key__['string'] @property def type(self): return self.__key__['type'] @property def comment(self): return self.__key__['comment'] @classmethod def _fingerprint(cls, entirekey): """returns the fingerprint of a key. :param entirekey: the key :type entirekey: string """ t, keystring, comment = cls._parse(entirekey) if keystring is not None: return cls._key_fingerprint(keystring) else: return '' @classmethod def _key_fingerprint(cls, key_string): """create the fingerprint form just the key. :param key_string: the key :type key_string: string """ # key = base64.decodestring(key_string) # fp_plain = hashlib.md5(key).hexdigest() key_padding = key_string.strip() + '=' * (4 - len(key_string.strip()) % 4) key = base64.b64decode(key_padding.encode('ascii')) fp_plain = hashlib.md5(key).hexdigest() return ':'.join(a + b for a, b in zip(fp_plain[::2], fp_plain[1::2])) @classmethod def _parse(cls, keystring): """ parse the keystring/keycontent into type,key,comment :param keystring: the content of a key in string format """ # comment section could have a space too keysegments = keystring.split(" ", 2) keytype = keysegments[0] key = None comment = None if len(keysegments) > 1: key = keysegments[1] if len(keysegments) > 2: comment = keysegments[2] return keytype, key, comment def _validate(self, keytype, key): """reads the key string from a file. THIS FUNCTION HAS A BUG. :param key: either the name of a file that contains the key, or the entire contents of such a file :param keytype: if 'file' the key is read form the file specified in key. if 'string' the key is passed as a string in key """ keystring = None if keytype.lower() == "file": try: keystring = open(key, "r").read() except: return False elif keytype.lower() == "string": keystring = key try: keytype, key_string, comment = self._parse(keystring) data = base64.decodestring(key_string) int_len = 4 str_len = struct.unpack('>I', data[:int_len])[0] # this should return 7 if data[int_len:int_len + str_len] == keytype: return True except Exception as e: # print(e) return False def _keyname_sanitation(self, username, keyname): keynamenew = "%s_%s" % ( username, keyname.replace('.', '_').replace('@', '_')) return keynamenew
# unit testing
[docs]def main(): from pprint import pprint sshkey = SSHkey("~/.ssh/id_rsa.pub") pprint(sshkey.key) print("Fingerprint:", sshkey.fingerprint) pprint(sshkey.__key__) print("sshkey", sshkey) print("str", str(sshkey)) print(sshkey.type) print(sshkey.__key__['key']) print(sshkey.key) print(sshkey.comment) """ key1 = "ssh-rsa abcdefg comment" key2 = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDD+NswLi/zjz" + \ "7Vf575eo9iWWku5m4nVSPMgP13JbKCTVKtavAXt8UPZTkYVWi" + \ "USeXRqlf+EZM11U8Mq6C/P/ECJS868rn2KSwFosNPF0OOz8zm" + \ "TvBQShtvBBBVd1kmZePxFGviZbKwe3z3iATLKE8h7pwcupqTi" + \ "n9m3FhQRsGSF7YTFcGXv0ZqxFA2j9+Ix7SVbN5IYxxgwc+mxO" + \ "zYIy1SKEAOPJQFXKkiXxNdLSzGgjkurhPAIns8MNYL9usKMGz" + \ "hgp656onGkSbQHZR3ZHsSsTXWP3SV5ih4QTTFunwB6C0TMQVs" + \ "EGw1P49hhFktb3md+RC4DFP7ZOzfkd9nne2B mycomment" print(key_validate("string", key1)) print(key_validate("string", key2)) print(key_parse(key1)) print(key_parse("abcdedfg")) print(key_parse("ssh-rsa somestringhere")[2]) """
if __name__ == "__main__": main()