From 087f89dd16c2fbafaa0aab8e5e2cff09489d40ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Douglas=20Mendiz=C3=A1bal?= Date: Wed, 7 Apr 2021 16:26:45 -0500 Subject: [PATCH] Add secure-rbac test for Secrets across projects This patch adds rbac tests to the Secrets resource to test access across different projects. This patch also changes the Reader, Member, and Admin test suite inheritance to remove code duplication. Change-Id: Icf5a52925244dfe7d98ba9cfba549fce67be44db --- barbican_tempest_plugin/tests/rbac/v1/base.py | 25 +- .../tests/rbac/v1/test_secrets.py | 272 +++++++++++------- 2 files changed, 186 insertions(+), 111 deletions(-) diff --git a/barbican_tempest_plugin/tests/rbac/v1/base.py b/barbican_tempest_plugin/tests/rbac/v1/base.py index bd70579..75541aa 100644 --- a/barbican_tempest_plugin/tests/rbac/v1/base.py +++ b/barbican_tempest_plugin/tests/rbac/v1/base.py @@ -47,7 +47,10 @@ class BarbicanV1RbacBase(test.BaseTestCase): _created_users = None created_objects = {} - credentials = ['system_admin'] + credentials = [ + 'system_admin', + 'project_alt_member' + ] # TODO(dmendiza): remove this and use the clients instead @classmethod @@ -76,6 +79,8 @@ class BarbicanV1RbacBase(test.BaseTestCase): cls._setup_new_user_client(project_id, 'member')) setattr(cls, 'os_project_reader', cls._setup_new_user_client(project_id, 'reader')) + setattr(cls, 'os_project_other_member', + cls._setup_new_user_client(project_id, 'member')) @classmethod def _setup_new_user_client(cls, project_id, role): @@ -122,7 +127,7 @@ class BarbicanV1RbacBase(test.BaseTestCase): def setup_clients(cls): super().setup_clients() - # setup clients for primary persona + # set up member clients os = cls.os_project_member cls.secret_client = os.secret_v1.SecretClient() cls.secret_metadata_client = os.secret_v1.SecretMetadataClient( @@ -154,6 +159,7 @@ class BarbicanV1RbacBase(test.BaseTestCase): cls.admin_secret_metadata_client = adm.secret_v1.SecretMetadataClient( service='key-manager' ) + cls.other_client = cls.os_project_alt_member.secret_v1.SecretClient() @classmethod def resource_setup(cls): @@ -176,7 +182,9 @@ class BarbicanV1RbacBase(test.BaseTestCase): for secret_uuid in list(cls.created_objects['secret']): cls.admin_secret_client.delete_secret(secret_uuid) cls.created_objects['secret'].remove(secret_uuid) - for client in [cls.secret_client, cls.admin_secret_client]: + for client in [cls.secret_client, + cls.admin_secret_client, + cls.other_client]: client.cleanup() finally: super(BarbicanV1RbacBase, cls).resource_cleanup() @@ -234,3 +242,14 @@ class BarbicanV1RbacBase(test.BaseTestCase): payload_content_encoding="base64", name=secret_name ) + + def create_other_project_secret(self, secret_name, payload=None): + kwargs = { + 'name': secret_name, + 'secret_type': 'passphrase', + } + if payload is not None: + kwargs['payload'] = payload + kwargs['payload_content_type'] = 'text/plain' + resp = self.other_client.create_secret(**kwargs) + return self.other_client.ref_to_uuid(resp['secret_ref']) diff --git a/barbican_tempest_plugin/tests/rbac/v1/test_secrets.py b/barbican_tempest_plugin/tests/rbac/v1/test_secrets.py index 9ceeec9..7df6df2 100644 --- a/barbican_tempest_plugin/tests/rbac/v1/test_secrets.py +++ b/barbican_tempest_plugin/tests/rbac/v1/test_secrets.py @@ -23,7 +23,7 @@ from barbican_tempest_plugin.tests.rbac.v1 import base as rbac_base CONF = config.CONF -class BarbicanV1RbacSecrets(metaclass=abc.ABCMeta): +class BarbicanV1RbacSecrets: @abc.abstractmethod def test_create_secret(self): @@ -86,91 +86,50 @@ class BarbicanV1RbacSecrets(metaclass=abc.ABCMeta): """ raise NotImplementedError + @abc.abstractmethod + def test_get_other_project_secret(self): + """Test get_secrets policy -class ProjectMemberTests(rbac_base.BarbicanV1RbacBase, BarbicanV1RbacSecrets): + Testing: GET /v1/secrets/{secret_id} + This test must check: + * whether the persona can get secret metadata for a secret that + belongs to a different project + """ + raise NotImplementedError - @classmethod - def setup_clients(cls): - super().setup_clients() - cls.client = cls.os_project_member.secret_v1.SecretClient() + @abc.abstractmethod + def test_get_other_project_secret_payload(self): + """Test get_secrets policy - def test_create_secret(self): - """Test add_secret policy.""" - self.client.create_secret(name='test_create_secret') + Testing: GET /v1/secrets/{secret_id}/payload + This test must check: + * whether the persona can get secret payload for a secret that + belongs to a different project + """ + raise NotImplementedError - key = rbac_base.create_aes_key() - expire_time = (datetime.utcnow() + timedelta(days=5)) - self.client.create_secret( - name='test_create_secret2', - expiration=expire_time.isoformat(), algorithm="aes", - bit_length=256, mode="cbc", payload=key, - payload_content_type="application/octet-stream", - payload_content_encoding="base64" - ) + @abc.abstractmethod + def test_put_other_project_secret_payload(self): + """Test put_secret policy. - def test_list_secrets(self): - """Test get_secrets policy.""" - # create two secrets - self.create_empty_secret_admin('test_list_secrets') - self.create_empty_secret_admin('test_list_secrets_2') + Testing: PUT /v1/secrets/{secret_id} + This test must check: + * whether the persona can PUT the secret payload in a 2-step + create when the first step is done by a member of a different + project. + """ + raise NotImplementedError - # list secrets with name secret_1 - resp = self.client.list_secrets(name='test_list_secrets') - secrets = resp['secrets'] - self.assertEqual('test_list_secrets', secrets[0]['name']) + @abc.abstractmethod + def test_delete_other_project_secret(self): + """Test delete_secret policy. - # list secrets with name secret_2 - resp = self.client.list_secrets(name='test_list_secrets_2') - secrets = resp['secrets'] - self.assertEqual('test_list_secrets_2', secrets[0]['name']) - - # list all secrets - resp = self.client.list_secrets() - secrets = resp['secrets'] - self.assertGreaterEqual(len(secrets), 2) - - def test_delete_secret(self): - """Test delete_secrets policy.""" - sec = self.create_empty_secret_admin('test_delete_secret_1') - uuid = self.client.ref_to_uuid(sec['secret_ref']) - self.client.delete_secret(uuid) - - def test_get_secret(self): - """Test get_secret policy.""" - sec = self.create_empty_secret_admin('test_get_secret') - uuid = self.client.ref_to_uuid(sec['secret_ref']) - resp = self.client.get_secret_metadata(uuid) - self.assertEqual(uuid, self.client.ref_to_uuid(resp['secret_ref'])) - - def test_get_secret_payload(self): - """Test get_secret payload policy.""" - key, sec = self.create_aes_secret_admin('test_get_secret_payload') - uuid = self.client.ref_to_uuid(sec['secret_ref']) - - # Retrieve the payload - payload = self.client.get_secret_payload(uuid) - self.assertEqual(key, base64.b64encode(payload)) - - def test_put_secret_payload(self): - """Test put_secret policy.""" - sec = self.create_empty_secret_admin('test_put_secret_payload') - uuid = self.client.ref_to_uuid(sec['secret_ref']) - - key = rbac_base.create_aes_key() - - # Associate the payload with the created secret - self.client.put_secret_payload(uuid, key) - - # Retrieve the payload - payload = self.client.get_secret_payload(uuid) - self.assertEqual(key, base64.b64encode(payload)) - - -class ProjectAdminTests(ProjectMemberTests): - @classmethod - def setup_clients(cls): - super().setup_clients() - cls.client = cls.os_project_admin.secret_v1.SecretClient() + Testing: DELETE /v1/secrets/{secret_id} + This test must check: + * whether the persona can delete a secret that belongs to a + different project + """ + raise NotImplementedError class ProjectReaderTests(rbac_base.BarbicanV1RbacBase, BarbicanV1RbacSecrets): @@ -265,57 +224,126 @@ class ProjectReaderTests(rbac_base.BarbicanV1RbacBase, BarbicanV1RbacSecrets): secret_id=uuid, payload=key ) + def test_get_other_project_secret(self): + other_secret_id = self.create_other_project_secret( + 'get_other_secret', + payload='¡Muy secreto!') + self.assertRaises( + exceptions.Forbidden, + self.client.get_secret_metadata, + other_secret_id) -class SystemAdminTests(rbac_base.BarbicanV1RbacBase, BarbicanV1RbacSecrets): + def test_get_other_project_secret_payload(self): + other_secret_id = self.create_other_project_secret( + 'get_other_payload', + payload='¡Más secreto!') + self.assertRaises( + exceptions.Forbidden, + self.client.get_secret_payload, + other_secret_id) + + def test_put_other_project_secret_payload(self): + other_secret_id = self.create_other_project_secret('put_other_payload') + self.assertRaises( + exceptions.Forbidden, + self.client.put_secret_payload, + other_secret_id, + 'Shhhh... secret!') + + def test_delete_other_project_secret(self): + other_secret_id = self.create_other_project_secret( + 'get_other_payload', + payload='loremipsumloremipsum') + self.assertRaises( + exceptions.Forbidden, + self.client.delete_secret, + other_secret_id) + + +class ProjectMemberTests(ProjectReaderTests): @classmethod def setup_clients(cls): super().setup_clients() - cls.client = cls.secret_client + cls.client = cls.os_project_member.secret_v1.SecretClient() def test_create_secret(self): - pass + """Test add_secret policy.""" + self.client.create_secret(name='test_create_secret') + + key = rbac_base.create_aes_key() + expire_time = (datetime.utcnow() + timedelta(days=5)) + self.client.create_secret( + name='test_create_secret2', + expiration=expire_time.isoformat(), algorithm="aes", + bit_length=256, mode="cbc", payload=key, + payload_content_type="application/octet-stream", + payload_content_encoding="base64" + ) def test_list_secrets(self): - pass + """Test get_secrets policy.""" + # create two secrets + self.create_empty_secret_admin('test_list_secrets') + self.create_empty_secret_admin('test_list_secrets_2') + + # list secrets with name secret_1 + resp = self.client.list_secrets(name='test_list_secrets') + secrets = resp['secrets'] + self.assertEqual('test_list_secrets', secrets[0]['name']) + + # list secrets with name secret_2 + resp = self.client.list_secrets(name='test_list_secrets_2') + secrets = resp['secrets'] + self.assertEqual('test_list_secrets_2', secrets[0]['name']) + + # list all secrets + resp = self.client.list_secrets() + secrets = resp['secrets'] + self.assertGreaterEqual(len(secrets), 2) def test_delete_secret(self): - pass + """Test delete_secrets policy.""" + sec = self.create_empty_secret_admin('test_delete_secret_1') + uuid = self.client.ref_to_uuid(sec['secret_ref']) + self.client.delete_secret(uuid) def test_get_secret(self): - pass + """Test get_secret policy.""" + sec = self.create_empty_secret_admin('test_get_secret') + uuid = self.client.ref_to_uuid(sec['secret_ref']) + resp = self.client.get_secret_metadata(uuid) + self.assertEqual(uuid, self.client.ref_to_uuid(resp['secret_ref'])) def test_get_secret_payload(self): - pass + """Test get_secret payload policy.""" + key, sec = self.create_aes_secret_admin('test_get_secret_payload') + uuid = self.client.ref_to_uuid(sec['secret_ref']) + + # Retrieve the payload + payload = self.client.get_secret_payload(uuid) + self.assertEqual(key, base64.b64encode(payload)) def test_put_secret_payload(self): - pass + """Test put_secret policy.""" + sec = self.create_empty_secret_admin('test_put_secret_payload') + uuid = self.client.ref_to_uuid(sec['secret_ref']) + + key = rbac_base.create_aes_key() + + # Associate the payload with the created secret + self.client.put_secret_payload(uuid, key) + + # Retrieve the payload + payload = self.client.get_secret_payload(uuid) + self.assertEqual(key, base64.b64encode(payload)) -class SystemMemberTests(rbac_base.BarbicanV1RbacBase, BarbicanV1RbacSecrets): - +class ProjectAdminTests(ProjectMemberTests): @classmethod def setup_clients(cls): super().setup_clients() - cls.client = cls.secret_client - - def test_create_secret(self): - pass - - def test_list_secrets(self): - pass - - def test_delete_secret(self): - pass - - def test_get_secret(self): - pass - - def test_get_secret_payload(self): - pass - - def test_put_secret_payload(self): - pass + cls.client = cls.os_project_admin.secret_v1.SecretClient() class SystemReaderTests(rbac_base.BarbicanV1RbacBase, BarbicanV1RbacSecrets): @@ -342,3 +370,31 @@ class SystemReaderTests(rbac_base.BarbicanV1RbacBase, BarbicanV1RbacSecrets): def test_put_secret_payload(self): pass + + def test_get_other_project_secret(self): + pass + + def test_get_other_project_secret_payload(self): + pass + + def test_put_other_project_secret_payload(self): + pass + + def test_delete_other_project_secret(self): + pass + + +class SystemMemberTests(SystemReaderTests): + + @classmethod + def setup_clients(cls): + super().setup_clients() + cls.client = cls.secret_client + + +class SystemAdminTests(SystemMemberTests): + + @classmethod + def setup_clients(cls): + super().setup_clients() + cls.client = cls.secret_client