test_openstack_credentials.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. """Which OpenStack credentials a provider authenticates with.
  2. The provider reads credentials from its config dict and, failing that, from
  3. the ``OS_*`` environment. These tests pin the precedence between the two:
  4. credentials configured explicitly win over whatever happens to be in the
  5. process environment, so a provider built for one identity never signs in as
  6. another. Nothing here touches a network: the Keystone version probe is
  7. patched and keystoneauth plugins are plain objects until used.
  8. """
  9. import os
  10. import unittest
  11. from unittest import mock
  12. from keystoneauth1.identity import v3
  13. from cloudbridge.providers.openstack.provider import OpenStackCloudProvider
  14. AUTH_URL = 'https://keystone.example.org:5000/v3'
  15. PASSWORD_ENV = {
  16. 'OS_USERNAME': 'ambient-user',
  17. 'OS_PASSWORD': 'ambient-password',
  18. 'OS_PROJECT_NAME': 'ambient-project',
  19. }
  20. APP_CRED_ENV = {
  21. 'OS_APPLICATION_CREDENTIAL_ID': 'ambient-app-cred-id',
  22. 'OS_APPLICATION_CREDENTIAL_SECRET': 'ambient-app-cred-secret',
  23. }
  24. ALL_CREDENTIAL_VARS = tuple(PASSWORD_ENV) + tuple(APP_CRED_ENV)
  25. def _environment(**values):
  26. """The process environment with only the given OS_* credentials set."""
  27. env = {k: v for k, v in os.environ.items() if k not in ALL_CREDENTIAL_VARS}
  28. env.update(values)
  29. return mock.patch.dict(os.environ, env, clear=True)
  30. def _provider(**config):
  31. # A configured zone keeps the compute service from asking Nova for one
  32. # while the provider is being built.
  33. return OpenStackCloudProvider(
  34. dict(config, os_auth_url=AUTH_URL, os_zone_name='nova'))
  35. def _keystone_auth(provider):
  36. with mock.patch.object(OpenStackCloudProvider, '_keystone_version',
  37. new_callable=mock.PropertyMock, return_value=3):
  38. # pylint:disable=protected-access
  39. return provider._keystone_session.auth
  40. class OpenStackCredentialPrecedenceTestCase(unittest.TestCase):
  41. def test_configured_application_credential_ignores_ambient_password(self):
  42. # The process may carry the server's own OS_USERNAME/OS_PASSWORD; a
  43. # provider configured with an application credential must use that
  44. # credential, not the ambient identity.
  45. with _environment(**PASSWORD_ENV):
  46. provider = _provider(
  47. os_application_credential_id='configured-id',
  48. os_application_credential_secret='configured-secret')
  49. self.assertIsNone(provider.username)
  50. self.assertIsNone(provider.password)
  51. auth = _keystone_auth(provider)
  52. self.assertIsInstance(auth, v3.ApplicationCredential)
  53. self.assertEqual(auth.auth_methods[0].application_credential_id,
  54. 'configured-id')
  55. def test_configured_password_ignores_ambient_application_credential(self):
  56. with _environment(**APP_CRED_ENV):
  57. provider = _provider(os_username='configured-user',
  58. os_password='configured-password',
  59. os_project_name='configured-project')
  60. self.assertIsNone(provider.app_cred_id)
  61. self.assertIsNone(provider.app_cred_secret)
  62. auth = _keystone_auth(provider)
  63. self.assertIsInstance(auth, v3.Password)
  64. self.assertEqual(auth.auth_methods[0].username, 'configured-user')
  65. def test_environment_is_used_when_nothing_is_configured(self):
  66. with _environment(**PASSWORD_ENV):
  67. provider = _provider()
  68. self.assertEqual(provider.username, 'ambient-user')
  69. self.assertEqual(provider.password, 'ambient-password')
  70. auth = _keystone_auth(provider)
  71. self.assertIsInstance(auth, v3.Password)
  72. def test_environment_completes_a_partially_configured_credential(self):
  73. # Keeping the secret out of the config file and in the environment is
  74. # legitimate: the environment fills in the missing half of the set
  75. # that is configured, and only that set.
  76. with _environment(**PASSWORD_ENV, **APP_CRED_ENV):
  77. provider = _provider(os_username='configured-user')
  78. self.assertEqual(provider.username, 'configured-user')
  79. self.assertEqual(provider.password, 'ambient-password')
  80. self.assertIsNone(provider.app_cred_id)
  81. self.assertIsNone(provider.app_cred_secret)
  82. with _environment(**PASSWORD_ENV, **APP_CRED_ENV):
  83. provider = _provider(os_application_credential_id='configured-id')
  84. self.assertEqual(provider.app_cred_id, 'configured-id')
  85. self.assertEqual(provider.app_cred_secret,
  86. 'ambient-app-cred-secret')
  87. self.assertIsNone(provider.username)
  88. self.assertIsNone(provider.password)