diff --git a/cloudbaseinit/plugins/common/setuserpassword.py b/cloudbaseinit/plugins/common/setuserpassword.py index 9e8dba79..4490dd0c 100644 --- a/cloudbaseinit/plugins/common/setuserpassword.py +++ b/cloudbaseinit/plugins/common/setuserpassword.py @@ -49,7 +49,7 @@ class SetUserPasswordPlugin(base.BasePlugin): if public_keys: return list(public_keys)[0] - def _get_password(self, service, osutils): + def _get_password(self, service, osutils, shared_data): if CONF.inject_user_password: password = service.get_admin_password() else: @@ -59,13 +59,12 @@ class SetUserPasswordPlugin(base.BasePlugin): LOG.warn('Using admin_pass metadata user password. Consider ' 'changing it as soon as possible') else: - # TODO(alexpilotti): setting a random password can be skipped - # if it's already present in the shared_data, as it has already - # been set by the CreateUserPlugin - LOG.debug('Generating a random user password') - # Generate a random password - # Limit to 14 chars for compatibility with NT - password = osutils.generate_random_password(14) + password = shared_data.get(constants.SHARED_DATA_PASSWORD) + if not password: + LOG.debug('Generating a random user password') + # Generate a random password + # Limit to 14 chars for compatibility with NT + password = osutils.generate_random_password(14) return password @@ -84,8 +83,8 @@ class SetUserPasswordPlugin(base.BasePlugin): LOG.info('No SSH public key available for password encryption') return True - def _set_password(self, service, osutils, user_name): - password = self._get_password(service, osutils) + def _set_password(self, service, osutils, user_name, shared_data): + password = self._get_password(service, osutils, shared_data) LOG.info('Setting the user\'s password') osutils.set_user_password(user_name, password) return password @@ -98,7 +97,8 @@ class SetUserPasswordPlugin(base.BasePlugin): osutils = osutils_factory.get_os_utils() if osutils.user_exists(user_name): - password = self._set_password(service, osutils, user_name) + password = self._set_password(service, osutils, + user_name, shared_data) LOG.info('Password succesfully updated for user %s' % user_name) # TODO(alexpilotti): encrypt with DPAPI shared_data[constants.SHARED_DATA_PASSWORD] = password diff --git a/cloudbaseinit/tests/plugins/common/test_setuserpassword.py b/cloudbaseinit/tests/plugins/common/test_setuserpassword.py index ecaa8832..21783dad 100644 --- a/cloudbaseinit/tests/plugins/common/test_setuserpassword.py +++ b/cloudbaseinit/tests/plugins/common/test_setuserpassword.py @@ -71,26 +71,51 @@ class SetUserPasswordPluginTests(unittest.TestCase): def test_get_ssh_plublic_key_no_pub_keys(self): self._test_get_ssh_public_key(data_exists=False) - def _test_get_password(self, inject_password): + def _test_get_password(self, inject_password, generate_password): + shared_data = {} + reuse_password = not generate_password and not inject_password + expected_password = 'Passw0rd' + if reuse_password: + # The password should be the one created by + # CreateUser plugin. + shared_data[constants.SHARED_DATA_PASSWORD] = ( + mock.sentinel.create_user_password) + mock_service = mock.MagicMock() mock_osutils = mock.MagicMock() - mock_service.get_admin_password.return_value = 'Passw0rd' - mock_osutils.generate_random_password.return_value = 'Passw0rd' - response = self._setpassword_plugin._get_password(mock_service, - mock_osutils) + mock_service.get_admin_password.return_value = expected_password + mock_osutils.generate_random_password.return_value = expected_password + + with testutils.ConfPatcher('inject_user_password', inject_password): + response = self._setpassword_plugin._get_password(mock_service, + mock_osutils, + shared_data) if inject_password: mock_service.get_admin_password.assert_called_with() + elif reuse_password: + self.assertFalse(mock_service.get_admin_password.called) + self.assertFalse(mock_osutils.generate_random_password.called) + expected_password = mock.sentinel.create_user_password else: mock_osutils.generate_random_password.assert_called_once_with(14) - self.assertEqual('Passw0rd', response) + + self.assertEqual(expected_password, response) def test_get_password_inject_true(self): - with testutils.ConfPatcher('inject_user_password', True): - self._test_get_password(inject_password=True) + self._test_get_password(generate_password=False, + inject_password=True) def test_get_password_inject_false(self): - with testutils.ConfPatcher('inject_user_password', False): - self._test_get_password(inject_password=False) + self._test_get_password(generate_password=False, + inject_password=False) + + def test_get_password_get_from_create_user_plugin(self): + self._test_get_password(inject_password=False, + generate_password=False) + + def test_get_password_generate(self): + self._test_get_password(inject_password=False, + generate_password=True) @mock.patch('cloudbaseinit.plugins.common.setuserpassword.' 'SetUserPasswordPlugin._get_ssh_public_key') @@ -130,12 +155,18 @@ class SetUserPasswordPluginTests(unittest.TestCase): mock_service = mock.MagicMock() mock_osutils = mock.MagicMock() mock_get_password.return_value = 'fake password' - response = self._setpassword_plugin._set_password(mock_service, - mock_osutils, - 'fake user') - mock_get_password.assert_called_once_with(mock_service, mock_osutils) - mock_osutils.set_user_password.assert_called_once_with('fake user', - 'fake password') + response = self._setpassword_plugin._set_password( + mock_service, + mock_osutils, + 'fake user', + mock.sentinel.shared_data) + mock_get_password.assert_called_once_with( + mock_service, + mock_osutils, + mock.sentinel.shared_data) + mock_osutils.set_user_password.assert_called_once_with( + 'fake user', + 'fake password') self.assertEqual(response, 'fake password') @mock.patch('cloudbaseinit.plugins.common.setuserpassword.' @@ -165,7 +196,8 @@ class SetUserPasswordPluginTests(unittest.TestCase): constants.SHARED_DATA_USERNAME, CONF.username) mock_osutils.user_exists.assert_called_once_with('fake username') mock_set_password.assert_called_once_with(mock_service, mock_osutils, - 'fake username') + 'fake username', + fake_shared_data) expected_logging = [ "Password succesfully updated for user fake username", @@ -177,6 +209,7 @@ class SetUserPasswordPluginTests(unittest.TestCase): expected_logging.append("Cannot set the password in the metadata " "as it is not supported by this service") self.assertFalse(mock_set_metadata_password.called) + self.assertEqual((1, False), response) self.assertEqual(expected_logging, snatcher.output)