示例#1
0
    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],
                )
示例#2
0
文件: test_gcp.py 项目: yijxiang/hvac
 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,
         )
示例#3
0
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'])
示例#4
0
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,
            )