This is an automated email from the ASF dual-hosted git repository. tomaz pushed a commit to branch 2.8.x in repository https://gitbox.apache.org/repos/asf/libcloud.git
commit b3f36cd27a47dcce885a972f55b52c4e2eddf624 Author: Tomaz Muraus <[email protected]> AuthorDate: Tue Mar 31 23:06:18 2020 +0200 Add support for Ed25519 key types when using paramiko >= 2.2.0. --- libcloud/compute/ssh.py | 19 +++++++++--- libcloud/test/compute/test_ssh_client.py | 53 ++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/libcloud/compute/ssh.py b/libcloud/compute/ssh.py index 78718fe..fcc5d01 100644 --- a/libcloud/compute/ssh.py +++ b/libcloud/compute/ssh.py @@ -517,10 +517,20 @@ class ParamikoSSHClient(BaseSSHClient): # NOTE: Paramiko only supports key in PKCS#1 PEM format. """ + key_types = [ + (paramiko.RSAKey, 'RSA'), + (paramiko.DSSKey, 'DSA'), + (paramiko.ECDSAKey, 'EC') + ] - for cls, key_type in [(paramiko.RSAKey, 'RSA'), - (paramiko.DSSKey, 'DSA'), - (paramiko.ECDSAKey, 'EC')]: + paramiko_version = getattr(paramiko, '__version__', '0.0.0') + paramiko_version = tuple([int(c) for c in paramiko_version.split('.')]) + + if paramiko_version >= (2, 2, 0): + # Ed25519 is only supported in paramiko >= 2.2.0 + key_types.append((paramiko.ed25519key.Ed25519Key, 'Ed25519')) + + for cls, key_type in key_types: # Work around for paramiko not recognizing keys which start with # "----BEGIN PRIVATE KEY-----" # Since key is already in PEM format, we just try changing the @@ -546,7 +556,8 @@ class ParamikoSSHClient(BaseSSHClient): else: return key - msg = ('Invalid or unsupported key type (only RSA, DSS and ECDSA keys' + msg = ('Invalid or unsupported key type (only RSA, DSS, ECDSA and' + ' Ed25519 keys' ' in PEM format are supported). For more information on ' ' supported key file types, see %s' % (SUPPORTED_KEY_TYPES_URL)) raise paramiko.ssh_exception.SSHException(msg) diff --git a/libcloud/test/compute/test_ssh_client.py b/libcloud/test/compute/test_ssh_client.py index dc59df5..1a323df 100644 --- a/libcloud/test/compute/test_ssh_client.py +++ b/libcloud/test/compute/test_ssh_client.py @@ -183,6 +183,59 @@ class ParamikoSSHClientTests(LibcloudTestCase): assertRaisesRegex(self, paramiko.ssh_exception.PasswordRequiredException, expected_msg, mock.connect) + conn_params = {'hostname': 'dummy.host.org', + 'username': 'ubuntu', + 'key_files': path} + + mock = ParamikoSSHClient(**conn_params) + + expected_msg = 'private key file is encrypted' + assertRaisesRegex(self, paramiko.ssh_exception.PasswordRequiredException, + expected_msg, mock.connect) + + @patch('paramiko.SSHClient', Mock) + def test_password_protected_key_valid_password_provided(self): + path = os.path.join(os.path.dirname(__file__), + 'fixtures', 'misc', + 'test_rsa_2048b_pass_foobar.key') + + # Supplied as key_material + with open(path, 'r') as fp: + private_key = fp.read() + + conn_params = {'hostname': 'dummy.host.org', + 'username': 'ubuntu', + 'key_material': private_key, + 'key_password': 'foobar'} + + mock = ParamikoSSHClient(**conn_params) + self.assertTrue(mock.connect()) + + conn_params = {'hostname': 'dummy.host.org', + 'username': 'ubuntu', + 'key_files': path, + 'key_password': 'foobar'} + + mock = ParamikoSSHClient(**conn_params) + self.assertTrue(mock.connect()) + + @patch('paramiko.SSHClient', Mock) + def test_ed25519_key_type(self): + path = os.path.join(os.path.dirname(__file__), + 'fixtures', 'misc', + 'test_ed25519.key') + + # Supplied as key_material + with open(path, 'r') as fp: + private_key = fp.read() + + conn_params = {'hostname': 'dummy.host.org', + 'username': 'ubuntu', + 'key_material': private_key} + + mock = ParamikoSSHClient(**conn_params) + self.assertTrue(mock.connect()) + def test_key_material_valid_pem_keys_invalid_header_auto_conversion(self): # Test a scenario where valid PEM keys with invalid headers which is # not recognized by paramiko are automatically converted in a format
