diff --git a/src/ssh/HISTORY.md b/src/ssh/HISTORY.md index c4cb447b37a..1146d629ba1 100644 --- a/src/ssh/HISTORY.md +++ b/src/ssh/HISTORY.md @@ -1,6 +1,11 @@ Release History =============== +0.1.4 +----- +* Change to use the first in the list of validprincipals as the default username +* Remove old paramiko dependency + 0.1.3 ----- * Add support for using private IPs diff --git a/src/ssh/azext_ssh/custom.py b/src/ssh/azext_ssh/custom.py index 8c479d584c8..9694aa6feef 100644 --- a/src/ssh/azext_ssh/custom.py +++ b/src/ssh/azext_ssh/custom.py @@ -54,10 +54,14 @@ def _get_and_write_certificate(cmd, public_key_file, cert_file): data = _prepare_jwk_data(public_key_file) from azure.cli.core._profile import Profile profile = Profile(cli_ctx=cmd.cli_ctx) - username, certificate = profile.get_msal_token(scopes, data) + # we used to use the username from the token but now we throw it away + _, certificate = profile.get_msal_token(scopes, data) if not cert_file: cert_file = public_key_file + "-aadcert.pub" - return _write_cert_file(certificate, cert_file), username.lower() + _write_cert_file(certificate, cert_file) + # instead we use the validprincipals from the cert due to mismatched upn and email in guest scenarios + username = ssh_utils.get_ssh_cert_principals(cert_file)[0] + return cert_file, username.lower() def _prepare_jwk_data(public_key_file): diff --git a/src/ssh/azext_ssh/ssh_utils.py b/src/ssh/azext_ssh/ssh_utils.py index fa232dc5f4c..d056c8b29ea 100644 --- a/src/ssh/azext_ssh/ssh_utils.py +++ b/src/ssh/azext_ssh/ssh_utils.py @@ -27,6 +27,28 @@ def create_ssh_keyfile(private_key_file): subprocess.call(command, shell=platform.system() == 'Windows') +def get_ssh_cert_info(cert_file): + command = [_get_ssh_path("ssh-keygen"), "-L", "-f", cert_file] + logger.debug("Running ssh-keygen command %s", ' '.join(command)) + return subprocess.check_output(command, shell=platform.system() == 'Windows').decode().splitlines() + + +def get_ssh_cert_principals(cert_file): + info = get_ssh_cert_info(cert_file) + principals = [] + in_principal = False + for line in info: + if ":" in line: + in_principal = False + if "Principals:" in line: + in_principal = True + continue + if in_principal: + principals.append(line.strip()) + + return principals + + def write_ssh_config(config_path, resource_group, vm_name, overwrite, ip, username, cert_file, private_key_file): file_utils.make_dirs_for_file(config_path) diff --git a/src/ssh/azext_ssh/tests/latest/test_custom.py b/src/ssh/azext_ssh/tests/latest/test_custom.py index 3ff75ca5fbc..b6b788f694e 100644 --- a/src/ssh/azext_ssh/tests/latest/test_custom.py +++ b/src/ssh/azext_ssh/tests/latest/test_custom.py @@ -37,6 +37,7 @@ def do_op_side_effect(cmd, resource_group, vm_name, ssh_ip, public_key_file, pri mock_do_op.assert_called_once_with( cmd, "rg", "vm", "ip", "public", "private", False, mock.ANY) + @mock.patch('azext_ssh.ssh_utils.get_ssh_cert_principals') @mock.patch('os.path.join') @mock.patch('azext_ssh.custom._assert_args') @mock.patch('azext_ssh.custom._check_or_create_public_private_files') @@ -45,10 +46,11 @@ def do_op_side_effect(cmd, resource_group, vm_name, ssh_ip, public_key_file, pri @mock.patch('azure.cli.core._profile.Profile.get_msal_token') @mock.patch('azext_ssh.custom._write_cert_file') def test_do_ssh_op(self, mock_write_cert, mock_ssh_creds, mock_get_mod_exp, mock_ip, - mock_check_files, mock_assert, mock_join): + mock_check_files, mock_assert, mock_join, mock_principal): cmd = mock.Mock() mock_op = mock.Mock() mock_check_files.return_value = "public", "private" + mock_principal.return_value = ["username"] mock_get_mod_exp.return_value = "modulus", "exponent" mock_ssh_creds.return_value = "username", "certificate" mock_join.return_value = "public-aadcert.pub" @@ -61,7 +63,7 @@ def test_do_ssh_op(self, mock_write_cert, mock_ssh_creds, mock_get_mod_exp, mock mock_get_mod_exp.assert_called_once_with("public") mock_write_cert.assert_called_once_with("certificate", "public-aadcert.pub") mock_op.assert_called_once_with( - "1.2.3.4", "username", mock_write_cert.return_value, "private") + "1.2.3.4", "username", "public-aadcert.pub", "private") @mock.patch('azext_ssh.custom._assert_args') @mock.patch('azext_ssh.custom._check_or_create_public_private_files') diff --git a/src/ssh/setup.py b/src/ssh/setup.py index 7876f43ad93..04293bca01f 100644 --- a/src/ssh/setup.py +++ b/src/ssh/setup.py @@ -7,7 +7,7 @@ from setuptools import setup, find_packages -VERSION = "0.1.3" +VERSION = "0.1.4" CLASSIFIERS = [ 'Development Status :: 4 - Beta', @@ -22,7 +22,6 @@ ] DEPENDENCIES = [ - 'paramiko==2.6.0', 'cryptography==2.8.0' ]