def test_read_config(self, label, write_config_first=True, raises=None): credentials = utils.load_test_data('example.jwt.json') if write_config_first: self.client.gcp.auth.configure( credentials=credentials, mount_point=self.TEST_MOUNT_POINT, ) if raises is not None: with self.assertRaises(raises): self.client.gcp.auth.read_config( mount_point=self.TEST_MOUNT_POINT, ) else: read_config_response = self.client.gcp.auth.read_config( mount_point=self.TEST_MOUNT_POINT, ) logging.debug('read_config_response: %s' % read_config_response) creds_dict = json.loads(credentials) expected_config = { 'project_id': creds_dict['project_id'], 'client_email': creds_dict['client_email'], 'private_key_id': creds_dict['private_key_id'], } for k, v in expected_config.items(): self.assertEqual( first=v, second=read_config_response[k], )
def test_login(self, label, test_params, raises, requests_mocker): role_name = 'hvac' credentials = utils.load_test_data('example.jwt.json') test_policies = [ "default", "dev", "prod", ] expected_status_code = 200 mock_url = 'http://localhost:8200/v1/auth/{mount_point}/login'.format( mount_point=self.TEST_MOUNT_POINT, ) mock_response = { "auth": { "client_token": "f33f8c72-924e-11f8-cb43-ac59d697597c", "accessor": "0e9e354a-520f-df04-6867-ee81cae3d42d", "policies": test_policies, "lease_duration": 2764800, "renewable": True, }, } requests_mocker.register_uri( method='POST', url=mock_url, status_code=expected_status_code, json=mock_response, ) gcp = Gcp(adapter=Request()) if raises is not None: with self.assertRaises(raises): gcp.login(role=role_name, jwt=credentials, mount_point=self.TEST_MOUNT_POINT, **test_params) else: login_response = gcp.login(role=role_name, jwt=credentials, mount_point=self.TEST_MOUNT_POINT, **test_params) logging.debug('login_response: %s' % login_response) self.assertEqual( first=login_response['auth']['policies'], second=test_policies, )
class TestLdap(utils.HvacIntegrationTestCase, TestCase): TEST_LDAP_PATH = 'test-ldap' ldap_server = None mock_server_port = None mock_ldap_url = None @classmethod def setUpClass(cls): super(TestLdap, cls).setUpClass() logging.getLogger('ldap_test').setLevel(logging.ERROR) cls.mock_server_port = utils.get_free_port() cls.mock_ldap_url = 'ldap://localhost:{port}'.format( port=cls.mock_server_port) cls.ldap_server = LdapServer({ 'port': cls.mock_server_port, 'bind_dn': LDAP_BIND_DN, 'password': LDAP_BIND_PASSWORD, 'base': { 'objectclass': ['domain'], 'dn': LDAP_BASE_DN, 'attributes': { 'dc': LDAP_BASE_DC } }, 'entries': LDAP_ENTRIES, }) cls.ldap_server.start() @classmethod def tearDownClass(cls): super(TestLdap, cls).tearDownClass() cls.ldap_server.stop() def setUp(self): super(TestLdap, self).setUp() if 'ldap/' not in self.client.list_auth_backends(): self.client.sys.enable_auth_method(method_type='ldap', path=self.TEST_LDAP_PATH) def tearDown(self): super(TestLdap, self).tearDown() self.client.disable_auth_backend(mount_point=self.TEST_LDAP_PATH, ) @parameterized.expand([ ('update url', dict(url=LDAP_URL)), ('update binddn', dict(url=LDAP_URL, bind_dn='cn=vault,ou=Users,dc=hvac,dc=network')), ('update upn_domain', dict(url=LDAP_URL, upn_domain='hvac.network')), ('update certificate', dict(url=LDAP_URL, certificate=utils.load_test_data('server-cert.pem'))), ('incorrect tls version', dict(url=LDAP_URL, tls_min_version='cats'), exceptions.InvalidRequest, "invalid 'tls_min_version'"), ]) def test_configure(self, test_label, parameters, raises=None, exception_message=''): parameters.update({ 'user_dn': LDAP_USERS_DN, 'group_dn': LDAP_GROUPS_DN, 'mount_point': self.TEST_LDAP_PATH, }) if raises: with self.assertRaises(raises) as cm: self.client.auth.ldap.configure(**parameters) self.assertIn( member=exception_message, container=str(cm.exception), ) else: expected_status_code = 204 configure_response = self.client.auth.ldap.configure(**parameters) self.assertEqual(first=expected_status_code, second=configure_response.status_code) read_config_response = self.client.auth.ldap.read_configuration( mount_point=self.TEST_LDAP_PATH, ) for parameter, argument in parameters.items(): if parameter == 'mount_point': continue self.assertIn( member=argument, container=read_config_response['data'].values(), ) def test_read_configuration(self): response = self.client.auth.ldap.read_configuration( mount_point=self.TEST_LDAP_PATH, ) self.assertIn( member='data', container=response, ) @parameterized.expand([ ('no policies', 'cats'), ('policies as list', 'cats', ['purr-policy']), ('policies as invalid type', 'cats', 'purr-policy', exceptions.ParamValidationError, '"policies" argument must be an instance of list'), ]) def test_create_or_update_group(self, test_label, name, policies=None, raises=None, exception_message=''): expected_status_code = 204 if raises: with self.assertRaises(raises) as cm: create_response = self.client.auth.ldap.create_or_update_group( name=name, policies=policies, mount_point=self.TEST_LDAP_PATH, ) if exception_message is not None: self.assertIn( member=exception_message, container=str(cm.exception), ) else: create_response = self.client.auth.ldap.create_or_update_group( name=name, policies=policies, mount_point=self.TEST_LDAP_PATH, ) self.assertEqual(first=expected_status_code, second=create_response.status_code) @parameterized.expand([ ('read configured groups', 'cats'), ('non-existent groups', 'cats', False, exceptions.InvalidPath), ]) def test_list_groups(self, test_label, name, configure_first=True, raises=None, exception_message=None): if configure_first: self.client.auth.ldap.create_or_update_group( name=name, mount_point=self.TEST_LDAP_PATH, ) if raises: with self.assertRaises(raises) as cm: self.client.auth.ldap.list_groups( mount_point=self.TEST_LDAP_PATH, ) if exception_message is not None: self.assertIn( member=exception_message, container=str(cm.exception), ) else: list_groups_response = self.client.auth.ldap.list_groups( mount_point=self.TEST_LDAP_PATH, ) # raise Exception(list_groups_response) self.assertDictEqual( d1=dict(keys=[name]), d2=list_groups_response['data'], ) @parameterized.expand([ ('read configured group', 'cats'), ('non-existent group', 'cats', False, exceptions.InvalidPath), ]) def test_read_group(self, test_label, name, configure_first=True, raises=None, exception_message=None): if configure_first: self.client.auth.ldap.create_or_update_group( name=name, mount_point=self.TEST_LDAP_PATH, ) if raises: with self.assertRaises(raises) as cm: self.client.auth.ldap.read_group( name=name, mount_point=self.TEST_LDAP_PATH, ) if exception_message is not None: self.assertIn( member=exception_message, container=str(cm.exception), ) else: read_group_response = self.client.auth.ldap.read_group( name=name, mount_point=self.TEST_LDAP_PATH, ) self.assertIn( member='policies', container=read_group_response['data'], ) @parameterized.expand([ ('no policies or groups', 'cats'), ('policies as list', 'cats', ['purr-policy']), ('policies as invalid type', 'cats', 'purr-policy', None, exceptions.ParamValidationError, '"policies" argument must be an instance of list'), ('no groups', 'cats', ['purr-policy']), ('groups as list', 'cats', None, ['meow-group']), ('groups as invalid type', 'cats', None, 'meow-group', exceptions.ParamValidationError, '"groups" argument must be an instance of list'), ]) def test_create_or_update_user(self, test_label, username, policies=None, groups=None, raises=None, exception_message=''): expected_status_code = 204 if raises: with self.assertRaises(raises) as cm: self.client.auth.ldap.create_or_update_user( username=username, policies=policies, groups=groups, mount_point=self.TEST_LDAP_PATH, ) if exception_message is not None: self.assertIn( member=exception_message, container=str(cm.exception), ) else: create_response = self.client.auth.ldap.create_or_update_user( username=username, policies=policies, groups=groups, mount_point=self.TEST_LDAP_PATH, ) self.assertEqual(first=expected_status_code, second=create_response.status_code) @parameterized.expand([ ('read configured group', 'cats'), ('non-existent group', 'cats', False, exceptions.InvalidPath), ]) def test_delete_group(self, test_label, name, configure_first=True, raises=None, exception_message=None): if configure_first: self.client.auth.ldap.create_or_update_group( name=name, mount_point=self.TEST_LDAP_PATH, ) expected_status_code = 204 delete_group_response = self.client.auth.ldap.delete_group( name=name, mount_point=self.TEST_LDAP_PATH, ) self.assertEqual(first=expected_status_code, second=delete_group_response.status_code) @parameterized.expand([ ('read configured user', 'cats'), ('non-existent user', 'cats', False, exceptions.InvalidPath), ]) def test_list_users(self, test_label, username, configure_first=True, raises=None, exception_message=None): if configure_first: self.client.auth.ldap.create_or_update_user( username=username, mount_point=self.TEST_LDAP_PATH, ) if raises: with self.assertRaises(raises) as cm: self.client.auth.ldap.list_users( mount_point=self.TEST_LDAP_PATH, ) if exception_message is not None: self.assertIn( member=exception_message, container=str(cm.exception), ) else: list_users_response = self.client.auth.ldap.list_users( mount_point=self.TEST_LDAP_PATH, ) self.assertDictEqual( d1=dict(keys=[username]), d2=list_users_response['data'], ) @parameterized.expand([ ('read configured user', 'cats'), ('non-existent user', 'cats', False, exceptions.InvalidPath), ]) def test_read_user(self, test_label, username, configure_first=True, raises=None, exception_message=None): if configure_first: self.client.auth.ldap.create_or_update_user( username=username, mount_point=self.TEST_LDAP_PATH, ) if raises: with self.assertRaises(raises) as cm: self.client.auth.ldap.read_user( username=username, mount_point=self.TEST_LDAP_PATH, ) if exception_message is not None: self.assertIn( member=exception_message, container=str(cm.exception), ) else: read_user_response = self.client.auth.ldap.read_user( username=username, mount_point=self.TEST_LDAP_PATH, ) self.assertIn( member='policies', container=read_user_response['data'], ) @parameterized.expand([ ('read configured user', 'cats'), ('non-existent user', 'cats', False, exceptions.InvalidPath), ]) def test_delete_user(self, test_label, username, configure_first=True, raises=None, exception_message=None): if configure_first: self.client.auth.ldap.create_or_update_user( username=username, mount_point=self.TEST_LDAP_PATH, ) expected_status_code = 204 delete_user_response = self.client.auth.ldap.delete_user( username=username, mount_point=self.TEST_LDAP_PATH, ) self.assertEqual(first=expected_status_code, second=delete_user_response.status_code) @parameterized.expand([ param(label='working creds with policy'), param( label='invalid creds', username='******', password='******', attach_policy=False, raises=exceptions.InvalidRequest, ), # The following two test cases cover either side of the associated changelog entry for LDAP auth here: # https://github.com/hashicorp/vault/blob/master/CHANGELOG.md#0103-june-20th-2018 param( label='working creds no membership with Vault version >= 0.10.3', attach_policy=False, skip_due_to_vault_version=utils.skip_if_vault_version_lt('0.10.3'), ), param( label='working creds no membership with Vault version < 0.10.3', attach_policy=False, raises=exceptions.InvalidRequest, exception_message='user is not a member of any authorized group', skip_due_to_vault_version=utils.skip_if_vault_version_ge('0.10.3'), ), ]) def test_login(self, label, username=LDAP_USER_NAME, password=LDAP_USER_PASSWORD, attach_policy=True, raises=None, exception_message='', skip_due_to_vault_version=False): if skip_due_to_vault_version: self.skipTest( reason='test case does not apply to Vault version under test') test_policy_name = 'test-ldap-policy' self.client.auth.ldap.configure( url=self.mock_ldap_url, bind_dn=self.ldap_server.config['bind_dn'], bind_pass=self.ldap_server.config['password'], user_dn=LDAP_USERS_DN, user_attr='uid', group_dn=LDAP_GROUPS_DN, group_attr='cn', insecure_tls=True, mount_point=self.TEST_LDAP_PATH, ) if attach_policy: self.prep_policy(test_policy_name) self.client.auth.ldap.create_or_update_group( name=LDAP_GROUP_NAME, policies=[test_policy_name], mount_point=self.TEST_LDAP_PATH, ) if raises: with self.assertRaises(raises) as cm: self.client.auth.ldap.login( username=username, password=password, mount_point=self.TEST_LDAP_PATH, ) if exception_message is not None: self.assertIn( member=exception_message, container=str(cm.exception), ) else: login_response = self.client.auth.ldap.login( username=username, password=password, mount_point=self.TEST_LDAP_PATH, ) self.assertDictEqual( d1=dict(username=username), d2=login_response['auth']['metadata'], ) self.assertEqual( first=login_response['auth']['client_token'], second=self.client.token, ) if attach_policy: expected_policies = ['default', test_policy_name] else: expected_policies = ['default'] self.assertEqual(first=expected_policies, second=login_response['auth']['policies'])
class TestGcp(utils.HvacIntegrationTestCase, TestCase): TEST_MOUNT_POINT = 'gcp-test' def setUp(self): super(TestGcp, self).setUp() if '%s/' % self.TEST_MOUNT_POINT not in self.client.list_auth_backends( ): self.client.enable_auth_backend( backend_type='gcp', mount_point=self.TEST_MOUNT_POINT, ) def tearDown(self): super(TestGcp, self).tearDown() self.client.disable_auth_backend(mount_point=self.TEST_MOUNT_POINT, ) @parameterized.expand([ param('success', ), param( 'set valid credentials', credentials=utils.load_test_data('example.jwt.json'), ), param( 'set invalid credentials', credentials='some invalid JWT', raises=exceptions.InvalidRequest, exception_message='error reading google credentials from given JSON' ), ]) def test_configure(self, label, credentials='', raises=None, exception_message=''): if raises: with self.assertRaises(raises) as cm: self.client.gcp.auth.configure( credentials=credentials, mount_point=self.TEST_MOUNT_POINT, ) self.assertIn( member=exception_message, container=str(cm.exception), ) else: configure_response = self.client.gcp.auth.configure( credentials=credentials, mount_point=self.TEST_MOUNT_POINT, ) logging.debug('configure_response: %s' % configure_response) self.assertEqual( first=configure_response.status_code, second=204, ) @parameterized.expand([ param('success', ), param('no config written yet', write_config_first=False, raises=exceptions.InvalidPath) ]) def test_read_config(self, label, write_config_first=True, raises=None): credentials = utils.load_test_data('example.jwt.json') if write_config_first: self.client.gcp.auth.configure( credentials=credentials, mount_point=self.TEST_MOUNT_POINT, ) if raises is not None: with self.assertRaises(raises): self.client.gcp.auth.read_config( mount_point=self.TEST_MOUNT_POINT, ) else: read_config_response = self.client.gcp.auth.read_config( mount_point=self.TEST_MOUNT_POINT, ) logging.debug('read_config_response: %s' % read_config_response) creds_dict = json.loads(credentials) expected_config = { 'project_id': creds_dict['project_id'], 'client_email': creds_dict['client_email'], 'private_key_id': creds_dict['private_key_id'], } for k, v in expected_config.items(): self.assertEqual( first=v, second=read_config_response[k], ) @parameterized.expand([ # param( # 'success', # TODO: figure out why this is returning a 405 # ), param( 'no existing config', write_config_first=False, raises=exceptions.UnexpectedError, ), ]) def test_delete_config(self, label, write_config_first=True, raises=None): if write_config_first: self.client.gcp.auth.configure(mount_point=self.TEST_MOUNT_POINT, ) if raises is not None: with self.assertRaises(raises): self.client.gcp.auth.delete_config( mount_point=self.TEST_MOUNT_POINT, ) else: delete_config_response = self.client.gcp.auth.delete_config( mount_point=self.TEST_MOUNT_POINT, ) logging.debug('delete_config_response: %s' % delete_config_response) self.assertEqual( first=delete_config_response.status_code, second=204, ) @parameterized.expand([ param('success iam', role_type='iam', extra_params=dict(bound_service_accounts=['*'], )), param( 'iam no bound service account', role_type='iam', raises=exceptions.InvalidRequest, exception_message= 'IAM role type must have at least one service account', ), param( 'success gce', role_type='gce', ), param( 'invalid role type', role_type='hvac', raises=exceptions.ParamValidationError, exception_message='unsupported role_type argument provided', ), param( 'wrong policy arg type', role_type='iam', policies='cats', raises=exceptions.ParamValidationError, exception_message='unsupported policies argument provided', ) ]) def test_create_role(self, label, role_type, policies=None, extra_params=None, raises=None, exception_message=''): role_name = 'hvac' project_id = 'test-hvac-project-not-a-real-project' if extra_params is None: extra_params = {} if raises: with self.assertRaises(raises) as cm: self.client.gcp.auth.create_role( name=role_name, role_type=role_type, project_id=project_id, policies=policies, mount_point=self.TEST_MOUNT_POINT, **extra_params) self.assertIn( member=exception_message, container=str(cm.exception), ) else: create_role_response = self.client.gcp.auth.create_role( name=role_name, role_type=role_type, project_id=project_id, policies=policies, mount_point=self.TEST_MOUNT_POINT, **extra_params) logging.debug('create_role_response: %s' % create_role_response) if utils.skip_if_vault_version_lt('0.10.0'): expected_status_code = 204 else: expected_status_code = 200 # TODO => figure out why this isn't a 204? self.assertEqual( first=create_role_response.status_code, second=expected_status_code, ) @parameterized.expand([ param( 'success add', add=['test'], ), param( 'success remove', remove=['test'], ), param( 'fail upon no changes', raises=exceptions.InvalidRequest, exception_message= 'must provide at least one value to add or remove', ), # TODO: wrong role type (gce) ]) def test_edit_service_accounts_on_iam_role(self, label, add=None, remove=None, create_role_first=True, raises=None, exception_message=''): role_name = 'hvac' project_id = 'test-hvac-project-not-a-real-project' if create_role_first: self.client.gcp.auth.create_role( name=role_name, role_type='iam', project_id=project_id, bound_service_accounts=[ '*****@*****.**' ], mount_point=self.TEST_MOUNT_POINT, ) if raises: with self.assertRaises(raises) as cm: self.client.gcp.auth.edit_service_accounts_on_iam_role( name=role_name, add=add, remove=remove, mount_point=self.TEST_MOUNT_POINT, ) self.assertIn( member=exception_message, container=str(cm.exception), ) else: edit_sa_on_iam_response = self.client.gcp.auth.edit_service_accounts_on_iam_role( name=role_name, add=add, remove=remove, mount_point=self.TEST_MOUNT_POINT, ) logging.debug('create_role_response: %s' % edit_sa_on_iam_response) if utils.skip_if_vault_version_lt('0.10.0'): expected_status_code = 204 else: expected_status_code = 200 # TODO => figure out why this isn't a 204? self.assertEqual( first=edit_sa_on_iam_response.status_code, second=expected_status_code, ) @parameterized.expand([ param( 'success add', add=['test-key:test-value'], ), param( 'success remove', remove=['test-key:test-value'], ), param( 'fail upon no changes', raises=exceptions.InvalidRequest, exception_message= 'must provide at least one value to add or remove', ), # TODO: wrong role type (iam) ]) def test_edit_labels_on_gce_role(self, label, add=None, remove=None, create_role_first=True, raises=None, exception_message=''): role_name = 'hvac' project_id = 'test-hvac-project-not-a-real-project' if create_role_first: self.client.gcp.auth.create_role( name=role_name, role_type='gce', project_id=project_id, bound_service_accounts=[ '*****@*****.**' ], mount_point=self.TEST_MOUNT_POINT, ) if raises: with self.assertRaises(raises) as cm: self.client.gcp.auth.edit_labels_on_gce_role( name=role_name, add=add, remove=remove, mount_point=self.TEST_MOUNT_POINT, ) self.assertIn( member=exception_message, container=str(cm.exception), ) else: edit_labled_response = self.client.gcp.auth.edit_labels_on_gce_role( name=role_name, add=add, remove=remove, mount_point=self.TEST_MOUNT_POINT, ) logging.debug('create_role_response: %s' % edit_labled_response) if utils.skip_if_vault_version_lt('0.10.0'): expected_status_code = 204 else: expected_status_code = 200 # TODO => figure out why this isn't a 204? self.assertEqual( first=edit_labled_response.status_code, second=expected_status_code, ) @parameterized.expand([ param('success', ), param( 'nonexistent role', create_role_first=False, raises=exceptions.InvalidPath, ), ]) def test_read_role(self, label, create_role_first=True, raises=None, exception_message=''): role_name = 'hvac' project_id = 'test-hvac-project-not-a-real-project' if create_role_first: self.client.gcp.auth.create_role( name=role_name, role_type='gce', project_id=project_id, bound_service_accounts=[ '*****@*****.**' ], mount_point=self.TEST_MOUNT_POINT, ) if raises: with self.assertRaises(raises) as cm: self.client.gcp.auth.read_role( name=role_name, mount_point=self.TEST_MOUNT_POINT, ) self.assertIn( member=exception_message, container=str(cm.exception), ) else: read_role_response = self.client.gcp.auth.read_role( name=role_name, mount_point=self.TEST_MOUNT_POINT, ) logging.debug('create_role_response: %s' % read_role_response) self.assertEqual( first=project_id, second=read_role_response['project_id'], ) @parameterized.expand([ param('success one role', ), param( 'success multiple roles', num_roles_to_create=7, ), param( 'no roles', num_roles_to_create=0, raises=exceptions.InvalidPath, ), ]) def test_list_roles(self, label, num_roles_to_create=1, raises=None): project_id = 'test-hvac-project-not-a-real-project' roles_to_create = ['hvac%s' % n for n in range(0, num_roles_to_create)] logging.debug('roles_to_create: %s' % roles_to_create) for role_to_create in roles_to_create: create_role_response = self.client.gcp.auth.create_role( name=role_to_create, role_type='gce', project_id=project_id, bound_service_accounts=[ '*****@*****.**' ], mount_point=self.TEST_MOUNT_POINT, ) logging.debug('create_role_response: %s' % create_role_response) if raises is not None: with self.assertRaises(raises): self.client.gcp.list_roles(mount_point=self.TEST_MOUNT_POINT, ) else: list_roles_response = self.client.gcp.auth.list_roles( mount_point=self.TEST_MOUNT_POINT, ) logging.debug('list_roles_response: %s' % list_roles_response) self.assertEqual( first=list_roles_response['keys'], second=roles_to_create, ) @parameterized.expand([ param('success', ), param( 'nonexistent role name', configure_role_first=False, ), ]) def test_delete_role(self, label, configure_role_first=True, raises=None): role_name = 'hvac' project_id = 'test-hvac-project-not-a-real-project' if configure_role_first: create_role_response = self.client.gcp.auth.create_role( name=role_name, role_type='gce', project_id=project_id, bound_service_accounts=[ '*****@*****.**' ], mount_point=self.TEST_MOUNT_POINT, ) logging.debug('create_role_response: %s' % create_role_response) if raises is not None: with self.assertRaises(raises): self.client.gcp.delete_role( role=role_name, mount_point=self.TEST_MOUNT_POINT, ) else: delete_role_response = self.client.gcp.delete_role( role=role_name, mount_point=self.TEST_MOUNT_POINT, ) logging.debug('delete_role_response: %s' % delete_role_response) self.assertEqual( first=delete_role_response.status_code, second=204, )