From 5f0e0307ae7cf60ee3801ae18400c20a0b32290b Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Mon, 6 Mar 2017 19:05:22 -0800 Subject: [PATCH 1/4] remove the length limitation of admin-username as shorter name is accpeted by portal and vm --- .../cli/command_modules/vm/_validators.py | 75 +++++++++++++++---- .../azure-cli-vm/tests/test_vm_actions.py | 57 +++++++++++++- 2 files changed, 116 insertions(+), 16 deletions(-) diff --git a/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py b/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py index 75be7e57989..748b882e6bb 100644 --- a/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py +++ b/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py @@ -523,15 +523,9 @@ def _validate_vm_create_auth(namespace): StorageProfile.SASpecializedOSDisk]: return - if len(namespace.admin_username) < 6 or namespace.admin_username.lower() == 'root': - # prompt for admin username if inadequate - from azure.cli.core.prompting import prompt, NoTTYException - try: - logger.warning("Cannot use admin username: %s. Admin username should be at " - "least 6 characters and cannot be 'root'", namespace.admin_username) - namespace.admin_username = prompt('Admin Username: ') - except NoTTYException: - raise CLIError('Please specify a valid admin username in non-interactive mode.') + err = _validate_admin_username(namespace.admin_username, namespace.os_type.lower() == 'linux') + if err: + raise CLIError(err) if not namespace.os_type: raise CLIError("Unable to resolve OS type. Specify '--os-type' argument.") @@ -551,13 +545,17 @@ def _validate_vm_create_auth(namespace): "incorrect usage for authentication-type 'password': " "[--admin-username USERNAME] --admin-password PASSWORD") - if not namespace.admin_password: - # prompt for admin password if not supplied - from azure.cli.core.prompting import prompt_pass, NoTTYException - try: + # validate password + from azure.cli.core.prompting import prompt_pass, NoTTYException + try: + if not namespace.admin_password: namespace.admin_password = prompt_pass('Admin Password: ', confirm=True) - except NoTTYException: - raise CLIError('Please specify both username and password in non-interactive mode.') + err = _validate_admin_password(namespace.admin_password, + namespace.os_type.lower() == 'linux') + if err: + raise CLIError(err) + except NoTTYException: + raise CLIError('Please specify both username and password in non-interactive mode.') elif namespace.authentication_type == 'ssh': @@ -571,6 +569,53 @@ def _validate_vm_create_auth(namespace): '/home/{}/.ssh/authorized_keys'.format(namespace.admin_username) +def _validate_admin_username(username, is_linux): + if not username: + return "admin user name can not be empty" + # pylint: disable=line-too-long + pattern = (r'[\\\/"\[\]:|<>+=;,?*@#()!A-Z]+' if is_linux else r'[\\\/"\[\]:|<>+=;,?*@]+') + linux_err = r'admin user name cannot contain upper case character A-Z, special characters \/"[]:|<>+=;,?*@#()! or start with $ or -' + win_err = r'admin user name cannot contain special characters \/"[]:|<>+=;,?*@# or ends with .' + if re.findall(pattern, username): + return linux_err if is_linux else win_err + if is_linux and re.findall(r'^[$-]+', username): + return linux_err + if not is_linux and username.endswith('.'): + return win_err + disallowed_user_names = [ + "administrator", "admin", "user", "user1", "test", "user2", + "test1", "user3", "admin1", "1", "123", "a", "actuser", "adm", + "admin2", "aspnet", "backup", "console", "david", "guest", "john", + "owner", "root", "server", "sql", "support", "support_388945a0", + "sys", "test2", "test3", "user4", "user5"] + if username.lower() in disallowed_user_names: + return 'The specified admin user name is not allowed, as it uses reserved words. Try again with a different value' + return None + + +def _validate_admin_password(password, is_linux): + max_length = 72 if is_linux else 123 + min_length = 12 + if len(password) not in range(min_length, max_length + 1): + return 'The pssword length must be between {} and {}'.format(min_length, max_length) + contains_lower = re.findall('[a-z]+', password) + contains_upper = re.findall('[A-Z]+', password) + contains_digit = re.findall('[0-9]+', password) + contains_special_char = re.findall(r'[ `~!@#$%^&*()=+_\[\]{}\|;:.\/\'\",<>?]+', password) + count = len([x for x in [contains_lower, contains_upper, + contains_digit, contains_special_char] if x]) + # pylint: disable=line-too-long + if count < 3: + return 'Password must have the 3 of the following: 1 lower case character, 1 upper case character, 1 number and 1 special character' + disallowed_passwords = [ + "abc@123", "P@$$w0rd", "P@ssw0rd", "P@ssword123", "Pa$$word", + "pass@word1", "Password!", "Password1", "Password22", "iloveyou!" + ] + if password.lower() in disallowed_passwords: + return 'The specified password is not allowed' + return None + + def validate_ssh_key(namespace): string_or_file = (namespace.ssh_key_value or os.path.join(os.path.expanduser('~'), '.ssh/id_rsa.pub')) diff --git a/src/command_modules/azure-cli-vm/tests/test_vm_actions.py b/src/command_modules/azure-cli-vm/tests/test_vm_actions.py index a893c8470fb..59ca8adbc1c 100644 --- a/src/command_modules/azure-cli-vm/tests/test_vm_actions.py +++ b/src/command_modules/azure-cli-vm/tests/test_vm_actions.py @@ -12,7 +12,9 @@ from azure.cli.command_modules.vm._validators import (validate_ssh_key, _is_valid_ssh_rsa_public_key, - _figure_out_storage_source) + _figure_out_storage_source, + _validate_admin_username, + _validate_admin_password) class TestActions(unittest.TestCase): @@ -65,3 +67,56 @@ def test_figure_out_storage_source(self): self.assertFalse(src_disk) self.assertFalse(src_snapshot) self.assertEqual(src_blob_uri, test_data) + + def test_validate_admin_username_linux(self): + # pylint: disable=line-too-long + err_invalid_char = r'admin user name cannot contain upper case character A-Z, special characters \/"[]:|<>+=;,?*@#()! or start with $ or -' + + self.assertEqual(err_invalid_char, _validate_admin_username('!@#', True)) + self.assertIsNotNone(_validate_admin_username('david', True), + 'The specified admin user name is not allowed, as it uses reserved words. Try again with a different value') + self.assertEqual(err_invalid_char, _validate_admin_username('dav[', True)) + self.assertEqual(err_invalid_char, _validate_admin_username('Adavid', True)) + self.assertEqual(err_invalid_char, _validate_admin_username('-ddavid', True)) + + self.assertIsNone(_validate_admin_username('d-avid1', True)) + self.assertIsNone(_validate_admin_username('david1', True)) + self.assertIsNone(_validate_admin_username('david1.', True)) + + def test_validate_admin_username_windows(self): + # pylint: disable=line-too-long + err_invalid_char = r'admin user name cannot contain special characters \/"[]:|<>+=;,?*@# or ends with .' + + self.assertEqual(err_invalid_char, _validate_admin_username('!@#', False)) + self.assertIsNotNone('The specified admin user name is not allowed, as it uses reserved words. Try again with a different value', + _validate_admin_username('david', False)) + self.assertEqual(err_invalid_char, _validate_admin_username('dav[', False)) + self.assertEqual(err_invalid_char, _validate_admin_username('dddivid.', False)) + + self.assertIsNone(_validate_admin_username('ADAVID', False)) + self.assertIsNone(_validate_admin_username('d-avid1', False)) + self.assertIsNone(_validate_admin_username('david1', False)) + + def test_validate_admin_password_linux(self): + # pylint: disable=line-too-long + err_length = 'The pssword length must be between 12 and 72' + err_variaty = 'Password must have the 3 of the following: 1 lower case character, 1 upper case character, 1 number and 1 special character' + + self.assertEqual(err_length, _validate_admin_password('te', True)) + self.assertEqual(err_length, _validate_admin_password('P12' + '3' * 70, True)) + self.assertEqual(err_variaty, _validate_admin_password('te12312312321', True)) + + self.assertIsNone(_validate_admin_password('Password22345', True)) + self.assertIsNone(_validate_admin_password('Password12!@#', True)) + + def test_validate_admin_password_windows(self): + # pylint: disable=line-too-long + err_length = 'The pssword length must be between 12 and 123' + err_variaty = 'Password must have the 3 of the following: 1 lower case character, 1 upper case character, 1 number and 1 special character' + + self.assertEqual(err_length, _validate_admin_password('P1', False)) + self.assertEqual(err_length, _validate_admin_password('te14' + '3' * 120, False)) + self.assertEqual(err_variaty, _validate_admin_password('te12345678997', False)) + + self.assertIsNone(_validate_admin_password('Password22!!!', False)) + self.assertIsNone(_validate_admin_password('Pas' + '1' * 70, False)) From 810044a17047aaed25133b4813405f1488cd2a03 Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Thu, 16 Mar 2017 17:24:20 -0700 Subject: [PATCH 2/4] update tests to use legit password --- .../azure-cli-vm/tests/test_vm_commands.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/command_modules/azure-cli-vm/tests/test_vm_commands.py b/src/command_modules/azure-cli-vm/tests/test_vm_commands.py index 237ae93652f..9ae05618cd2 100644 --- a/src/command_modules/azure-cli-vm/tests/test_vm_commands.py +++ b/src/command_modules/azure-cli-vm/tests/test_vm_commands.py @@ -497,7 +497,7 @@ def test_vm_create_no_wait(self): self.execute() def body(self): - self.cmd('vm create -g {} -n {} --admin-username user12 --admin-password VerySecret! --authentication-type password --image UbuntuLTS --no-wait'.format(self.resource_group, self.name), checks=NoneCheck()) + self.cmd('vm create -g {} -n {} --admin-username user12 --admin-password testPassword0 --authentication-type password --image UbuntuLTS --no-wait'.format(self.resource_group, self.name), checks=NoneCheck()) self.cmd('vm wait -g {} -n {} --custom "{}"'.format(self.resource_group, self.name, "instanceView.statuses[?code=='PowerState/running']"), checks=NoneCheck()) self.cmd('vm get-instance-view -g {} -n {}'.format(self.resource_group, self.name), checks=[ JMESPathCheck("length(instanceView.statuses[?code=='PowerState/running'])", 1) @@ -547,7 +547,7 @@ def __init__(self, test_method): def set_up(self): super(VMExtensionScenarioTest, self).set_up() - self.cmd('vm create -n {} -g {} --image UbuntuLTS --authentication-type password --admin-username user11 --admin-password TestPass1@'.format(self.vm_name, self.resource_group)) + self.cmd('vm create -n {} -g {} --image UbuntuLTS --authentication-type password --admin-username user11 --admin-password testPassword0'.format(self.vm_name, self.resource_group)) def test_vm_extension(self): self.execute() @@ -764,7 +764,7 @@ def test_vm_boot_diagnostics(self): def set_up(self): super(VMBootDiagnostics, self).set_up() self.cmd('storage account create -g {} -n {} --sku Standard_LRS -l westus'.format(self.resource_group, self.storage_name)) - self.cmd('vm create -n {} -g {} --image UbuntuLTS --authentication-type password --admin-username user11 --admin-password TestPass1@ --use-unmanaged-disk'.format(self.vm_name, self.resource_group)) + self.cmd('vm create -n {} -g {} --image UbuntuLTS --authentication-type password --admin-username user11 --admin-password testPassword0 --use-unmanaged-disk'.format(self.vm_name, self.resource_group)) def body(self): storage_uri = 'https://{}.blob.core.windows.net/'.format(self.storage_name) @@ -789,7 +789,7 @@ def __init__(self, test_method): def set_up(self): super(VMSSExtensionInstallTest, self).set_up() - self.cmd('vmss create -n {} -g {} --image UbuntuLTS --authentication-type password --admin-username admin123 --admin-password TestPass1@'.format(self.vmss_name, self.resource_group)) + self.cmd('vmss create -n {} -g {} --image UbuntuLTS --authentication-type password --admin-username admin123 --admin-password testPassword0'.format(self.vmss_name, self.resource_group)) def test_vmss_extension(self): self.execute() @@ -1369,7 +1369,7 @@ def body(self): instance_count = 5 new_instance_count = 4 - self.cmd('vmss create --admin-password Test1234@! --name {} -g {} --admin-username myadmin --image Win2012R2Datacenter --instance-count {}' + self.cmd('vmss create --admin-password testPassword0 --name {} -g {} --admin-username myadmin --image Win2012R2Datacenter --instance-count {}' .format(vmss_name, self.resource_group, instance_count)) self.cmd('vmss show --name {} -g {}'.format(vmss_name, self.resource_group), @@ -1441,7 +1441,7 @@ def body(self): caching = 'ReadWrite' upgrade_policy = 'automatic' - self.cmd('vmss create --image Debian --admin-password Test1234@! -l westus' + self.cmd('vmss create --image Debian --admin-password testPassword0 -l westus' ' -g {} -n {} --disable-overprovision --instance-count {}' ' --storage-caching {} --upgrade-policy-mode {}' ' --authentication-type password --admin-username myadmin --public-ip-address {}' From 7f545da3d07f0c784a02d9033bf5692cfcbdc160 Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Thu, 16 Mar 2017 17:53:49 -0700 Subject: [PATCH 3/4] make validation routine throw --- .../cli/command_modules/vm/_validators.py | 32 ++++----- .../azure-cli-vm/tests/test_vm_actions.py | 66 +++++++++++-------- .../azure-cli-vm/tests/test_vm_defaults.py | 2 +- 3 files changed, 52 insertions(+), 48 deletions(-) diff --git a/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py b/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py index 748b882e6bb..a40661e827e 100644 --- a/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py +++ b/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py @@ -523,9 +523,7 @@ def _validate_vm_create_auth(namespace): StorageProfile.SASpecializedOSDisk]: return - err = _validate_admin_username(namespace.admin_username, namespace.os_type.lower() == 'linux') - if err: - raise CLIError(err) + _validate_admin_username(namespace.admin_username, namespace.os_type.lower() == 'linux') if not namespace.os_type: raise CLIError("Unable to resolve OS type. Specify '--os-type' argument.") @@ -545,17 +543,16 @@ def _validate_vm_create_auth(namespace): "incorrect usage for authentication-type 'password': " "[--admin-username USERNAME] --admin-password PASSWORD") - # validate password from azure.cli.core.prompting import prompt_pass, NoTTYException try: if not namespace.admin_password: namespace.admin_password = prompt_pass('Admin Password: ', confirm=True) - err = _validate_admin_password(namespace.admin_password, - namespace.os_type.lower() == 'linux') - if err: - raise CLIError(err) except NoTTYException: - raise CLIError('Please specify both username and password in non-interactive mode.') + raise CLIError('Please specify password in non-interactive mode.') + + # validate password + _validate_admin_password(namespace.admin_password, + namespace.os_type.lower() == 'linux') elif namespace.authentication_type == 'ssh': @@ -577,11 +574,11 @@ def _validate_admin_username(username, is_linux): linux_err = r'admin user name cannot contain upper case character A-Z, special characters \/"[]:|<>+=;,?*@#()! or start with $ or -' win_err = r'admin user name cannot contain special characters \/"[]:|<>+=;,?*@# or ends with .' if re.findall(pattern, username): - return linux_err if is_linux else win_err + raise CLIError(linux_err if is_linux else win_err) if is_linux and re.findall(r'^[$-]+', username): - return linux_err + raise CLIError(linux_err) if not is_linux and username.endswith('.'): - return win_err + raise CLIError(win_err) disallowed_user_names = [ "administrator", "admin", "user", "user1", "test", "user2", "test1", "user3", "admin1", "1", "123", "a", "actuser", "adm", @@ -589,15 +586,15 @@ def _validate_admin_username(username, is_linux): "owner", "root", "server", "sql", "support", "support_388945a0", "sys", "test2", "test3", "user4", "user5"] if username.lower() in disallowed_user_names: - return 'The specified admin user name is not allowed, as it uses reserved words. Try again with a different value' - return None + raise CLIError('The specified admin user name is not allowed, as it uses reserved words. Try again with a different value') def _validate_admin_password(password, is_linux): max_length = 72 if is_linux else 123 min_length = 12 if len(password) not in range(min_length, max_length + 1): - return 'The pssword length must be between {} and {}'.format(min_length, max_length) + raise CLIError('The pssword length must be between {} and {}'.format(min_length, + max_length)) contains_lower = re.findall('[a-z]+', password) contains_upper = re.findall('[A-Z]+', password) contains_digit = re.findall('[0-9]+', password) @@ -606,14 +603,13 @@ def _validate_admin_password(password, is_linux): contains_digit, contains_special_char] if x]) # pylint: disable=line-too-long if count < 3: - return 'Password must have the 3 of the following: 1 lower case character, 1 upper case character, 1 number and 1 special character' + raise CLIError('Password must have the 3 of the following: 1 lower case character, 1 upper case character, 1 number and 1 special character') disallowed_passwords = [ "abc@123", "P@$$w0rd", "P@ssw0rd", "P@ssword123", "Pa$$word", "pass@word1", "Password!", "Password1", "Password22", "iloveyou!" ] if password.lower() in disallowed_passwords: - return 'The specified password is not allowed' - return None + raise CLIError('The specified password is not allowed') def validate_ssh_key(namespace): diff --git a/src/command_modules/azure-cli-vm/tests/test_vm_actions.py b/src/command_modules/azure-cli-vm/tests/test_vm_actions.py index 59ca8adbc1c..f385bbc9191 100644 --- a/src/command_modules/azure-cli-vm/tests/test_vm_actions.py +++ b/src/command_modules/azure-cli-vm/tests/test_vm_actions.py @@ -72,51 +72,59 @@ def test_validate_admin_username_linux(self): # pylint: disable=line-too-long err_invalid_char = r'admin user name cannot contain upper case character A-Z, special characters \/"[]:|<>+=;,?*@#()! or start with $ or -' - self.assertEqual(err_invalid_char, _validate_admin_username('!@#', True)) - self.assertIsNotNone(_validate_admin_username('david', True), - 'The specified admin user name is not allowed, as it uses reserved words. Try again with a different value') - self.assertEqual(err_invalid_char, _validate_admin_username('dav[', True)) - self.assertEqual(err_invalid_char, _validate_admin_username('Adavid', True)) - self.assertEqual(err_invalid_char, _validate_admin_username('-ddavid', True)) + self._verify_username_with_ex('david', True, 'The specified admin user name is not allowed, as it uses reserved words. Try again with a different value') + self._verify_username_with_ex('!@#', True, err_invalid_char) + self._verify_username_with_ex('dav[', True, err_invalid_char) + self._verify_username_with_ex('Adavid', True, err_invalid_char) + self._verify_username_with_ex('-ddavid', True, err_invalid_char) - self.assertIsNone(_validate_admin_username('d-avid1', True)) - self.assertIsNone(_validate_admin_username('david1', True)) - self.assertIsNone(_validate_admin_username('david1.', True)) + _validate_admin_username('d-avid1', True) + _validate_admin_username('david1', True) + _validate_admin_username('david1.', True) def test_validate_admin_username_windows(self): # pylint: disable=line-too-long err_invalid_char = r'admin user name cannot contain special characters \/"[]:|<>+=;,?*@# or ends with .' - self.assertEqual(err_invalid_char, _validate_admin_username('!@#', False)) - self.assertIsNotNone('The specified admin user name is not allowed, as it uses reserved words. Try again with a different value', - _validate_admin_username('david', False)) - self.assertEqual(err_invalid_char, _validate_admin_username('dav[', False)) - self.assertEqual(err_invalid_char, _validate_admin_username('dddivid.', False)) + self._verify_username_with_ex('david', False, 'The specified admin user name is not allowed, as it uses reserved words. Try again with a different value') + self._verify_username_with_ex('!@#', False, err_invalid_char) + self._verify_username_with_ex('dav[', False, err_invalid_char) + self._verify_username_with_ex('dddivid.', False, err_invalid_char) - self.assertIsNone(_validate_admin_username('ADAVID', False)) - self.assertIsNone(_validate_admin_username('d-avid1', False)) - self.assertIsNone(_validate_admin_username('david1', False)) + _validate_admin_username('ADAVID', False) + _validate_admin_username('d-avid1', False) + _validate_admin_username('david1', False) def test_validate_admin_password_linux(self): # pylint: disable=line-too-long err_length = 'The pssword length must be between 12 and 72' - err_variaty = 'Password must have the 3 of the following: 1 lower case character, 1 upper case character, 1 number and 1 special character' + err_variety = 'Password must have the 3 of the following: 1 lower case character, 1 upper case character, 1 number and 1 special character' - self.assertEqual(err_length, _validate_admin_password('te', True)) - self.assertEqual(err_length, _validate_admin_password('P12' + '3' * 70, True)) - self.assertEqual(err_variaty, _validate_admin_password('te12312312321', True)) + self._verify_password_with_ex('te', True, err_length) + self._verify_password_with_ex('P12' + '3' * 70, True, err_length) + self._verify_password_with_ex('te12312312321', True, err_variety) - self.assertIsNone(_validate_admin_password('Password22345', True)) - self.assertIsNone(_validate_admin_password('Password12!@#', True)) + _validate_admin_password('Password22345', True) + _validate_admin_password('Password12!@#', True) def test_validate_admin_password_windows(self): # pylint: disable=line-too-long err_length = 'The pssword length must be between 12 and 123' - err_variaty = 'Password must have the 3 of the following: 1 lower case character, 1 upper case character, 1 number and 1 special character' + err_variety = 'Password must have the 3 of the following: 1 lower case character, 1 upper case character, 1 number and 1 special character' - self.assertEqual(err_length, _validate_admin_password('P1', False)) - self.assertEqual(err_length, _validate_admin_password('te14' + '3' * 120, False)) - self.assertEqual(err_variaty, _validate_admin_password('te12345678997', False)) + self._verify_password_with_ex('P1', False, err_length) + self._verify_password_with_ex('te14' + '3' * 120, False, err_length) + self._verify_password_with_ex('te12345678997', False, err_variety) - self.assertIsNone(_validate_admin_password('Password22!!!', False)) - self.assertIsNone(_validate_admin_password('Pas' + '1' * 70, False)) + _validate_admin_password('Password22!!!', False) + _validate_admin_password('Pas' + '1' * 70, False) + + def _verify_username_with_ex(self, admin_username, is_linux, expected_err): + with self.assertRaises(CLIError) as context: + _validate_admin_username(admin_username, is_linux) + self.assertTrue(expected_err in str(context.exception)) + + def _verify_password_with_ex(self, admin_password, is_linux, expected_err): + with self.assertRaises(CLIError) as context: + _validate_admin_password(admin_password, is_linux) + self.assertTrue(expected_err in str(context.exception)) diff --git a/src/command_modules/azure-cli-vm/tests/test_vm_defaults.py b/src/command_modules/azure-cli-vm/tests/test_vm_defaults.py index 57e027f6f61..9543ccd5fa0 100644 --- a/src/command_modules/azure-cli-vm/tests/test_vm_defaults.py +++ b/src/command_modules/azure-cli-vm/tests/test_vm_defaults.py @@ -263,7 +263,7 @@ def test_linux_with_password(self): ns.os_type = "LINux" ns.authentication_type = 'password' ns.admin_username = 'user12345' - ns.admin_password = 'verySecret!' + ns.admin_password = 'verySecret!!!' _validate_vm_create_auth(ns) # still has 'password' self.assertEqual(ns.authentication_type, 'password') From 69729241559b55496e96b0d2cd3fad4ad60451de Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Fri, 17 Mar 2017 10:59:10 -0700 Subject: [PATCH 4/4] address review feedback --- .../cli/command_modules/vm/_validators.py | 20 +++---- .../azure-cli-vm/tests/test_vm_actions.py | 55 ++++++++++--------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py b/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py index a40661e827e..02a5dc78591 100644 --- a/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py +++ b/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py @@ -523,7 +523,7 @@ def _validate_vm_create_auth(namespace): StorageProfile.SASpecializedOSDisk]: return - _validate_admin_username(namespace.admin_username, namespace.os_type.lower() == 'linux') + _validate_admin_username(namespace.admin_username, namespace.os_type) if not namespace.os_type: raise CLIError("Unable to resolve OS type. Specify '--os-type' argument.") @@ -552,7 +552,7 @@ def _validate_vm_create_auth(namespace): # validate password _validate_admin_password(namespace.admin_password, - namespace.os_type.lower() == 'linux') + namespace.os_type) elif namespace.authentication_type == 'ssh': @@ -566,9 +566,10 @@ def _validate_vm_create_auth(namespace): '/home/{}/.ssh/authorized_keys'.format(namespace.admin_username) -def _validate_admin_username(username, is_linux): +def _validate_admin_username(username, os_type): if not username: - return "admin user name can not be empty" + raise CLIError("admin user name can not be empty") + is_linux = (os_type.lower() == 'linux') # pylint: disable=line-too-long pattern = (r'[\\\/"\[\]:|<>+=;,?*@#()!A-Z]+' if is_linux else r'[\\\/"\[\]:|<>+=;,?*@]+') linux_err = r'admin user name cannot contain upper case character A-Z, special characters \/"[]:|<>+=;,?*@#()! or start with $ or -' @@ -586,10 +587,11 @@ def _validate_admin_username(username, is_linux): "owner", "root", "server", "sql", "support", "support_388945a0", "sys", "test2", "test3", "user4", "user5"] if username.lower() in disallowed_user_names: - raise CLIError('The specified admin user name is not allowed, as it uses reserved words. Try again with a different value') + raise CLIError("This user name '{}' meets the general requirements, but is specifically disallowed for this image. Please try a different value.".format(username)) -def _validate_admin_password(password, is_linux): +def _validate_admin_password(password, os_type): + is_linux = (os_type.lower() == 'linux') max_length = 72 if is_linux else 123 min_length = 12 if len(password) not in range(min_length, max_length + 1): @@ -604,12 +606,6 @@ def _validate_admin_password(password, is_linux): # pylint: disable=line-too-long if count < 3: raise CLIError('Password must have the 3 of the following: 1 lower case character, 1 upper case character, 1 number and 1 special character') - disallowed_passwords = [ - "abc@123", "P@$$w0rd", "P@ssw0rd", "P@ssword123", "Pa$$word", - "pass@word1", "Password!", "Password1", "Password22", "iloveyou!" - ] - if password.lower() in disallowed_passwords: - raise CLIError('The specified password is not allowed') def validate_ssh_key(namespace): diff --git a/src/command_modules/azure-cli-vm/tests/test_vm_actions.py b/src/command_modules/azure-cli-vm/tests/test_vm_actions.py index f385bbc9191..8cc6ab7478c 100644 --- a/src/command_modules/azure-cli-vm/tests/test_vm_actions.py +++ b/src/command_modules/azure-cli-vm/tests/test_vm_actions.py @@ -72,52 +72,55 @@ def test_validate_admin_username_linux(self): # pylint: disable=line-too-long err_invalid_char = r'admin user name cannot contain upper case character A-Z, special characters \/"[]:|<>+=;,?*@#()! or start with $ or -' - self._verify_username_with_ex('david', True, 'The specified admin user name is not allowed, as it uses reserved words. Try again with a different value') - self._verify_username_with_ex('!@#', True, err_invalid_char) - self._verify_username_with_ex('dav[', True, err_invalid_char) - self._verify_username_with_ex('Adavid', True, err_invalid_char) - self._verify_username_with_ex('-ddavid', True, err_invalid_char) - - _validate_admin_username('d-avid1', True) - _validate_admin_username('david1', True) - _validate_admin_username('david1.', True) + self._verify_username_with_ex('!@#', 'linux', err_invalid_char) + self._verify_username_with_ex('dav[', 'linux', err_invalid_char) + self._verify_username_with_ex('Adavid', 'linux', err_invalid_char) + self._verify_username_with_ex('-ddavid', 'linux', err_invalid_char) + self._verify_username_with_ex('', 'linux', 'admin user name can not be empty') + self._verify_username_with_ex('david', 'linux', + "This user name 'david' meets the general requirements, but is specifically disallowed for this image. Please try a different value.") + + _validate_admin_username('d-avid1', 'linux') + _validate_admin_username('david1', 'linux') + _validate_admin_username('david1.', 'linux') def test_validate_admin_username_windows(self): # pylint: disable=line-too-long err_invalid_char = r'admin user name cannot contain special characters \/"[]:|<>+=;,?*@# or ends with .' - self._verify_username_with_ex('david', False, 'The specified admin user name is not allowed, as it uses reserved words. Try again with a different value') - self._verify_username_with_ex('!@#', False, err_invalid_char) - self._verify_username_with_ex('dav[', False, err_invalid_char) - self._verify_username_with_ex('dddivid.', False, err_invalid_char) + self._verify_username_with_ex('!@#', 'windows', err_invalid_char) + self._verify_username_with_ex('dav[', 'windows', err_invalid_char) + self._verify_username_with_ex('dddivid.', 'windows', err_invalid_char) + self._verify_username_with_ex('john', 'windows', + "This user name 'john' meets the general requirements, but is specifically disallowed for this image. Please try a different value.") - _validate_admin_username('ADAVID', False) - _validate_admin_username('d-avid1', False) - _validate_admin_username('david1', False) + _validate_admin_username('ADAVID', 'windows') + _validate_admin_username('d-avid1', 'windows') + _validate_admin_username('david1', 'windows') def test_validate_admin_password_linux(self): # pylint: disable=line-too-long err_length = 'The pssword length must be between 12 and 72' err_variety = 'Password must have the 3 of the following: 1 lower case character, 1 upper case character, 1 number and 1 special character' - self._verify_password_with_ex('te', True, err_length) - self._verify_password_with_ex('P12' + '3' * 70, True, err_length) - self._verify_password_with_ex('te12312312321', True, err_variety) + self._verify_password_with_ex('te', 'linux', err_length) + self._verify_password_with_ex('P12' + '3' * 70, 'linux', err_length) + self._verify_password_with_ex('te12312312321', 'linux', err_variety) - _validate_admin_password('Password22345', True) - _validate_admin_password('Password12!@#', True) + _validate_admin_password('Password22345', 'linux') + _validate_admin_password('Password12!@#', 'linux') def test_validate_admin_password_windows(self): # pylint: disable=line-too-long err_length = 'The pssword length must be between 12 and 123' err_variety = 'Password must have the 3 of the following: 1 lower case character, 1 upper case character, 1 number and 1 special character' - self._verify_password_with_ex('P1', False, err_length) - self._verify_password_with_ex('te14' + '3' * 120, False, err_length) - self._verify_password_with_ex('te12345678997', False, err_variety) + self._verify_password_with_ex('P1', 'windows', err_length) + self._verify_password_with_ex('te14' + '3' * 120, 'windows', err_length) + self._verify_password_with_ex('te12345678997', 'windows', err_variety) - _validate_admin_password('Password22!!!', False) - _validate_admin_password('Pas' + '1' * 70, False) + _validate_admin_password('Password22!!!', 'windows') + _validate_admin_password('Pas' + '1' * 70, 'windows') def _verify_username_with_ex(self, admin_username, is_linux, expected_err): with self.assertRaises(CLIError) as context: