Add secure-rbac tests for Secret Metadata

This patch test RBAC access for the Secret Metadata API.

Depends-On: I8222ea2a55cdb72f1d9affe9fb0cf542c6b7c88c
Change-Id: I4dda0eb7198892ed1b662b4c3f3b6e99d9d3e80a
diff --git a/barbican_tempest_plugin/services/key_manager/json/secret_metadata_client.py b/barbican_tempest_plugin/services/key_manager/json/secret_metadata_client.py
index dae8ae3..5376217 100644
--- a/barbican_tempest_plugin/services/key_manager/json/secret_metadata_client.py
+++ b/barbican_tempest_plugin/services/key_manager/json/secret_metadata_client.py
@@ -16,16 +16,18 @@
 import json
 
 from tempest import config
-from tempest.lib.common import rest_client
+
+from barbican_tempest_plugin.services.key_manager.json import base
 
 CONF = config.CONF
 
 
-class SecretMetadataClient(rest_client.RestClient):
+class SecretMetadataClient(base.BarbicanTempestClient):
 
     def get_secret_metadata(self, secret_id):
         resp, body = self.get("v1/secrets/%s/metadata" % secret_id)
         self.expected_success(200, resp.status)
+        # Note: "metadata" top level key gets dropped by _parse_resp()
         return self._parse_resp(body)
 
     def put_secret_metadata(self, secret_id, **kwargs):
@@ -33,6 +35,7 @@
         uri = "v1/secrets/%s/metadata" % secret_id
         resp, body = self.put(uri, json.dumps(body_dict))
         self.expected_success(201, resp.status)
+        # Note: "metadata" top level key gets dropped by _parse_resp()
         return self._parse_resp(body)
 
     def get_secret_metadata_by_key(self, secret_id, key):
diff --git a/barbican_tempest_plugin/tests/rbac/v1/base.py b/barbican_tempest_plugin/tests/rbac/v1/base.py
index 235636c..4c3ad32 100644
--- a/barbican_tempest_plugin/tests/rbac/v1/base.py
+++ b/barbican_tempest_plugin/tests/rbac/v1/base.py
@@ -129,9 +129,7 @@
         # setup clients for admin persona
         adm = cls.os_project_admin
         cls.admin_secret_client = adm.secret_v1.SecretClient()
-        cls.admin_secret_metadata_client = adm.secret_v1.SecretMetadataClient(
-            service='key-manager'
-        )
+        cls.admin_secret_metadata_client = adm.secret_v1.SecretMetadataClient()
         cls.admin_consumer_client = adm.secret_v1.ConsumerClient(
             service='key-manager'
         )
@@ -145,9 +143,7 @@
         # set clients for member persona
         member = cls.os_project_member
         cls.secret_client = member.secret_v1.SecretClient()
-        cls.secret_metadata_client = member.secret_v1.SecretMetadataClient(
-            service='key-manager'
-        )
+        cls.secret_metadata_client = member.secret_v1.SecretMetadataClient()
         cls.consumer_client = member.secret_v1.ConsumerClient(
             service='key-manager'
         )
@@ -162,6 +158,8 @@
         # project
         cls.other_secret_client = \
             cls.os_project_alt_member.secret_v1.SecretClient()
+        cls.other_secret_metadata_client = \
+            cls.os_project_alt_member.secret_v1.SecretMetadataClient()
         cls.other_container_client = \
             cls.os_project_alt_member.secret_v1.ContainerClient()
         cls.other_order_client = \
@@ -265,6 +263,24 @@
         resp = self.other_secret_client.create_secret(**kwargs)
         return self.other_secret_client.ref_to_uuid(resp['secret_ref'])
 
+    def create_test_secret(self, client, name, payload=None):
+        """Create a secret for testing
+
+        The new secret is created using the given client.  If no
+        payload is given, the secret is left empty.
+
+        :returns: the uuid for the new secret
+        """
+        kwargs = {
+            'name': name,
+            'secret_type': 'passphrase'
+        }
+        if payload is not None:
+            kwargs['payload'] = payload
+            kwargs['payload_content_type'] = 'text/plain'
+        resp = client.create_secret(**kwargs)
+        return client.ref_to_uuid(resp['secret_ref'])
+
     def create_test_order(self, client, order_name):
         """Create a symmetric key order for testing
 
diff --git a/barbican_tempest_plugin/tests/rbac/v1/test_secret_metadata.py b/barbican_tempest_plugin/tests/rbac/v1/test_secret_metadata.py
new file mode 100644
index 0000000..a8e61a7
--- /dev/null
+++ b/barbican_tempest_plugin/tests/rbac/v1/test_secret_metadata.py
@@ -0,0 +1,336 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import abc
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from barbican_tempest_plugin.tests.rbac.v1 import base
+
+
+class BarbicanV1RbacSecretMetadata:
+
+    @abc.abstractmethod
+    def test_create_key_value_pair(self):
+        """Test create_key_value_pair policy
+
+        Testing: POST /v1/secrets/{secret-id}/metadata
+        This test must check:
+          * whether the persona can add metadata to a secret
+        """
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def test_put_secret_metadata(self):
+        """Test put_secret_metadata policy
+
+        Testing: PUT /v1/secrets/{secret-id}/metadata
+        This test must check:
+          * whether the persona can update metadata on a secret
+        """
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def test_get_secret_metadata(self):
+        """Test get_secret_metadata policy
+
+        Testing: GET /v1/secrets/{secret-id}/metadata
+        This test must check:
+          * whether the persona can retrieve secret metadata
+        """
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def test_update_secret_metadata_by_key(self):
+        """Test update_secret_metadata policy
+
+        Testing: PUT /v1/secrets/{secret-id}/metadata/{meta-key}
+        This test must check:
+          * whether the persona can update individual secret metadata
+            values
+        """
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def test_get_secret_metadata_by_key(self):
+        """Test get_secret_metadata_by_key policy
+
+        Testing: GET /v1/secrets/{secret-id}/metadata/{meta-key}
+        This test must check:
+          * whether the persona can retrieve individual secret metadata
+            values
+        """
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def test_delete_secret_metadata_by_key(self):
+        """Test delete_secret_metadata_by_key policy
+
+        Testing: DELETE /v1/secrets/{secret-id}/metadata/{meta-key}
+        This test must check:
+          * whether the persona can delete individual secret metadata
+            values
+        """
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def test_create_key_value_pair_on_other_secret(self):
+        """Test create_key_value_pair policy
+
+        Testing: POST /v1/secrets/{secret-id}/metadata
+        This test must check:
+          * whether the persona can add metadata to a secret
+            that belongs to a different project
+        """
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def test_put_secret_metadata_on_other_secret(self):
+        """Test put_secret_metadata policy
+
+        Testing: PUT /v1/secrets/{secret-id}/metadata
+        This test must check:
+          * whether the persona can update metadata on a secret
+            that belongs to a different project
+        """
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def test_get_secret_metadata_from_other_secret(self):
+        """Test get_secret_metadata policy
+
+        Testing: GET /v1/secrets/{secret-id}/metadata
+        This test must check:
+          * whether the persona can retrieve secret metadata
+            from a secret that belongs to a different project
+        """
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def test_update_other_secret_metadata_by_key(self):
+        """Test update_secret_metadata policy
+
+        Testing: PUT /v1/secrets/{secret-id}/metadata/{meta-key}
+        This test must check:
+          * whether the persona can update individual secret metadata
+            values on a secret that belongs to a different project
+        """
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def test_get_other_secret_metadata_by_key(self):
+        """Test get_secret_metadata_by_key policy
+
+        Testing: GET /v1/secrets/{secret-id}/metadata/{meta-key}
+        This test must check:
+          * whether the persona can retrieve individual secret metadata
+            values for a secret that belongs to a different project
+        """
+        raise NotImplementedError
+
+    @abc.abstractmethod
+    def test_delete_other_secret_metadata_by_key(self):
+        """Test delete_secret_metadata policy
+
+        Testing: DELETE /v1/secrets/{secret-id}/metadata/{meta-key}
+        This test must check:
+          * whether the persona can delete individual secret metadata
+            values
+        """
+        raise NotImplementedError
+
+
+class ProjectReaderTests(base.BarbicanV1RbacBase,
+                         BarbicanV1RbacSecretMetadata):
+
+    @classmethod
+    def setup_clients(cls):
+        super().setup_clients()
+        cls.client = cls.os_project_reader.secret_v1.SecretMetadataClient()
+
+    def setUp(self):
+        super().setUp()
+        self.secret_id = self.create_test_secret(
+            self.secret_client,
+            data_utils.rand_name('test-secret-metadata'),
+            'SECRET_PASSPHRASE')
+        self.secret_metadata_client.create_key_value_pair(
+            self.secret_id,
+            'foo',
+            'bar')
+
+        self.other_secret_id = self.create_test_secret(
+            self.other_secret_client,
+            data_utils.rand_name('test-secret-metadata'),
+            'SECRET_PASSPHRASE')
+        self.other_secret_metadata_client.create_key_value_pair(
+            self.other_secret_id,
+            'foo',
+            'bar')
+
+    def test_create_key_value_pair(self):
+        self.assertRaises(
+            exceptions.Forbidden,
+            self.client.create_key_value_pair,
+            self.secret_id,
+            'mykey',
+            'foo'
+        )
+
+    def test_put_secret_metadata(self):
+        meta = {
+            'foo': 'bar',
+            'baz': 'bork'
+        }
+        self.assertRaises(
+            exceptions.Forbidden,
+            self.client.put_secret_metadata,
+            self.secret_id,
+            **meta)
+
+    def test_get_secret_metadata(self):
+        self.assertRaises(
+            exceptions.Forbidden,
+            self.client.get_secret_metadata,
+            self.secret_id)
+
+    def test_update_secret_metadata_by_key(self):
+        self.assertRaises(
+            exceptions.Forbidden,
+            self.client.update_secret_metadata,
+            self.secret_id,
+            'foo',
+            'baz')
+
+    def test_get_secret_metadata_by_key(self):
+        self.assertRaises(
+            exceptions.Forbidden,
+            self.client.get_secret_metadata_by_key,
+            self.secret_id,
+            'foo')
+
+    def test_delete_secret_metadata_by_key(self):
+        self.assertRaises(
+            exceptions.Forbidden,
+            self.client.delete_secret_metadata_by_key,
+            self.secret_id,
+            'foo')
+
+    def test_create_key_value_pair_on_other_secret(self):
+        self.assertRaises(
+            exceptions.Forbidden,
+            self.client.create_key_value_pair,
+            self.other_secret_id,
+            'mykey',
+            'foo'
+        )
+
+    def test_put_secret_metadata_on_other_secret(self):
+        meta = {
+            'foo': 'bar',
+            'baz': 'bork'
+        }
+        self.assertRaises(
+            exceptions.Forbidden,
+            self.client.put_secret_metadata,
+            self.other_secret_id,
+            **meta)
+
+    def test_get_secret_metadata_from_other_secret(self):
+        self.assertRaises(
+            exceptions.Forbidden,
+            self.client.get_secret_metadata,
+            self.other_secret_id)
+
+    def test_update_other_secret_metadata_by_key(self):
+        self.assertRaises(
+            exceptions.Forbidden,
+            self.client.update_secret_metadata,
+            self.other_secret_id,
+            'foo',
+            'baz')
+
+    def test_get_other_secret_metadata_by_key(self):
+        self.assertRaises(
+            exceptions.Forbidden,
+            self.client.get_secret_metadata_by_key,
+            self.other_secret_id,
+            'foo')
+
+    def test_delete_other_secret_metadata_by_key(self):
+        self.assertRaises(
+            exceptions.Forbidden,
+            self.client.delete_secret_metadata_by_key,
+            self.other_secret_id,
+            'foo')
+
+
+class ProjectMemberTests(ProjectReaderTests):
+
+    @classmethod
+    def setup_clients(cls):
+        super().setup_clients()
+        cls.client = cls.secret_metadata_client
+
+    def test_create_key_value_pair(self):
+        resp = self.client.create_key_value_pair(
+            self.secret_id,
+            'mykey',
+            'foo'
+        )
+        self.assertEqual('mykey', resp['key'])
+        self.assertEqual('foo', resp['value'])
+
+    def test_put_secret_metadata(self):
+        test_meta = {
+            'foo': 'baz',
+            'bar': 'bork'
+        }
+        self.client.put_secret_metadata(self.secret_id, **test_meta)
+        resp = self.client.get_secret_metadata(self.secret_id)
+
+        self.assertIn('bar', resp.keys())
+        self.assertEqual('baz', resp['foo'])
+
+    def test_get_secret_metadata(self):
+        resp = self.client.get_secret_metadata(self.secret_id)
+
+        self.assertIn('foo', resp.keys())
+        self.assertEqual('bar', resp['foo'])
+
+    def test_update_secret_metadata_by_key(self):
+        self.client.update_secret_metadata(self.secret_id, 'foo', 'baz')
+
+        resp = self.secret_metadata_client.get_secret_metadata(self.secret_id)
+        self.assertEqual('baz', resp['foo'])
+
+    def test_get_secret_metadata_by_key(self):
+        resp = self.client.get_secret_metadata_by_key(self.secret_id, 'foo')
+        self.assertEqual('foo', resp['key'])
+        self.assertEqual('bar', resp['value'])
+
+    def test_delete_secret_metadata_by_key(self):
+        self.client.delete_secret_metadata_by_key(self.secret_id, 'foo')
+        self.assertRaises(
+            exceptions.NotFound,
+            self.client.get_secret_metadata_by_key,
+            self.secret_id,
+            'foo')
+
+
+class ProjectAdminTests(ProjectMemberTests):
+
+    @classmethod
+    def setup_clients(cls):
+        super().setup_clients()
+        cls.client = cls.admin_secret_metadata_client