def save(self, master_key: PKey): with io.StringIO() as buffer_: master_key.write_private_key(buffer_) pem = buffer_.getvalue() self.driver.upload_object_via_stream( self._countable_iterator([pem]), self.container, self.object_name, {"content_type": "application/x-pem-key"} )
def save(self, master_key: PKey): with io.StringIO() as buffer_: master_key.write_private_key(buffer_) pem = buffer_.getvalue() self.driver.upload_object_via_stream( self._countable_iterator([pem]), self.container, self.object_name, {'content_type': 'application/x-pem-key'})
def format_openssh_pubkey(key: PKey) -> str: """Format the given ``key`` to an OpenSSH public key line, used by :file:`authorized_keys`, :file:`id_rsa.pub`, etc. :param key: the key object to format :type key: :class:`paramiko.pkey.PKey` :return: a formatted openssh public key line :rtype: :class:`str` """ return '{} {} '.format(key.get_name(), key.get_base64())
def test_parse_junk(self): """Non-key data is allowed before and after the key itself""" key_str = '\n'.join([ "BLA bla BLA", "Lots of junk", self.ecdsa_str.strip(), "It's your lucky day, we even have trailing junk!" ]) self.assertEqual(PKey._parse_openssh_pkey(key_str), self.ecdsa_parsed)
def save(self, master_key: PKey): extra = {'content_type': 'application/x-pem-key'} if isinstance(self.driver, S3StorageDriver): # On some cases (altough unknown condition), S3 driver failed to # match signature when it uploads object through stream. # This is workaround to upload the master key without stream. with tempfile.NamedTemporaryFile('w+', encoding='utf-8') as f: master_key.write_private_key(f) f.file.flush() self.driver.upload_object(f.name, self.container, self.object_name, extra) return with io.StringIO() as buffer_: master_key.write_private_key(buffer_) pem = buffer_.getvalue() self.driver.upload_object_via_stream(self._countable_iterator([pem]), self.container, self.object_name, extra)
def test_parse_old_plain(self): key_str = open(_support("test_rsa.key")).read() pkformat, typ, headers, data = PKey._parse_openssh_pkey(key_str) self.assertEqual(pkformat, PKey.FORMAT_ORIGINAL) self.assertEqual(typ, RSAKey.LEGACY_TYPE) self.assertEqual(headers, {}) self.assertIsInstance(data, bytes) self.assertEqual(len(data), 606)
def test_parse_new(self): """In new format, parsing is same for encryped and un-encrypted.""" key_str = open(_support("test_ed25519.key")).read() pkformat, typ, headers, data = PKey._parse_openssh_pkey(key_str) self.assertEqual(pkformat, PKey.FORMAT_OPENSSH) self.assertEqual(typ, "OPENSSH") self.assertEqual(headers, {}) self.assertIsInstance(data, bytes) self.assertEqual(len(data), 266)
def load(self) -> PKey: if os.path.isfile(self.path): classes = PKey.__subclasses__() last = len(classes) + 1 for i, cls in enumerate(classes): try: return cls.from_private_key_file(self.path) except SSHException: if i == last: raise continue raise EmptyStoreError()
def get_key_fingerprint(key: PKey, glue: str=':') -> str: """Get the hexadecimal fingerprint string of the ``key``. :param key: the key to get fingerprint :type key: :class:`paramiko.pkey.PKey` :param glue: glue character to be placed between bytes. ``':'`` by default :type glue: :class:`str` :return: the fingerprint string :rtype: :class:`str` """ return glue.join(map('{:02x}'.format, key.get_fingerprint()))
def save(self, master_key: PKey) -> None: extra = {'content_type': 'application/x-pem-key'} if isinstance(self.driver, S3StorageDriver): # On some cases (altough unknown condition), S3 driver failed to # match signature when it uploads object through stream. # This is workaround to upload the master key without stream. with tempfile.NamedTemporaryFile('w+', encoding='utf-8') as f: master_key.write_private_key(f) getattr(f, 'file').flush() # workaround mypy self.driver.upload_object( f.name, self.container, self.object_name, extra ) return with io.StringIO() as buffer_: master_key.write_private_key(buffer_) pem = getattr(buffer_, 'getvalue')() # workaround mypy self.driver.upload_object_via_stream( type(self)._countable_iterator([pem]), self.container, self.object_name, extra )
def test_parse_old_password(self): """Old format with headers""" pkformat, typ, headers, data = PKey._parse_openssh_pkey(self.ecdsa_str) self.assertEqual(pkformat, PKey.FORMAT_ORIGINAL) self.assertEqual(typ, ECDSAKey.LEGACY_TYPE) self.assertEqual( headers, { "dek-info": "AES-128-CBC,EEB56BC745EDB2DE04FC3FE1F8DA387E", "proc-type": "4,ENCRYPTED" }) self.assertIsInstance(data, bytes) self.assertEqual(len(data), 128)
def connect(self): try: self.remote_client = SSHClient() self.remote_client.set_missing_host_key_policy(AutoAddPolicy()) self.remote_client.connect( self.hostname, username=self.username, password=self.password, port=self.port, pkey=PKey(self.private_key) if self.private_key else None, key_filename=self.private_key_file_path, ) except AuthenticationException as e: raise RemoteExecutor.AuthenticationException(str(e)) except NoValidConnectionsError as e: raise RemoteExecutor.NoValidConnectionException(str(e)) except Exception as e: raise RemoteExecutor.ConnectionException(str(e))
def register(self, identity: Identity, public_key: PKey) -> None: with self._connect() as connection: cursor = connection.cursor() try: params = (self._get_key_params(public_key) + (public_key.get_base64(),) + self._get_identity_params(identity)) self._execute(cursor, ''' INSERT INTO geofront_public_key ( key_type, key_fingerprint, key_base64, team_type, identifier ) VALUES (?, ?, ?, ?, ?) ''', params) connection.commit() except self.integrity_error as e: raise DuplicatePublicKeyError(str(e)) finally: cursor.close()
def read_private_key_file(file_: io.IOBase) -> PKey: """Read a private key file. Similar to :meth:`PKey.from_private_key() <paramiko.pkey.PKey.from_private_key>` except it guess the key type. :param file_: a stream of the private key to read :type file_: :class:`io.IOBase` :return: the read private key :rtype: :class:`paramiko.pkey.PKery` :raise paramiko.ssh_exception.SSHException: when something goes wrong """ classes = PKey.__subclasses__() last = len(classes) + 1 for i, cls in enumerate(classes): try: return cls.from_private_key(file_) except SSHException: if i == last: raise file_.seek(0) continue
def check_auth_publickey(self, username: Text, key: PKey) -> int: ssh_pub_key = SSHKey(f"{key.get_name()} {key.get_base64()}") ssh_pub_key.parse() logging.debug("check_auth_publickey: username=%s, key=%s %s %sbits", username, key.get_name(), ssh_pub_key.hash_sha256(), ssh_pub_key.bits) if self.session.session_log_dir: os.makedirs(self.session.session_log_dir, exist_ok=True) pubkeyfile_path = os.path.join(self.session.session_log_dir, 'publickeys') with open(pubkeyfile_path, 'a+') as pubkeyfile: pubkeyfile.write( f"{key.get_name()} {key.get_base64()} saved-from-auth-publickey\n" ) if self.args.disable_pubkey_auth: logging.debug( "Publickey login attempt, but publickey auth was disabled!") return paramiko.common.AUTH_FAILED if self.args.accept_first_publickey: logging.debug('host probing disabled - first key accepted') if self.args.disallow_publickey_auth: logging.debug( 'ignoring argument --disallow-publickey-auth, first key still accepted' ) self.session.authenticator.authenticate(username, key=None) self.session.accepted_key = key return paramiko.common.AUTH_SUCCESSFUL auth_result: int = self.session.authenticator.authenticate(username, key=key) if auth_result == paramiko.common.AUTH_SUCCESSFUL: self.session.accepted_key = key if self.session.accepted_key is not None and self.args.enable_trivial_auth: logging.debug("found valid key for trivial authentication") return paramiko.common.AUTH_FAILED if self.args.disallow_publickey_auth: return paramiko.common.AUTH_FAILED return auth_result
def save(self, master_key: PKey): master_key.write_private_key_file(self.path)
def test_parse_empty(self): with self.assertRaises(SSHException) as ctx: PKey._parse_openssh_pkey("") self.assertEqual(str(ctx.exception), "not a valid private key file")
def test_bad_base64(self): with self.assertRaises(SSHException) as ctx: PKey._parse_openssh_pkey(INVALID_BASE64_KEY) self.assertEqual(str(ctx.exception), "base64 decoding error: Incorrect padding")
def test_parse_end_line(self): """END tag must be on a line by itself""" key_str = self.ecdsa_str.strip() + "BLA" with self.assertRaises(SSHException): PKey._parse_openssh_pkey(key_str)
def test_parse_begin_line(self): """BEGIN tag must be on a line by itself""" key_str = "BLA" + self.ecdsa_str with self.assertRaises(SSHException): PKey._parse_openssh_pkey(key_str)
def main(*margs): parser = argparse.ArgumentParser("Netconf Client Utility") parser.add_argument("--debug", action="store_true", help="Enable debug logging") parser.add_argument('--host', default="localhost", help='Netconf server hostname') parser.add_argument( '--get', const="", nargs='?', help="Perform <get>. arg value is xpath/xml filter or taken from infile if not specified") parser.add_argument( '--get-config', const="", nargs='?', help= "Perform <get-config>. arg value is xpath/xml filter or taken from infile if not specified") parser.add_argument( '--hello', action="store_true", help="Do hello and return capabilities of server.") parser.add_argument("-i", "--infile", help="File to read from") parser.add_argument( '-p', '--password', default=None, help='Password (or passphrase) use "env:" or "file:" prefix to specify password source') parser.add_argument( '-k', '--keyfile', default=None, help='SSH key use password to specify passphrase') # Deprecated now parse password args more functional parser.add_argument('--passenv', default=None, help=argparse.SUPPRESS) parser.add_argument('--port', type=int, default=830, help='Netconf server port') parser.add_argument("-q", "--quiet", action="store_true", help="Quiet operation") parser.add_argument('--source', default="running", help="Source for get config") parser.add_argument('--timeout', type=float, help="Timeout for command in fractional seconds") parser.add_argument('-u', '--username', default="admin", help='Netconf username') parser.add_argument("-v", "--verbose", action="store_true", help="Verbose logging") args = parser.parse_args(*margs) if args.passenv and args.password: print("Only one of --password and --passenv allowed", file=sys.stderr) sys.exit(1) if args.passenv: args.password = os.environ[args.passenv] else: args.password = parse_password_arg(args.password) if args.keyfile: args.password = PKey.from_private_key_file(args.keyfile, password=args.password) if args.debug: logging.basicConfig(level=logging.DEBUG) elif args.verbose: logging.basicConfig(level=logging.INFO) elif args.quiet: logging.basicConfig(level=logging.ERROR) else: logging.basicConfig(level=logging.WARNING) session = client.NetconfSSHSession( args.host, args.port, args.username, args.password, debug=args.debug) if args.hello: result = "\n".join(session.capabilities) + "\n" elif args.get is not None: result = session.get(args.get, args.timeout) result = " " + etree.tounicode(result, pretty_print=True) elif args.get_config is not None: result = session.get_config(args.source, args.get_config, args.timeout) result = " " + etree.tounicode(result, pretty_print=True) else: print("get: {}".format(args.get)) if args.infile: xml = open(args.infile).read() else: xml = sys.stdin.read() if not xml: print("Nothing to do.", file=sys.stderr) sys.exit(1) result = session.send_rpc(xml)[2] sys.stdout.write(result) session.close()
def test_parse_crlf(self): """Test handling of Windows newlines""" key_str = self.ecdsa_str key_str = key_str.replace("\n", "\r\n") self.assertEqual(PKey._parse_openssh_pkey(key_str), self.ecdsa_parsed)
def test_parse_whitespace(self): """In some places, extraneous whitespace should not affect parsing""" key_str = self.ecdsa_str key_str = key_str.replace("\n", " \t\n") key_str = key_str.replace(": ", ": \t ") self.assertEqual(PKey._parse_openssh_pkey(key_str), self.ecdsa_parsed)
def _get_key_params(self, public_key: PKey) -> Tuple[str, str]: return public_key.get_name(), get_key_fingerprint(public_key, '')
def setUpClass(cls): # Several tests rely on these fields. cls.ecdsa_str = open( _support("test_ecdsa_password_256.key")).read().strip() cls.ecdsa_parsed = PKey._parse_openssh_pkey(cls.ecdsa_str)