Merge "Replace assertItemsEqual with assertCountEqual"
diff --git a/.zuul.yaml b/.zuul.yaml
index b827bce..ba6fc8c 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -1,3 +1,39 @@
+- job:
+ name: keystone-protection-functional
+ parent: keystone-dsvm-py3-functional
+ vars:
+ tempest_test_regex: 'keystone_tempest_plugin.tests.rbac'
+ devstack_localrc:
+ KEYSTONE_ENFORCE_SCOPE: True
+ devstack_plugins:
+ keystone: https://opendev.org/openstack/keystone
+ devstack_services:
+ g-api: false
+ g-reg: false
+ n-api: false
+ n-api-meta: false
+ n-cond: false
+ n-cpu: false
+ n-novnc: false
+ n-sch: false
+ placement-api: false
+ q-agt: false
+ q-dhcp: false
+ q-l3: false
+ q-meta: false
+ q-metering: false
+ s-account: false
+ s-container: false
+ s-object: false
+ s-proxy: false
+ c-api: false
+ c-bak: false
+ c-sch: false
+ c-vol: false
+ cinder: false
+ devstack_local_conf:
+ post-config: {}
+
- project:
templates:
- check-requirements
@@ -5,28 +41,38 @@
check:
jobs:
- keystone-dsvm-py3-functional
- - keystone-dsvm-py3-functional-federation-opensuse15:
+ - keystone-dsvm-py3-functional-federation-ubuntu-focal:
voting: false
- - keystone-dsvm-py3-functional-federation-opensuse15-k2k
+ - keystone-dsvm-py3-functional-federation-ubuntu-focal-k2k
+ - keystone-dsvm-py3-functional-wallaby
+ - keystone-dsvm-py3-functional-victoria
- keystone-dsvm-py3-functional-ussuri
- keystone-dsvm-py3-functional-train
- - keystone-dsvm-py3-functional-stein
+ - keystone-protection-functional
gate:
jobs:
- keystone-dsvm-py3-functional
- - keystone-dsvm-py3-functional-federation-opensuse15-k2k
+ - keystone-dsvm-py3-functional-federation-ubuntu-focal-k2k
+ - keystone-protection-functional
+
+- job:
+ name: keystone-dsvm-py3-functional-wallaby
+ parent: keystone-dsvm-py3-functional
+ override-checkout: stable/wallaby
+
+- job:
+ name: keystone-dsvm-py3-functional-victoria
+ parent: keystone-dsvm-py3-functional
+ override-checkout: stable/victoria
- job:
name: keystone-dsvm-py3-functional-ussuri
parent: keystone-dsvm-py3-functional
+ nodeset: openstack-single-node-bionic
override-checkout: stable/ussuri
- job:
name: keystone-dsvm-py3-functional-train
parent: keystone-dsvm-py3-functional
+ nodeset: openstack-single-node-bionic
override-checkout: stable/train
-
-- job:
- name: keystone-dsvm-py3-functional-stein
- parent: keystone-dsvm-py3-functional
- override-checkout: stable/stein
diff --git a/keystone_tempest_plugin/clients.py b/keystone_tempest_plugin/clients.py
index 97b5b14..93c0753 100644
--- a/keystone_tempest_plugin/clients.py
+++ b/keystone_tempest_plugin/clients.py
@@ -19,6 +19,7 @@
from keystone_tempest_plugin.services.identity.v3 import (
service_providers_client)
from keystone_tempest_plugin.services.identity.v3 import auth_client
+from keystone_tempest_plugin.services.identity.v3 import limits_client
from keystone_tempest_plugin.services.identity.v3 import saml2_client
from tempest import clients
@@ -29,7 +30,10 @@
def __init__(self, credentials):
super(Manager, self).__init__(credentials)
+ # keystone auth client
self.auth_client = auth_client.AuthClient(self.auth_provider)
+
+ # federation clients
self.identity_providers_client = (
identity_providers_client.IdentityProvidersClient(
self.auth_provider))
@@ -40,3 +44,8 @@
self.service_providers_client = (
service_providers_client.ServiceProvidersClient(
self.auth_provider))
+
+ # unified limits clients
+ self.registered_limits_client = limits_client.RegisteredLimitsClient(
+ self.auth_provider)
+ self.limits_client = limits_client.LimitsClient(self.auth_provider)
diff --git a/keystone_tempest_plugin/config.py b/keystone_tempest_plugin/config.py
index 25964a8..2d4d189 100644
--- a/keystone_tempest_plugin/config.py
+++ b/keystone_tempest_plugin/config.py
@@ -15,7 +15,7 @@
from oslo_config import cfg
-identity_feature_option = [
+identity_feature_options = [
cfg.BoolOpt('federation',
default=False,
help='Does the environment support the Federated Identity '
@@ -25,6 +25,10 @@
help='Whether to test federated scenarios against an external '
'identity provider. If disabled, only '
'Keystone-to-Keystone tests will be enabled.'),
+ cfg.BoolOpt('enforce_scope',
+ default=False,
+ help='Does the keystone service enforce scope and use '
+ 'scope-aware policies?'),
]
fed_scenario_group = cfg.OptGroup(name='fed_scenario',
diff --git a/keystone_tempest_plugin/plugin.py b/keystone_tempest_plugin/plugin.py
index 76f7a9c..72db604 100644
--- a/keystone_tempest_plugin/plugin.py
+++ b/keystone_tempest_plugin/plugin.py
@@ -32,12 +32,12 @@
def register_opts(self, conf):
config.register_opt_group(conf, config.identity_feature_group,
- project_config.identity_feature_option)
+ project_config.identity_feature_options)
config.register_opt_group(conf, project_config.fed_scenario_group,
project_config.FedScenarioGroup)
def get_opt_lists(self):
return [(config.identity_feature_group.name,
- project_config.identity_feature_option),
+ project_config.identity_feature_options),
(project_config.fed_scenario_group.name,
project_config.FedScenarioGroup)]
diff --git a/keystone_tempest_plugin/services/identity/v3/limits_client.py b/keystone_tempest_plugin/services/identity/v3/limits_client.py
new file mode 100644
index 0000000..6e95b9d
--- /dev/null
+++ b/keystone_tempest_plugin/services/identity/v3/limits_client.py
@@ -0,0 +1,156 @@
+# Copyright 2020 SUSE LLC
+#
+# 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 json
+
+import http.client
+from tempest.lib.common import rest_client
+
+from keystone_tempest_plugin.services.identity import clients
+
+
+class RegisteredLimitsClient(clients.Identity):
+
+ subpath_prefix = 'registered_limits'
+ collection_url = subpath_prefix
+ entity_url = subpath_prefix + '/%s'
+
+ def create_registered_limits(self, payload):
+ """Create a list of registered limits.
+
+ :param body: A list of registered limits objects.
+ """
+ post_body = json.dumps({'registered_limits': payload})
+ resp, body = super(RegisteredLimitsClient, self).post(
+ self.collection_url, post_body)
+ self.expected_success(http.client.CREATED, resp.status)
+ body = json.loads(body.decode('utf-8'))
+ return rest_client.ResponseBody(resp, body)
+
+ def list_registered_limits(self, **kwargs):
+ """List registered limits.
+
+ :param kwargs: Filter by service_id, region_id, or resource_name
+ """
+ resp, body = super(RegisteredLimitsClient, self).get(
+ self.collection_url, **kwargs)
+ self.expected_success(http.client.OK, resp.status)
+ body = json.loads(body.decode('utf-8'))
+ return rest_client.ResponseBody(resp, body)
+
+ def update_registered_limit(self, registered_limit_id, registered_limit):
+ """Update a registered limit.
+
+ :param registered_limit_id: ID of registered limit to update
+ :param registered_limit: new registered limit object
+ """
+ patch_body = json.dumps({'registered_limit': registered_limit})
+ resp, body = super(RegisteredLimitsClient, self).patch(
+ self.entity_url % registered_limit_id, patch_body)
+ self.expected_success(http.client.OK, resp.status)
+ body = json.loads(body.decode('utf-8'))
+ return rest_client.ResponseBody(resp, body)
+
+ def show_registered_limit(self, registered_limit_id):
+ """Get a registered limit.
+
+ :param registered_limit_id: ID of registered limit to show
+ """
+ resp, body = super(RegisteredLimitsClient, self).get(
+ self.entity_url % registered_limit_id)
+ self.expected_success(http.client.OK, resp.status)
+ body = json.loads(body.decode('utf-8'))
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_registered_limit(self, registered_limit_id):
+ """Delete a registered limit.
+
+ :param registered_limit_id: ID of registered limit to delete.
+ """
+ resp, body = super(RegisteredLimitsClient, self).delete(
+ self.entity_url % registered_limit_id)
+ self.expected_success(http.client.NO_CONTENT, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+
+class LimitsClient(clients.Identity):
+
+ subpath_prefix = 'limits'
+ collection_url = subpath_prefix
+ entity_url = subpath_prefix + '/%s'
+
+ def limits_model(self):
+ """Get limits model from server."""
+ url = self.entity_url % 'model'
+ resp, body = super(LimitsClient, self).get(url)
+ self.expected_success(http.client.OK, resp.status)
+ body = json.loads(body.decode('utf-8'))
+ return rest_client.ResponseBody(resp, body)
+
+ def create_limits(self, payload):
+ """Create a list of project limits.
+
+ :param body: A list of project limits objects.
+ """
+ post_body = json.dumps({'limits': payload})
+ resp, body = super(LimitsClient, self).post(
+ self.collection_url, post_body)
+ self.expected_success(http.client.CREATED, resp.status)
+ body = json.loads(body.decode('utf-8'))
+ return rest_client.ResponseBody(resp, body)
+
+ def list_limits(self, **kwargs):
+ """List project limits.
+
+ :param kwargs: Filter by service_id, region_id, resource_name,
+ or project/domain ID
+ """
+ resp, body = super(LimitsClient, self).get(
+ self.collection_url, **kwargs)
+ self.expected_success(http.client.OK, resp.status)
+ body = json.loads(body.decode('utf-8'))
+ return rest_client.ResponseBody(resp, body)
+
+ def update_limit(self, limit_id, limit):
+ """Update a project limit.
+
+ :param limit_id: ID of project limit to update
+ :param limit: new project limit object
+ """
+ patch_body = json.dumps({'limit': limit})
+ resp, body = super(LimitsClient, self).patch(
+ self.entity_url % limit_id, patch_body)
+ self.expected_success(http.client.OK, resp.status)
+ body = json.loads(body.decode('utf-8'))
+ return rest_client.ResponseBody(resp, body)
+
+ def show_limit(self, limit_id):
+ """Get a project limit.
+
+ :param limit_id: ID of project limit to show
+ """
+ resp, body = super(LimitsClient, self).get(self.entity_url % limit_id)
+ self.expected_success(http.client.OK, resp.status)
+ body = json.loads(body.decode('utf-8'))
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_limit(self, limit_id):
+ """Delete a project limit.
+
+ :param limit_id: ID of project limit to delete.
+ """
+ resp, body = super(LimitsClient, self).delete(
+ self.entity_url % limit_id)
+ self.expected_success(http.client.NO_CONTENT, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/keystone_tempest_plugin/tests/base.py b/keystone_tempest_plugin/tests/base.py
index 16f0092..77dcafe 100644
--- a/keystone_tempest_plugin/tests/base.py
+++ b/keystone_tempest_plugin/tests/base.py
@@ -42,3 +42,6 @@
cls.tokens_client = cls.keystone_manager.token_v3_client
cls.consumers_client = cls.keystone_manager.oauth_consumers_client
cls.oauth_token_client = cls.keystone_manager.oauth_token_client
+ cls.registered_limits_client = (
+ cls.keystone_manager.registered_limits_client)
+ cls.limits_client = cls.keystone_manager.limits_client
diff --git a/keystone_tempest_plugin/tests/rbac/__init__.py b/keystone_tempest_plugin/tests/rbac/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/__init__.py
diff --git a/keystone_tempest_plugin/tests/rbac/v3/__init__.py b/keystone_tempest_plugin/tests/rbac/v3/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/__init__.py
diff --git a/keystone_tempest_plugin/tests/rbac/v3/base.py b/keystone_tempest_plugin/tests/rbac/v3/base.py
new file mode 100644
index 0000000..d260b7b
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/base.py
@@ -0,0 +1,41 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.
+
+from tempest import config
+
+CONF = config.CONF
+
+
+class IdentityV3RbacBaseTests(object):
+
+ identity_version = 'v3'
+
+ @classmethod
+ def skip_checks(cls):
+ super(IdentityV3RbacBaseTests, cls).skip_checks()
+ if not CONF.identity_feature_enabled.enforce_scope:
+ raise cls.skipException("enforce_scope is not enabled for "
+ "keystone, skipping RBAC tests")
+
+ def do_request(self, method, expected_status=200, client=None, **payload):
+ if not client:
+ client = self.client
+ if isinstance(expected_status, type(Exception)):
+ self.assertRaises(expected_status,
+ getattr(client, method),
+ **payload)
+ else:
+ response = getattr(client, method)(**payload)
+ self.assertEqual(response.response.status, expected_status)
+ return response
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_access_rule.py b/keystone_tempest_plugin/tests/rbac/v3/test_access_rule.py
new file mode 100644
index 0000000..25767fc
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_access_rule.py
@@ -0,0 +1,487 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest import clients
+from tempest.lib import auth
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacAccessRuleTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ identity_version = 'v3'
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacAccessRuleTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.access_rules_client
+ cls.admin_client = cls.os_system_admin
+
+ def user(self):
+ user = {}
+ name = data_utils.rand_name('user')
+ user['name'] = name
+ user['password'] = data_utils.rand_password()
+ return user
+
+ def app_cred(self):
+ app_cred = {}
+ app_cred['name'] = data_utils.rand_name('app_cred')
+ app_cred['access_rules'] = [
+ {
+ 'path': '/servers',
+ 'method': 'GET',
+ 'service': 'compute',
+ }
+ ]
+ return app_cred
+
+ @classmethod
+ def setup_user_client(cls, domain_id=None):
+ """Set up project user with its own client.
+
+ This is to enable the project user to create its own app cred.
+
+ Returns a client object and the user's ID.
+ """
+ user_dict = {
+ 'name': data_utils.rand_name('user'),
+ 'password': data_utils.rand_password(),
+ }
+ if domain_id:
+ user_dict['domain_id'] = domain_id
+ user_id = cls.admin_client.users_v3_client.create_user(
+ **user_dict)['user']['id']
+
+ def try_delete_user():
+ # delete user if not deleted by domain deletion
+ try:
+ cls.admin_client.users_v3_client.delete_user(user_id)
+ except exceptions.NotFound:
+ pass
+
+ cls.addClassResourceCleanup(try_delete_user)
+ project_id = cls.admin_client.projects_client.create_project(
+ data_utils.rand_name())['project']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.projects_client.delete_project, project_id)
+ member_role_id = cls.admin_client.roles_v3_client.list_roles(
+ name='member')['roles'][0]['id']
+ cls.admin_client.roles_v3_client.create_user_role_on_project(
+ project_id, user_id, member_role_id)
+ creds = auth.KeystoneV3Credentials(
+ user_id=user_id,
+ password=user_dict['password'],
+ project_id=project_id)
+ auth_provider = clients.get_auth_provider(creds)
+ creds = auth_provider.fill_credentials()
+ client = clients.Manager(credentials=creds)
+ return client, user_id
+
+ @abc.abstractmethod
+ def test_identity_get_access_rule(self):
+ """Test identity:get_access_rule policy
+
+ This test must check:
+ * whether the persona can retrieve an access rule they own
+ * whether the persona can retrieve an access rule they do not own
+ * whether the persona can retrieve an access rule that does not exist
+ * whether the persona can retrieve an access rule for a user in their
+ own domain (if applicable)
+ * whether the persona can retrieve an access rule for a user in
+ another domain (if applicable)
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_access_rules(self):
+ """Test identity:list_access_rules policy
+
+ This test must check:
+ * whether the persona can list their own access rules
+ * whether the persona can list the access rules for another user
+ * whether the persona can list the access rules for a user in their
+ own domain
+ * whether the persona can list the access rules for a user in another
+ domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_access_rule(self):
+ """Test identity:delete_access_rule policy.
+
+ This test must check
+ * whether the persona can delete an access rule they own
+ * whether the persona can delete an access rule for an arbitrary user
+ * whether the persona can delete an access rule that does not exist
+ * whether the persona can delete an access rule for a user in another
+ domain (if applicable)
+ * whether the persona can delete an access rule for a user in their
+ own domain (if applicable)
+ * whether the persona can delete an access rule that does not exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacAccessRuleTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ @classmethod
+ def setup_clients(cls):
+ super(SystemAdminTests, cls).setup_clients()
+ cls.test_user_client, cls.test_user_id = cls.setup_user_client()
+
+ def setUp(self):
+ # create app cred for other user
+ super(SystemAdminTests, self).setUp()
+ app_cred_client = self.test_user_client.application_credentials_client
+ app_cred = app_cred_client.create_application_credential(
+ user_id=self.test_user_id, **self.app_cred()
+ )['application_credential']
+ self.app_cred_id = app_cred['id']
+ self.access_rule_id = app_cred['access_rules'][0]['id']
+
+ def try_delete_app_cred(id):
+ app_cred_client = self.admin_client.application_credentials_client
+ try:
+ app_cred_client.delete_application_credential(
+ user_id=self.test_user_id,
+ application_credential_id=id)
+ except exceptions.NotFound:
+ pass
+
+ def try_delete_access_rule(id):
+ try:
+ self.admin_client.access_rules_client.delete_access_rule(
+ user_id=self.test_user_id,
+ access_rule_id=id)
+ except exceptions.NotFound:
+ pass
+ self.addCleanup(try_delete_access_rule, self.access_rule_id)
+ self.addCleanup(try_delete_app_cred, self.app_cred_id)
+
+ def test_identity_get_access_rule(self):
+ # system admin cannot create app creds and therefore cannot create
+ # access rules, so skip retrieval of own access rule
+
+ # retrieve other user's access rules
+ self.do_request(
+ 'show_access_rule',
+ user_id=self.test_user_id, access_rule_id=self.access_rule_id)
+
+ # retrieving a non-existent access rule should return a 404
+ self.do_request(
+ 'show_access_rule', expected_status=exceptions.NotFound,
+ user_id=self.test_user_id,
+ access_rule_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_access_rules(self):
+ # system admin cannot create app creds and therefore cannot create
+ # access rules, so skip listing of own access rule
+
+ # list other user's access rules
+ self.do_request('list_access_rules', user_id=self.test_user_id)
+
+ def test_identity_delete_access_rule(self):
+ # system admin cannot create app creds and therefore cannot create
+ # access rules, so skip deletion of own access rule
+
+ # delete other user's access rules
+ app_cred_client = self.admin_client.application_credentials_client
+ app_cred_client.delete_application_credential(
+ user_id=self.test_user_id,
+ application_credential_id=self.app_cred_id)
+ self.do_request(
+ 'delete_access_rule', expected_status=204,
+ user_id=self.test_user_id, access_rule_id=self.access_rule_id)
+
+ # deleting a non-existent access rule should return a 404
+ self.do_request(
+ 'delete_access_rule', expected_status=exceptions.NotFound,
+ user_id=self.test_user_id,
+ access_rule_id=data_utils.rand_uuid_hex())
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_delete_access_rule(self):
+ app_cred_client = self.admin_client.application_credentials_client
+ app_cred_client.delete_application_credential(
+ user_id=self.test_user_id,
+ application_credential_id=self.app_cred_id)
+ self.do_request(
+ 'delete_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_id, access_rule_id=self.access_rule_id)
+
+ # retrieving a non-existent access rule should return a 404
+ self.do_request(
+ 'show_access_rule', expected_status=exceptions.NotFound,
+ user_id=self.test_user_id,
+ access_rule_id=data_utils.rand_uuid_hex())
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(IdentityV3RbacAccessRuleTest, base.BaseIdentityTest):
+
+ # Domain admins cannot create their own app creds (app creds can only be
+ # scoped to projects) and domain admins have no special privileges over the
+ # app creds own by users in their domains.
+
+ credentials = ['domain_admin', 'system_admin']
+
+ @classmethod
+ def setup_clients(cls):
+ super(DomainAdminTests, cls).setup_clients()
+ own_domain_id = cls.persona.credentials.domain_id
+ cls.test_client_1, cls.test_user_1 = cls.setup_user_client(
+ domain_id=own_domain_id)
+
+ def setUp(self):
+ super(DomainAdminTests, self).setUp()
+ self.other_domain_id = self.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.addCleanup(self.admin_client.domains_client.delete_domain,
+ self.other_domain_id)
+ self.addCleanup(self.admin_client.domains_client.update_domain,
+ domain_id=self.other_domain_id, enabled=False)
+ self.test_client_2, self.test_user_2 = self.setup_user_client(
+ domain_id=self.other_domain_id)
+ client = self.test_client_1.application_credentials_client
+ app_cred_1 = client.create_application_credential(
+ user_id=self.test_user_1, **self.app_cred()
+ )['application_credential']
+ self.access_rule_1 = app_cred_1['access_rules'][0]['id']
+ self.addCleanup(
+ self.test_client_1.access_rules_client.delete_access_rule,
+ self.test_user_1,
+ self.access_rule_1)
+ self.addCleanup(
+ client.delete_application_credential,
+ self.test_user_1,
+ app_cred_1['id'])
+ client = self.test_client_2.application_credentials_client
+ app_cred_2 = client.create_application_credential(
+ user_id=self.test_user_2, **self.app_cred()
+ )['application_credential']
+ self.access_rule_2 = app_cred_2['access_rules'][0]['id']
+ self.addCleanup(
+ self.test_client_2.access_rules_client.delete_access_rule,
+ self.test_user_2,
+ self.access_rule_2)
+ self.addCleanup(
+ client.delete_application_credential,
+ self.test_user_2,
+ app_cred_2['id'])
+
+ def test_identity_get_access_rule(self):
+ # accessing access rules should be forbidden no matter whether the
+ # owner is in the domain or outside of it
+
+ # retrieve access rule from user in own domain
+ self.do_request(
+ 'show_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1, access_rule_id=self.access_rule_1)
+
+ # retrieve access rule from user in other domain
+ self.do_request(
+ 'show_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2, access_rule_id=self.access_rule_2)
+
+ # retrieving a non-existent access rule should return a 403
+ self.do_request(
+ 'show_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1,
+ access_rule_id=data_utils.rand_uuid_hex())
+ self.do_request(
+ 'show_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2,
+ access_rule_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_access_rules(self):
+ # listing access rules should be forbidden no matter whether the
+ # owner is in the domain or outside of it
+ self.do_request(
+ 'list_access_rules', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1)
+ self.do_request(
+ 'list_access_rules', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2)
+
+ def test_identity_delete_access_rule(self):
+ # deleting access rules should be forbidden no matter whether the
+ # owner is in the domain or outside of it
+
+ # delete access rule from user in own domain
+ self.do_request(
+ 'delete_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1, access_rule_id=self.access_rule_1)
+
+ # delete access rule from user in other domain
+ self.do_request(
+ 'delete_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2, access_rule_id=self.access_rule_2)
+
+ # deleting a non-existent access rule should return a 403
+ self.do_request(
+ 'delete_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1,
+ access_rule_id=data_utils.rand_uuid_hex())
+ self.do_request(
+ 'delete_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2,
+ access_rule_id=data_utils.rand_uuid_hex())
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainAdminTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(IdentityV3RbacAccessRuleTest, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+ @classmethod
+ def setup_clients(cls):
+ super(ProjectAdminTests, cls).setup_clients()
+ cls.test_user_client, cls.test_user_id = cls.setup_user_client()
+
+ def setUp(self):
+ super(ProjectAdminTests, self).setUp()
+ app_cred_client = self.persona.application_credentials_client
+ user_id = self.persona.credentials.user_id
+ self.app_cred_1 = app_cred_client.create_application_credential(
+ user_id, **self.app_cred())['application_credential']
+ self.access_rule_1 = self.app_cred_1['access_rules'][0]['id']
+
+ def try_delete_own_app_cred(id):
+ app_cred_client = self.persona.application_credentials_client
+ try:
+ app_cred_client.delete_application_credential(
+ self.persona.credentials.user_id, id)
+ except exceptions.NotFound:
+ pass
+
+ def try_delete_own_access_rule(id):
+ try:
+ self.persona.access_rules_client.delete_access_rule(
+ self.persona.credentials.user_id, id)
+ except exceptions.NotFound:
+ pass
+
+ self.addCleanup(try_delete_own_access_rule, self.access_rule_1)
+ self.addCleanup(try_delete_own_app_cred, self.app_cred_1['id'])
+
+ app_cred_client = self.test_user_client.application_credentials_client
+ self.app_cred_2 = app_cred_client.create_application_credential(
+ self.test_user_id, **self.app_cred())['application_credential']
+ self.access_rule_2 = self.app_cred_2['access_rules'][0]['id']
+ self.addCleanup(
+ self.test_user_client.access_rules_client.delete_access_rule,
+ self.test_user_id, self.access_rule_2)
+ self.addCleanup(
+ app_cred_client.delete_application_credential,
+ self.test_user_id, self.app_cred_2['id'])
+
+ def test_identity_get_access_rule(self):
+ # should be able to access own credential
+ self.do_request(
+ 'show_access_rule',
+ user_id=self.persona.credentials.user_id,
+ access_rule_id=self.access_rule_1)
+
+ # retrieving non-existent access rule for self should return 404
+ self.do_request(
+ 'show_access_rule', expected_status=exceptions.NotFound,
+ user_id=self.persona.credentials.user_id,
+ access_rule_id=data_utils.rand_uuid_hex())
+
+ # should not be able to access another user's credential
+ self.do_request(
+ 'show_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_id, access_rule_id=self.access_rule_2)
+
+ # retrieving non-existent access rule for other user should return 403
+ self.do_request(
+ 'show_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_id,
+ access_rule_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_access_rules(self):
+ # should be able to list own credentials
+ self.do_request(
+ 'list_access_rules', user_id=self.persona.credentials.user_id)
+
+ # should not be able to list another user's credentials
+ self.do_request(
+ 'list_access_rules', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_id)
+
+ def test_identity_delete_access_rule(self):
+ # should be able to delete own credential
+ app_cred_client = self.persona.application_credentials_client
+ app_cred_client.delete_application_credential(
+ user_id=self.persona.credentials.user_id,
+ application_credential_id=self.app_cred_1['id'])
+ self.do_request(
+ 'delete_access_rule', expected_status=204,
+ user_id=self.persona.credentials.user_id,
+ access_rule_id=self.access_rule_1)
+
+ # deleting non-existent access rule for self should return 404
+ self.do_request(
+ 'delete_access_rule', expected_status=exceptions.NotFound,
+ user_id=self.persona.credentials.user_id,
+ access_rule_id=data_utils.rand_uuid_hex())
+
+ # should not be able to delete another user's credential
+ self.do_request(
+ 'delete_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_id, access_rule_id=self.access_rule_2)
+
+ # deleting non-existent access rule for other user should return 403
+ self.do_request(
+ 'delete_access_rule', expected_status=exceptions.Forbidden,
+ user_id=self.test_user_id,
+ access_rule_id=data_utils.rand_uuid_hex())
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_application_credential.py b/keystone_tempest_plugin/tests/rbac/v3/test_application_credential.py
new file mode 100644
index 0000000..3ca1680
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_application_credential.py
@@ -0,0 +1,565 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest import clients
+from tempest.lib import auth
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacApplicationCredentialTest(
+ rbac_base.IdentityV3RbacBaseTests, metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacApplicationCredentialTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.application_credentials_client
+ cls.admin_client = cls.os_system_admin
+
+ @classmethod
+ def setup_user_client(cls, domain_id=None):
+ """Set up project user with its own client.
+
+ This is to enable the project user to create its own app cred.
+
+ Returns a client object and the user's ID.
+ """
+ user_dict = {
+ 'name': data_utils.rand_name('user'),
+ 'password': data_utils.rand_password(),
+ }
+ if domain_id:
+ user_dict['domain_id'] = domain_id
+ user_id = cls.admin_client.users_v3_client.create_user(
+ **user_dict)['user']['id']
+
+ def try_cleanup_user():
+ # if domain is cleaned up first, user will already be deleted
+ try:
+ cls.admin_client.users_v3_client.delete_user(user_id)
+ except exceptions.NotFound:
+ pass
+
+ cls.addClassResourceCleanup(try_cleanup_user)
+ project_id = cls.admin_client.projects_client.create_project(
+ data_utils.rand_name())['project']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.projects_client.delete_project, project_id)
+ member_role_id = cls.admin_client.roles_v3_client.list_roles(
+ name='member')['roles'][0]['id']
+ cls.admin_client.roles_v3_client.create_user_role_on_project(
+ project_id, user_id, member_role_id)
+ creds = auth.KeystoneV3Credentials(
+ user_id=user_id,
+ password=user_dict['password'],
+ project_id=project_id)
+ auth_provider = clients.get_auth_provider(creds)
+ creds = auth_provider.fill_credentials()
+ client = clients.Manager(credentials=creds)
+ return client, user_id
+
+ def app_cred(self):
+ app_cred = {}
+ app_cred['name'] = data_utils.rand_name('app_cred')
+ return app_cred
+
+ @abc.abstractmethod
+ def test_identity_create_application_credential(self):
+ """Test identity:create_application_credential policy.
+
+ This test must check:
+ * whether the persona can create an application credential for
+ themself
+ * whether the persona can create an application credential for
+ another user
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_application_credential(self):
+ """Test identity:get_application_credential policy.
+
+ This test must check:
+ * whether the persona can get their own application credential
+ * whether the persona can get an application credential for another
+ user
+ * whether the persona can get an application credential for a user in
+ another domain (if applicable)
+ * whether the persona can get an application credential for a user in
+ their own domain (if applicable)
+ * whether the persona can get an application credential that does not
+ exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_application_credentials(self):
+ """Test identity:list_application_credentials policy.
+
+ This test must check:
+ * whether the persona can list all application credentials for
+ themself
+ * whether the persona can list all application credentials for
+ another user
+ * whether the persona can list application credentials for a user in
+ their own domain
+ * whether the persona can list application credentials for a user in
+ another domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_application_credential(self):
+ """Test identity:delete_application_credential policy.
+
+ This test must check
+ * whether the persona can delete their own application credential
+ * whether the persona can delete an application credential for
+ another user
+ * whether the persona can delete an application credential for a user
+ in another domain (if applicable)
+ * whether the persona can delete an application credential for a user
+ in their own domain (if applicable)
+ * whether the persona can delete an application credential that does
+ not exist
+ """
+ pass
+
+
+class SystemAdminTests(
+ IdentityV3RbacApplicationCredentialTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ @classmethod
+ def setup_clients(cls):
+ super(SystemAdminTests, cls).setup_clients()
+ cls.test_user_client, cls.test_user_id = cls.setup_user_client()
+
+ def test_identity_create_application_credential(self):
+ # Creating an application credential requires a project ID in the
+ # token, therefore system-scoped users cannot create app creds.
+ raise self.skipException(
+ "Skipping identity:create_application_credential test for "
+ "system user")
+
+ def test_identity_get_application_credential(self):
+ # Creating an application credential requires a project ID in the
+ # token, therefore system-scoped users cannot create app creds, so skip
+ # check for showing user's own app creds
+
+ # retrieve other user's app cred
+ user_app_cred_client = \
+ self.test_user_client.application_credentials_client
+ app_cred = user_app_cred_client.create_application_credential(
+ user_id=self.test_user_id, **self.app_cred()
+ )['application_credential']
+ self.addCleanup(
+ user_app_cred_client.delete_application_credential,
+ self.test_user_id,
+ app_cred['id'])
+ self.do_request(
+ 'show_application_credential',
+ user_id=self.test_user_id,
+ application_credential_id=app_cred['id'])
+
+ # retrieve app cred that does not exist
+ self.do_request(
+ 'show_application_credential',
+ expected_status=exceptions.NotFound,
+ user_id=self.test_user_id,
+ application_credential_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_application_credentials(self):
+ # Creating an application credential requires a project ID in the
+ # token, therefore system-scoped users cannot create app creds, so skip
+ # check for listing user's own app creds
+
+ # list other user's app creds
+ user_app_cred_client = \
+ self.test_user_client.application_credentials_client
+ app_cred = user_app_cred_client.create_application_credential(
+ user_id=self.test_user_id, **self.app_cred()
+ )['application_credential']
+ self.addCleanup(
+ user_app_cred_client.delete_application_credential,
+ self.test_user_id,
+ app_cred['id'])
+ resp = self.do_request(
+ 'list_application_credentials',
+ user_id=self.test_user_id)
+ self.assertEqual(
+ resp['application_credentials'][0]['id'],
+ app_cred['id'])
+
+ def test_identity_delete_application_credential(self):
+ # Creating an application credential requires a project ID in the
+ # token, therefore system-scoped users cannot create app creds, so skip
+ # check for deleting user's own app creds
+
+ # delete other user's app cred
+ user_app_cred_client = \
+ self.test_user_client.application_credentials_client
+ app_cred = user_app_cred_client.create_application_credential(
+ user_id=self.test_user_id, **self.app_cred()
+ )['application_credential']
+ self.do_request(
+ 'delete_application_credential',
+ expected_status=204,
+ user_id=self.test_user_id,
+ application_credential_id=app_cred['id'])
+
+ # delete app cred that does not exist
+ self.do_request(
+ 'delete_application_credential',
+ expected_status=exceptions.NotFound,
+ user_id=self.test_user_id,
+ application_credential_id=data_utils.rand_uuid_hex())
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_delete_application_credential(self):
+ # Creating an application credential requires a project ID in the
+ # token, therefore system-scoped users cannot create app creds, so skip
+ # check for deleting user's own app creds
+
+ # delete other user's app cred
+ user_app_cred_client = \
+ self.test_user_client.application_credentials_client
+ app_cred = user_app_cred_client.create_application_credential(
+ user_id=self.test_user_id, **self.app_cred()
+ )['application_credential']
+ self.addCleanup(
+ user_app_cred_client.delete_application_credential,
+ self.test_user_id,
+ app_cred['id'])
+ self.do_request(
+ 'delete_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_id,
+ application_credential_id=app_cred['id'])
+
+ # delete app cred that does not exist
+ self.do_request(
+ 'delete_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_id,
+ application_credential_id=data_utils.rand_uuid_hex())
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(
+ IdentityV3RbacApplicationCredentialTest, base.BaseIdentityTest):
+
+ # Domain admins cannot create their own app creds (app creds can only be
+ # scoped to projects) and domain admins have no special privileges over the
+ # app creds own by users in their domains.
+
+ credentials = ['domain_admin', 'system_admin']
+
+ @classmethod
+ def setup_clients(cls):
+ super(DomainAdminTests, cls).setup_clients()
+ own_domain_id = cls.persona.credentials.domain_id
+ cls.test_client_1, cls.test_user_1 = cls.setup_user_client(
+ domain_id=own_domain_id)
+
+ def setUp(self):
+ super(DomainAdminTests, self).setUp()
+ self.other_domain_id = self.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.addCleanup(self.admin_client.domains_client.delete_domain,
+ self.other_domain_id)
+ self.addCleanup(self.admin_client.domains_client.update_domain,
+ domain_id=self.other_domain_id, enabled=False)
+ self.test_client_2, self.test_user_2 = self.setup_user_client(
+ domain_id=self.other_domain_id)
+ client = self.test_client_1.application_credentials_client
+ self.app_cred_1 = client.create_application_credential(
+ user_id=self.test_user_1, **self.app_cred()
+ )['application_credential']
+ self.addCleanup(
+ client.delete_application_credential,
+ self.test_user_1,
+ self.app_cred_1['id'])
+ client = self.test_client_2.application_credentials_client
+ self.app_cred_2 = client.create_application_credential(
+ user_id=self.test_user_2, **self.app_cred()
+ )['application_credential']
+ self.addCleanup(
+ client.delete_application_credential,
+ self.test_user_2,
+ self.app_cred_2['id'])
+
+ def test_identity_create_application_credential(self):
+ # Creating an application credential requires a project ID in the
+ # token, therefore system-scoped users cannot create app creds.
+ raise self.skipException(
+ "Skipping identity:create_application_credential test for "
+ "domain user")
+
+ def test_identity_get_application_credential(self):
+ # Creating an application credential requires a project ID in the
+ # token, therefore domain-scoped users cannot create app creds, so skip
+ # check for showing user's own app creds
+
+ # accessing application credentials should be forbidden no matter
+ # whether the owner is in the domain or outside of it
+
+ # retrieve app cred from user in own domain
+ self.do_request(
+ 'show_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1,
+ application_credential_id=self.app_cred_1['id'])
+
+ # retrieve app cred from user in other domain
+ self.do_request(
+ 'show_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2,
+ application_credential_id=self.app_cred_2['id'])
+
+ # retrieve app cred that does not exist
+ self.do_request(
+ 'show_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1,
+ application_credential_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_application_credentials(self):
+ # Creating an application credential requires a project ID in the
+ # token, therefore domain-scoped users cannot create app creds, so skip
+ # check for listing user's own app creds
+
+ # listing application credentials should be forbidden no matter
+ # whether the owner is in the domain or outside of it
+
+ # list app creds from user in own domain
+ self.do_request(
+ 'list_application_credentials',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1)
+
+ # list app creds from user in other domain
+ self.do_request(
+ 'list_application_credentials',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2)
+
+ def test_identity_delete_application_credential(self):
+ # Creating an application credential requires a project ID in the
+ # token, therefore domain-scoped users cannot create app creds, so skip
+ # check for deleting user's own app creds
+
+ # deleting application credentials should be forbidden no matter
+ # whether the owner is in the domain or outside of it
+
+ # delete app cred from user in own domain
+ self.do_request(
+ 'delete_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1,
+ application_credential_id=self.app_cred_1['id'])
+
+ # delete app cred from user in other domain
+ self.do_request(
+ 'delete_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2,
+ application_credential_id=self.app_cred_2['id'])
+
+ # delete app cred that does not exist
+ self.do_request(
+ 'delete_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1,
+ application_credential_id=data_utils.rand_uuid_hex())
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainAdminTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(IdentityV3RbacApplicationCredentialTest,
+ base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+ @classmethod
+ def setup_clients(cls):
+ super(ProjectAdminTests, cls).setup_clients()
+ cls.test_user_client, cls.test_user_id = cls.setup_user_client()
+
+ def test_identity_create_application_credential(self):
+ # user can create their own app cred
+ user_id = self.persona.credentials.user_id
+ resp = self.do_request(
+ 'create_application_credential',
+ expected_status=201,
+ user_id=user_id,
+ **self.app_cred())['application_credential']
+ self.addCleanup(
+ self.client.delete_application_credential,
+ user_id, resp['id'])
+
+ # user cannot create app cred for another user
+ user_id = self.test_user_id
+ self.do_request(
+ 'create_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=user_id,
+ **self.app_cred())
+
+ def test_identity_get_application_credential(self):
+ # user can retrieve their own app cred
+ user_id = self.persona.credentials.user_id
+ app_cred = self.client.create_application_credential(
+ user_id=user_id, **self.app_cred())['application_credential']
+ self.addCleanup(
+ self.client.delete_application_credential,
+ user_id=user_id, application_credential_id=app_cred['id'])
+ self.do_request(
+ 'show_application_credential',
+ user_id=user_id, application_credential_id=app_cred['id'])
+
+ # retrieving non-existent app cred for self should return 404
+ self.do_request(
+ 'show_application_credential',
+ expected_status=exceptions.NotFound,
+ user_id=user_id,
+ application_credential_id=data_utils.rand_uuid_hex())
+
+ # user cannot retrieve another user's app cred by using the victim's
+ # user ID in the request or by trying to bypass the user ownership
+ # check by crafting a path the the attacker's user ID
+ user_id = self.test_user_id
+ client = self.test_user_client.application_credentials_client
+ app_cred = client.create_application_credential(
+ user_id=user_id, **self.app_cred())['application_credential']
+ self.addCleanup(
+ client.delete_application_credential,
+ user_id=user_id, application_credential_id=app_cred['id'])
+ self.do_request(
+ 'show_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.persona.credentials.user_id,
+ application_credential_id=app_cred['id'])
+ self.do_request(
+ 'show_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=user_id, application_credential_id=app_cred['id'])
+
+ # retrieving non-existent app cred for another user should return 403
+ self.do_request(
+ 'show_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=user_id,
+ application_credential_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_application_credentials(self):
+ # user can list their own app creds
+ user_id = self.persona.credentials.user_id
+ app_cred = self.client.create_application_credential(
+ user_id=user_id, **self.app_cred())['application_credential']
+ self.addCleanup(
+ self.client.delete_application_credential,
+ user_id=user_id, application_credential_id=app_cred['id'])
+ self.do_request(
+ 'list_application_credentials', user_id=user_id)
+
+ # user cannot list another user's app creds
+ user_id = self.test_user_id
+ client = self.test_user_client.application_credentials_client
+ app_cred = client.create_application_credential(
+ user_id=user_id, **self.app_cred())['application_credential']
+ self.addCleanup(
+ client.delete_application_credential,
+ user_id=user_id, application_credential_id=app_cred['id'])
+ self.do_request(
+ 'list_application_credentials',
+ expected_status=exceptions.Forbidden, user_id=user_id)
+
+ def test_identity_delete_application_credential(self):
+ # user can delete their own app cred
+ user_id = self.persona.credentials.user_id
+ app_cred = self.client.create_application_credential(
+ user_id=user_id, **self.app_cred())['application_credential']
+ self.do_request(
+ 'delete_application_credential',
+ expected_status=204,
+ user_id=user_id, application_credential_id=app_cred['id'])
+
+ # deleting non-existent app cred for self should return 404
+ self.do_request(
+ 'delete_application_credential',
+ expected_status=exceptions.NotFound,
+ user_id=user_id,
+ application_credential_id=data_utils.rand_uuid_hex())
+
+ # user cannot delete another user's app cred by using the victim's
+ # user ID in the request or by trying to bypass the user ownership
+ # check by crafting a path the the attacker's user ID
+ user_id = self.test_user_id
+ client = self.test_user_client.application_credentials_client
+ app_cred = client.create_application_credential(
+ user_id=user_id, **self.app_cred())['application_credential']
+ self.addCleanup(
+ client.delete_application_credential,
+ user_id=user_id, application_credential_id=app_cred['id'])
+ self.do_request(
+ 'delete_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.persona.credentials.user_id,
+ application_credential_id=app_cred['id'])
+ self.do_request(
+ 'delete_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=user_id, application_credential_id=app_cred['id'])
+
+ # deleting non-existent app cred for another user should return 403
+ self.do_request(
+ 'delete_application_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=user_id,
+ application_credential_id=data_utils.rand_uuid_hex())
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_consumer.py b/keystone_tempest_plugin/tests/rbac/v3/test_consumer.py
new file mode 100644
index 0000000..b7dbb95
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_consumer.py
@@ -0,0 +1,196 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacOauth1ConsumerTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacOauth1ConsumerTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.oauth_consumers_client
+ cls.admin_client = cls.os_system_admin.oauth_consumers_client
+
+ def consumer(self):
+ return {"description": data_utils.arbitrary_string()}
+
+ @abc.abstractmethod
+ def test_identity_create_consumer(self):
+ """Test identity:create_consumer policy.
+
+ This test must check:
+ * whether the persona can create a consumer
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_consumer(self):
+ """Test identity:get_consumer policy.
+
+ This test must check:
+ * whether the persona can get a consumer
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_consumers(self):
+ """Test identity:list_consumers policy.
+
+ This test must check:
+ * whether the persona can list all consumers
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_consumer(self):
+ """Test identity:update_consumer policy.
+
+ This test must check:
+ * whether the persona can update a
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_consumer(self):
+ """Test identity:delete_consumer policy.
+
+ This test must check
+ * whether the persona can delete a consumer
+ """
+ pass
+
+
+class SystemAdminTests(
+ IdentityV3RbacOauth1ConsumerTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_consumer(self):
+ resp = self.do_request('create_consumer',
+ expected_status=201,
+ **self.consumer())
+ self.addCleanup(self.client.delete_consumer,
+ resp['consumer']['id'])
+
+ def test_identity_get_consumer(self):
+ consumer = self.admin_client.create_consumer(
+ **self.consumer())['consumer']
+ self.addCleanup(self.admin_client.delete_consumer, consumer['id'])
+ resp = self.do_request('show_consumer', consumer_id=consumer['id'])
+ self.assertEqual(resp['consumer']['id'], consumer['id'])
+
+ def test_identity_list_consumers(self):
+ consumer = self.admin_client.create_consumer(
+ **self.consumer())['consumer']
+ self.addCleanup(self.admin_client.delete_consumer, consumer['id'])
+ resp = self.do_request('list_consumers')
+ self.assertIn(consumer['id'], set(c['id'] for c in resp['consumers']))
+
+ def test_identity_update_consumer(self):
+ consumer = self.client.create_consumer(**self.consumer())['consumer']
+ self.addCleanup(self.client.delete_consumer, consumer['id'])
+ self.do_request('update_consumer',
+ consumer_id=consumer['id'],
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_consumer(self):
+ consumer = self.client.create_consumer(**self.consumer())['consumer']
+ self.do_request('delete_consumer',
+ expected_status=204,
+ consumer_id=consumer['id'])
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_consumer(self):
+ self.do_request('create_consumer',
+ expected_status=exceptions.Forbidden,
+ **self.consumer())
+
+ def test_identity_update_consumer(self):
+ consumer = self.admin_client.create_consumer(
+ **self.consumer())['consumer']
+ self.addCleanup(self.admin_client.delete_consumer, consumer['id'])
+ self.do_request('update_consumer',
+ expected_status=exceptions.Forbidden,
+ consumer_id=consumer['id'],
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_consumer(self):
+ consumer = self.admin_client.create_consumer(
+ **self.consumer())['consumer']
+ self.do_request('delete_consumer',
+ expected_status=exceptions.Forbidden,
+ consumer_id=consumer['id'])
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemMemberTests):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_consumer(self):
+ consumer = self.admin_client.create_consumer(
+ **self.consumer())['consumer']
+ self.addCleanup(self.admin_client.delete_consumer, consumer['id'])
+ self.do_request('show_consumer',
+ expected_status=exceptions.Forbidden,
+ consumer_id=consumer['id'])
+
+ def test_identity_list_consumers(self):
+ consumer = self.admin_client.create_consumer(
+ **self.consumer())['consumer']
+ self.addCleanup(self.admin_client.delete_consumer, consumer['id'])
+ self.do_request('list_consumers',
+ expected_status=exceptions.Forbidden)
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_credential.py b/keystone_tempest_plugin/tests/rbac/v3/test_credential.py
new file mode 100644
index 0000000..5b1bee2
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_credential.py
@@ -0,0 +1,490 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest import clients
+from tempest.lib import auth
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacCredentialTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacCredentialTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.credentials_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_credentials_client = cls.admin_client.credentials_client
+
+ # personas in own or other domains
+ own_domain_id = cls.persona.credentials.domain_id
+ cls.test_client_1, cls.test_user_1 = cls.setup_user_client(
+ domain_id=own_domain_id)
+ cls.other_domain_id = cls.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.delete_domain, cls.other_domain_id)
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.update_domain,
+ domain_id=cls.other_domain_id, enabled=False)
+ cls.test_client_2, cls.test_user_2 = cls.setup_user_client(
+ domain_id=cls.other_domain_id)
+
+ @classmethod
+ def setup_user_client(cls, domain_id=None):
+ """Set up project user with its own client.
+
+ This is to enable the project user to create its own credential.
+
+ Returns a client object and the user's ID.
+ """
+ user_dict = {
+ 'name': data_utils.rand_name('user'),
+ 'password': data_utils.rand_password(),
+ }
+ if domain_id:
+ user_dict['domain_id'] = domain_id
+ user_id = cls.admin_client.users_v3_client.create_user(
+ **user_dict)['user']['id']
+
+ def try_cleanup_user():
+ # if domain is cleaned up first, user will already be deleted
+ try:
+ cls.admin_client.users_v3_client.delete_user(user_id)
+ except exceptions.NotFound:
+ pass
+
+ cls.addClassResourceCleanup(try_cleanup_user)
+ project_id = cls.admin_client.projects_client.create_project(
+ data_utils.rand_name())['project']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.projects_client.delete_project, project_id)
+ member_role_id = cls.admin_client.roles_v3_client.list_roles(
+ name='member')['roles'][0]['id']
+ cls.admin_client.roles_v3_client.create_user_role_on_project(
+ project_id, user_id, member_role_id)
+ creds = auth.KeystoneV3Credentials(
+ user_id=user_id,
+ password=user_dict['password'],
+ project_id=project_id)
+ auth_provider = clients.get_auth_provider(creds)
+ creds = auth_provider.fill_credentials()
+ client = clients.Manager(credentials=creds)
+ return client, user_id
+
+ def credential(self, user_id):
+ cred = {
+ 'blob': data_utils.rand_uuid_hex(),
+ 'type': data_utils.rand_uuid_hex(),
+ 'user_id': user_id,
+ }
+ return cred
+
+ @abc.abstractmethod
+ def test_identity_create_credential(self):
+ """Test identity:create_credential policy.
+
+ This test must check:
+ * whether the persona can create a credential for themself
+ * whether the persona can create acredential for another user in
+ their own domain
+ * whether the persona can create acredential for another user in
+ another domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_credential(self):
+ """Test identity:get_credential policy.
+
+ This test must check:
+ * whether the persona can get their own credential
+ * whether the persona can get a credential for a user in another
+ domain
+ * whether the persona can get a credential for a user in their own
+ domain
+ * whether the persona can get a credential that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_credentials(self):
+ """Test identity:list_credentials policy.
+
+ This test must check:
+ * whether the persona can list all credentials for themself
+ * whether the persona can list credentials for a user in their own
+ domain
+ * whether the persona can list credentials for a user in another
+ domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_credential(self):
+ """Test identity:update_credential policy.
+
+ This test must check:
+ * whether the persona can update their own credential
+ * whether the persona can update a credential for a user in another
+ domain
+ * whether the persona can update a credential for a user in their own
+ domain
+ * whether the persona can update a credential that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_credential(self):
+ """Test identity:delete_credential policy.
+
+ This test must check
+ * whether the persona can delete their own credential
+ * whether the persona can delete a credential for a user in another
+ domain
+ * whether the persona can delete a credential for a user in their own
+ domain
+ * whether the persona can delete a credential that does not exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacCredentialTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_credential(self):
+ # user can create their own credential
+ user_id = self.persona.credentials.user_id
+ resp = self.do_request(
+ 'create_credential',
+ expected_status=201,
+ **self.credential(user_id=user_id))['credential']
+ self.addCleanup(self.client.delete_credential, resp['id'])
+ # user can create credential for other user in own domain
+ resp = self.do_request(
+ 'create_credential',
+ expected_status=201,
+ **self.credential(user_id=self.test_user_1))['credential']
+ self.addCleanup(self.client.delete_credential, resp['id'])
+ # user can create credential for other user in other domain
+ resp = self.do_request(
+ 'create_credential',
+ expected_status=201,
+ **self.credential(user_id=self.test_user_2))['credential']
+ self.addCleanup(self.client.delete_credential, resp['id'])
+
+ def test_identity_get_credential(self):
+ # user can get their own credential, credential for user in own domain,
+ # or credential for user in other domain
+ user_id = self.persona.credentials.user_id
+ for u in [user_id, self.test_user_1, self.test_user_2]:
+ cred = self.admin_credentials_client.create_credential(
+ **self.credential(user_id=u))['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, cred['id'])
+ self.do_request('show_credential', credential_id=cred['id'])
+ # non-existent credential is Not Found
+ self.do_request(
+ 'show_credential',
+ expected_status=exceptions.NotFound,
+ credential_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_credentials(self):
+ # user can list their own credentials, credentials for user in own
+ # domain, or credentials for user in other domain
+ user_id = self.persona.credentials.user_id
+ for u in [user_id, self.test_user_1, self.test_user_2]:
+ cred = self.admin_credentials_client.create_credential(
+ **self.credential(user_id=u))['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, cred['id'])
+ resp = self.do_request('list_credentials')['credentials']
+ self.assertIn(cred['id'], [c['id'] for c in resp])
+
+ def test_identity_update_credential(self):
+ # user can update their own credential, credential for user in own
+ # domain, or credential for user in other domain
+ user_id = self.persona.credentials.user_id
+ for u in [user_id, self.test_user_1, self.test_user_2]:
+ cred = self.credential(user_id=u)
+ resp = self.client.create_credential(**cred)['credential']
+ self.addCleanup(self.client.delete_credential, resp['id'])
+ cred['blob'] = data_utils.rand_uuid_hex()
+ self.do_request(
+ 'update_credential', credential_id=resp['id'], **cred)
+ # non-existent credential is Not Found
+ self.do_request(
+ 'update_credential',
+ expected_status=exceptions.NotFound,
+ credential_id=data_utils.rand_uuid_hex(),
+ **self.credential(user_id=self.test_user_2))
+
+ def test_identity_delete_credential(self):
+ # user can delete their own credential, credential for user in own
+ # domain, or credential for user in other domain
+ user_id = self.persona.credentials.user_id
+ for u in [user_id, self.test_user_1, self.test_user_2]:
+ cred = self.credential(user_id=u)
+ resp = self.client.create_credential(**cred)['credential']
+ self.do_request(
+ 'delete_credential',
+ expected_status=204,
+ credential_id=resp['id'])
+ # non-existent credential is Not Found
+ self.do_request(
+ 'delete_credential',
+ expected_status=exceptions.NotFound,
+ credential_id=data_utils.rand_uuid_hex())
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_credential(self):
+ # user can create their own credential
+ user_id = self.persona.credentials.user_id
+ resp = self.do_request(
+ 'create_credential',
+ expected_status=201,
+ **self.credential(user_id=user_id))['credential']
+ self.addCleanup(self.client.delete_credential, resp['id'])
+ # user cannot create credential for other user
+ for u in [self.test_user_1, self.test_user_2]:
+ self.do_request(
+ 'create_credential',
+ expected_status=exceptions.Forbidden,
+ **self.credential(user_id=u))
+
+ def test_identity_update_credential(self):
+ # user can update their own credential
+ user_id = self.persona.credentials.user_id
+ cred = self.credential(user_id=user_id)
+ resp = self.admin_credentials_client.create_credential(
+ **cred)['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, resp['id'])
+ cred['blob'] = data_utils.rand_uuid_hex()
+ self.do_request(
+ 'update_credential',
+ credential_id=resp['id'], **cred)
+ # user cannot update credential for other user
+ for u in [self.test_user_1, self.test_user_2]:
+ cred = self.credential(user_id=u)
+ resp = self.admin_credentials_client.create_credential(
+ **cred)['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, resp['id'])
+ cred['blob'] = data_utils.rand_uuid_hex()
+ self.do_request(
+ 'update_credential',
+ expected_status=exceptions.Forbidden,
+ credential_id=resp['id'], **cred)
+ # non-existent credential is Forbidden
+ self.do_request(
+ 'update_credential',
+ expected_status=exceptions.Forbidden,
+ credential_id=data_utils.rand_uuid_hex(),
+ **self.credential(user_id=self.test_user_2))
+
+ def test_identity_delete_credential(self):
+ # user can delete their own credential
+ user_id = self.persona.credentials.user_id
+ cred = self.credential(user_id=user_id)
+ resp = self.admin_credentials_client.create_credential(
+ **cred)['credential']
+ self.do_request(
+ 'delete_credential',
+ expected_status=204,
+ credential_id=resp['id'])
+ # user cannot delete credential for other user
+ for u in [self.test_user_1, self.test_user_2]:
+ cred = self.credential(user_id=u)
+ resp = self.admin_credentials_client.create_credential(
+ **cred)['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, resp['id'])
+ self.do_request(
+ 'delete_credential',
+ expected_status=exceptions.Forbidden,
+ credential_id=resp['id'])
+ # non-existent credential is Forbidden
+ self.do_request(
+ 'delete_credential',
+ expected_status=exceptions.Forbidden,
+ credential_id=data_utils.rand_uuid_hex())
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(IdentityV3RbacCredentialTest, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_create_credential(self):
+ # domain admins cannot create credentials
+ user_id = self.persona.credentials.user_id
+ for u in [user_id, self.test_user_1, self.test_user_2]:
+ self.do_request(
+ 'create_credential',
+ expected_status=exceptions.Forbidden,
+ **self.credential(user_id=u))
+
+ def test_identity_get_credential(self):
+ # domain admins cannot get credentials
+ user_id = self.persona.credentials.user_id
+ for u in [user_id, self.test_user_1, self.test_user_2]:
+ cred = self.admin_credentials_client.create_credential(
+ **self.credential(user_id=u))['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, cred['id'])
+ self.do_request(
+ 'show_credential',
+ expected_status=exceptions.Forbidden,
+ credential_id=cred['id'])
+ # non-existent credential is Forbidden
+ self.do_request(
+ 'show_credential',
+ expected_status=exceptions.Forbidden,
+ credential_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_credentials(self):
+ # domain admins cannot list credentials
+ user_id = self.persona.credentials.user_id
+ for u in [user_id, self.test_user_1, self.test_user_2]:
+ cred = self.admin_credentials_client.create_credential(
+ **self.credential(user_id=u))['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, cred['id'])
+ self.do_request(
+ 'list_credentials',
+ expected_status=exceptions.Forbidden)
+
+ def test_identity_update_credential(self):
+ # domain admins cannot update credentials
+ user_id = self.persona.credentials.user_id
+ for u in [user_id, self.test_user_1, self.test_user_2]:
+ cred = self.credential(user_id=u)
+ resp = self.admin_credentials_client.create_credential(
+ **cred)['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, resp['id'])
+ cred['blob'] = data_utils.rand_uuid_hex()
+ self.do_request(
+ 'update_credential',
+ expected_status=exceptions.Forbidden,
+ credential_id=resp['id'], **cred)
+ # non-existent credential is Forbidden
+ self.do_request(
+ 'update_credential',
+ expected_status=exceptions.Forbidden,
+ credential_id=data_utils.rand_uuid_hex(),
+ **self.credential(user_id=user_id))
+
+ def test_identity_delete_credential(self):
+ # domain admins cannot delete credentials
+ user_id = self.persona.credentials.user_id
+ for u in [user_id, self.test_user_1, self.test_user_2]:
+ cred = self.credential(user_id=u)
+ resp = self.admin_credentials_client.create_credential(
+ **cred)['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, resp['id'])
+ self.do_request(
+ 'delete_credential',
+ expected_status=exceptions.Forbidden,
+ credential_id=resp['id'])
+ # non-existent credential is Forbidden
+ self.do_request(
+ 'delete_credential',
+ expected_status=exceptions.Forbidden,
+ credential_id=data_utils.rand_uuid_hex())
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainAdminTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(SystemReaderTests):
+
+ credentials = ['project_admin', 'system_admin']
+
+ def test_identity_get_credential(self):
+ # user can get their own credential
+ user_id = self.persona.credentials.user_id
+ cred = self.admin_credentials_client.create_credential(
+ **self.credential(user_id=user_id))['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, cred['id'])
+ self.do_request('show_credential', credential_id=cred['id'])
+ # user cannot get credential for another user
+ for u in [self.test_user_1, self.test_user_2]:
+ cred = self.admin_credentials_client.create_credential(
+ **self.credential(user_id=u))['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, cred['id'])
+ self.do_request(
+ 'show_credential',
+ expected_status=exceptions.Forbidden,
+ credential_id=cred['id'])
+ # non-existent credential is Forbidden
+ self.do_request(
+ 'show_credential',
+ expected_status=exceptions.Forbidden,
+ credential_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_credentials(self):
+ # user can list their own credentials
+ user_id = self.persona.credentials.user_id
+ cred = self.admin_credentials_client.create_credential(
+ **self.credential(user_id=user_id))['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, cred['id'])
+ resp = self.do_request('list_credentials')['credentials']
+ self.assertIn(cred['id'], [c['id'] for c in resp])
+ # user cannot list credentials for other users
+ for u in [self.test_user_1, self.test_user_2]:
+ cred = self.admin_credentials_client.create_credential(
+ **self.credential(user_id=u))['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_credential, cred['id'])
+ resp = self.do_request('list_credentials')['credentials']
+ self.assertNotIn(cred['id'], [c['id'] for c in resp])
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_domain.py b/keystone_tempest_plugin/tests/rbac/v3/test_domain.py
new file mode 100644
index 0000000..13f0b71
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_domain.py
@@ -0,0 +1,223 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacDomainTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacDomainTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.domains_client
+ admin_client = cls.os_system_admin
+ cls.admin_domains_client = admin_client.domains_client
+
+ @abc.abstractmethod
+ def test_identity_create_domain(self):
+ """Test identity:create_domain policy.
+
+ This test must check:
+ * whether the persona can create a domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_domain(self):
+ """Test identity:get_domain policy.
+
+ This test must check:
+ * whether the persona can get a domain
+ * whether the persona can get a domain that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_domains(self):
+ """Test identity:list_domains policy.
+
+ This test must check:
+ * whether the persona can list all domains
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_domain(self):
+ """Test identity:update_domain policy.
+
+ This test must check:
+ * whether the persona can update a domain
+ * whether the persona can update a domain that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_domain(self):
+ """Test identity:delete_domain policy.
+
+ This test must check
+ * whether the persona can delete a domain
+ * whether the persona can delete a domain that does not exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacDomainTests, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_domain(self):
+ domain_id = self.do_request(
+ 'create_domain', expected_status=201, name=data_utils.rand_name()
+ )['domain']['id']
+ self.addCleanup(self.admin_domains_client.delete_domain, domain_id)
+ self.addCleanup(self.admin_domains_client.update_domain,
+ domain_id=domain_id, enabled=False)
+
+ def test_identity_get_domain(self):
+ domain_id = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.addCleanup(self.admin_domains_client.delete_domain, domain_id)
+ self.addCleanup(self.admin_domains_client.update_domain,
+ domain_id=domain_id, enabled=False)
+ self.do_request('show_domain', domain_id=domain_id)
+ # user gets a 404 for nonexistent domain
+ self.do_request('show_domain', expected_status=exceptions.NotFound,
+ domain_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_domains(self):
+ domain_id = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.addCleanup(self.admin_domains_client.delete_domain, domain_id)
+ self.addCleanup(self.admin_domains_client.update_domain,
+ domain_id=domain_id, enabled=False)
+ resp = self.do_request('list_domains')
+ self.assertIn(domain_id, [d['id'] for d in resp['domains']])
+
+ def test_identity_update_domain(self):
+ domain_id = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.addCleanup(self.admin_domains_client.delete_domain, domain_id)
+ self.addCleanup(self.admin_domains_client.update_domain,
+ domain_id=domain_id, enabled=False)
+ self.do_request('update_domain',
+ domain_id=domain_id,
+ description=data_utils.arbitrary_string())
+ # user gets a 404 for nonexistent domain
+ self.do_request('update_domain', expected_status=exceptions.NotFound,
+ domain_id=data_utils.rand_uuid_hex())
+
+ def test_identity_delete_domain(self):
+ domain_id = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.do_request('update_domain',
+ domain_id=domain_id,
+ enabled=False)
+ self.do_request('delete_domain', expected_status=204,
+ domain_id=domain_id)
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_domain(self):
+ self.do_request('create_domain', expected_status=exceptions.Forbidden,
+ name=data_utils.rand_name())
+
+ def test_identity_update_domain(self):
+ domain_id = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.addCleanup(self.admin_domains_client.delete_domain, domain_id)
+ self.addCleanup(self.admin_domains_client.update_domain,
+ domain_id=domain_id, enabled=False)
+ self.do_request('update_domain', expected_status=exceptions.Forbidden,
+ domain_id=domain_id,
+ description=data_utils.arbitrary_string())
+ # user gets a 404 for nonexistent domain
+ self.do_request('update_domain', expected_status=exceptions.NotFound,
+ domain_id=data_utils.rand_uuid_hex())
+
+ def test_identity_delete_domain(self):
+ domain_id = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.addCleanup(self.admin_domains_client.delete_domain, domain_id)
+ self.addCleanup(self.admin_domains_client.update_domain,
+ domain_id=domain_id, enabled=False)
+ self.do_request('delete_domain', expected_status=exceptions.Forbidden,
+ domain_id=domain_id)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_domain(self):
+ domain_id = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.addCleanup(self.admin_domains_client.delete_domain, domain_id)
+ self.addCleanup(self.admin_domains_client.update_domain,
+ domain_id=domain_id, enabled=False)
+ self.do_request('show_domain', expected_status=exceptions.Forbidden,
+ domain_id=domain_id)
+ # user gets a 403 for nonexistent domain
+ self.do_request('show_domain', expected_status=exceptions.Forbidden,
+ domain_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_domains(self):
+ domain_id = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.addCleanup(self.admin_domains_client.delete_domain, domain_id)
+ self.addCleanup(self.admin_domains_client.update_domain,
+ domain_id=domain_id, enabled=False)
+ self.do_request('list_domains',
+ expected_status=exceptions.Forbidden)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_domain_config.py b/keystone_tempest_plugin/tests/rbac/v3/test_domain_config.py
new file mode 100644
index 0000000..8f1fdbf
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_domain_config.py
@@ -0,0 +1,381 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacDomainConfigTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacDomainConfigTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.domain_config_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_domain_config_client = cls.admin_client.domain_config_client
+
+ @classmethod
+ def resource_setup(cls):
+ super(IdentityV3RbacDomainConfigTest, cls).resource_setup()
+ cls.domain_id = cls.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name('domain'))['domain']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.delete_domain,
+ cls.domain_id)
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.update_domain,
+ cls.domain_id,
+ enabled=False)
+
+ def domain_config(self, **kwargs):
+ ref = {
+ "identity": {
+ "driver": "ldap"
+ },
+ "ldap": {
+ "url": "ldap://myldap.com:389/",
+ "user_tree_dn": "ou=Users,dc=my_new_root,dc=org"
+ }
+ }
+ ref.update(kwargs)
+ return ref
+
+ @abc.abstractmethod
+ def test_identity_create_domain_config(self):
+ """Test identity:create_domain_config policy.
+
+ This test must check:
+ * whether the persona can create a domain config for a valid domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_domain_config(self):
+ """Test identity:get_domain_config policy.
+
+ This test must check:
+ * whether the persona can get a domain config
+ * whether the persona can get an option group for a domain config
+ * whether the persona can get an option from a group in a domain
+ config
+ * whether the persona can get a config for an invalid domain
+ * whether the persona can get a config that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_domain_config_default(self):
+ """Test identity:get_domain_config_default policy.
+
+ * whether the persona can get the default config
+ * whether the persona can get the default config for an option group
+ * whether the persona can get the default value for an option
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_security_compliance_domain_config(self):
+ """Test identity:get_security_compliance_domain_config policy.
+
+ This test must check:
+ * whether the persona can get the security compliance configuration
+ for the default domain
+ * whether the persona can get an option from the security compliance
+ configuration for the default domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_domain_config(self):
+ """Test identity:update_domain_config policy.
+
+ This test must check:
+ * whether the persona can update the config for a domain
+ * whether the persona can update an option group config for a domain
+ * whether the persona can update an option in a domain config
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_domain_config(self):
+ """Test identity:delete_domain_config policy.
+
+ This test must check
+ * whether the persona can delete a domain config
+ * whether the persona can delete an option group within a domain
+ config
+ * whether the persona can delete an option within a domain config
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacDomainConfigTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_domain_config(self):
+ self.do_request(
+ 'create_domain_config',
+ expected_status=201,
+ domain_id=self.domain_id,
+ **self.domain_config())
+ self.addCleanup(
+ self.admin_domain_config_client.delete_domain_config,
+ self.domain_id)
+
+ def test_identity_get_domain_config(self):
+ # should be able to get domain config, group and individual options
+ self.admin_domain_config_client.create_domain_config(
+ self.domain_id, **self.domain_config())
+ self.addCleanup(
+ self.admin_domain_config_client.delete_domain_config,
+ self.domain_id)
+ self.do_request(
+ 'show_domain_config',
+ domain_id=self.domain_id)
+ self.do_request(
+ 'show_domain_group_config',
+ domain_id=self.domain_id,
+ group='ldap')
+ self.do_request(
+ 'show_domain_group_option_config',
+ domain_id=self.domain_id,
+ group='ldap',
+ option='url')
+ # should get Not Found for invalid domain
+ self.do_request(
+ 'show_domain_config',
+ expected_status=exceptions.NotFound,
+ domain_id=data_utils.rand_uuid_hex())
+ # should get Not Found for nonexistent config for valid domain
+ domain = self.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name('domain'))['domain']['id']
+ self.addCleanup(self.admin_client.domains_client.delete_domain, domain)
+ self.addCleanup(
+ self.admin_client.domains_client.update_domain,
+ domain, enabled=False)
+ self.do_request(
+ 'show_domain_config',
+ expected_status=exceptions.NotFound,
+ domain_id=domain)
+
+ def test_identity_get_domain_config_default(self):
+ self.do_request('show_default_config_settings')
+ self.do_request('show_default_group_config', group='ldap')
+ self.do_request(
+ 'show_default_group_option', group='ldap', option='url')
+
+ def test_identity_get_security_compliance_domain_config(self):
+ self.do_request(
+ 'show_domain_group_config',
+ domain_id='default',
+ group='security_compliance')
+ self.do_request(
+ 'show_domain_group_option_config',
+ domain_id='default',
+ group='security_compliance',
+ option='password_regex_description')
+
+ def test_identity_update_domain_config(self):
+ self.admin_domain_config_client.create_domain_config(
+ self.domain_id, **self.domain_config())
+ self.addCleanup(
+ self.admin_domain_config_client.delete_domain_config,
+ self.domain_id)
+ self.do_request(
+ 'update_domain_group_config',
+ domain_id=self.domain_id,
+ group='ldap',
+ ldap={'url': 'ldaps://myldap.com:636/',
+ 'user_tree_dn': 'ou=People,dc=my_new_root,dc=org'})
+ self.do_request(
+ 'update_domain_group_option_config',
+ domain_id=self.domain_id,
+ group='ldap',
+ option='user_tree_dn',
+ user_tree_dn='ou=Aliens,dc=my_new_root,dc=org')
+ # test changing the entire config last
+ self.do_request(
+ 'update_domain_config',
+ domain_id=self.domain_id,
+ identity={"driver": "sql"})
+
+ def test_identity_delete_domain_config(self):
+ self.admin_domain_config_client.create_domain_config(
+ self.domain_id, **self.domain_config())
+ self.do_request(
+ 'delete_domain_group_option_config',
+ expected_status=204,
+ domain_id=self.domain_id,
+ group='ldap',
+ option='user_tree_dn')
+ self.do_request(
+ 'delete_domain_group_config',
+ expected_status=204,
+ domain_id=self.domain_id,
+ group='ldap')
+ self.do_request(
+ 'delete_domain_config',
+ expected_status=204,
+ domain_id=self.domain_id)
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_domain_config(self):
+ self.do_request(
+ 'create_domain_config',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.domain_id,
+ **self.domain_config())
+
+ def test_identity_update_domain_config(self):
+ self.admin_domain_config_client.create_domain_config(
+ self.domain_id, **self.domain_config())
+ self.addCleanup(
+ self.admin_domain_config_client.delete_domain_config,
+ self.domain_id)
+ self.do_request(
+ 'update_domain_group_config',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.domain_id,
+ group='ldap',
+ ldap={'url': 'ldaps://myldap.com:636/',
+ 'user_tree_dn': 'ou=People,dc=my_new_root,dc=org'})
+ self.do_request(
+ 'update_domain_group_option_config',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.domain_id,
+ group='ldap',
+ option='user_tree_dn',
+ user_tree_dn='ou=Aliens,dc=my_new_root,dc=org')
+ # test changing the entire config last
+ self.do_request(
+ 'update_domain_config',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.domain_id,
+ identity={"driver": "sql"})
+
+ def test_identity_delete_domain_config(self):
+ self.admin_domain_config_client.create_domain_config(
+ self.domain_id, **self.domain_config())
+ self.do_request(
+ 'delete_domain_group_option_config',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.domain_id,
+ group='ldap',
+ option='user_tree_dn')
+ self.do_request(
+ 'delete_domain_group_config',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.domain_id,
+ group='ldap')
+ self.do_request(
+ 'delete_domain_config',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.domain_id)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_domain_config(self):
+ # should not be able to get domain config, group and individual options
+ self.admin_domain_config_client.create_domain_config(
+ self.domain_id, **self.domain_config())
+ self.addCleanup(
+ self.admin_domain_config_client.delete_domain_config,
+ self.domain_id)
+ self.do_request(
+ 'show_domain_config',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.domain_id)
+ self.do_request(
+ 'show_domain_group_config',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.domain_id,
+ group='ldap')
+ self.do_request(
+ 'show_domain_group_option_config',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.domain_id,
+ group='ldap',
+ option='url')
+ # should get Forbidden for invalid domain
+ self.do_request(
+ 'show_domain_config',
+ expected_status=exceptions.Forbidden,
+ domain_id=data_utils.rand_uuid_hex())
+ # should get Forbidden for nonexistent config for valid domain
+ domain = self.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name('domain'))['domain']['id']
+ self.addCleanup(self.admin_client.domains_client.delete_domain, domain)
+ self.addCleanup(
+ self.admin_client.domains_client.update_domain,
+ domain, enabled=False)
+ self.do_request(
+ 'show_domain_config',
+ expected_status=exceptions.Forbidden,
+ domain_id=domain)
+
+ def test_identity_get_domain_config_default(self):
+ self.do_request(
+ 'show_default_config_settings',
+ expected_status=exceptions.Forbidden)
+ self.do_request(
+ 'show_default_group_config',
+ expected_status=exceptions.Forbidden, group='ldap')
+ self.do_request(
+ 'show_default_group_option',
+ expected_status=exceptions.Forbidden, group='ldap', option='url')
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainAdminTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_ec2_credential.py b/keystone_tempest_plugin/tests/rbac/v3/test_ec2_credential.py
new file mode 100644
index 0000000..6c7d19b
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_ec2_credential.py
@@ -0,0 +1,544 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest import clients
+from tempest.lib import auth
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacEc2CredentialTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacEc2CredentialTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.users_v3_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_credentials_client = cls.admin_client.users_v3_client
+
+ # personas in own or other domains
+ own_domain_id = cls.persona.credentials.domain_id
+ cls.test_client_1, cls.test_user_1, cls.test_project_1 = (
+ cls.setup_user_client(domain_id=own_domain_id))
+ cls.other_domain_id = cls.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.delete_domain, cls.other_domain_id)
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.update_domain,
+ domain_id=cls.other_domain_id, enabled=False)
+ cls.test_client_2, cls.test_user_2, cls.test_project_2 = (
+ cls.setup_user_client(domain_id=cls.other_domain_id))
+
+ @classmethod
+ def setup_user_client(cls, domain_id=None):
+ """Set up project user with its own client.
+
+ This is to enable the project user to create its own credential.
+
+ Returns a client object and the user's ID.
+ """
+ user_dict = {
+ 'name': data_utils.rand_name('user'),
+ 'password': data_utils.rand_password(),
+ }
+ if domain_id:
+ user_dict['domain_id'] = domain_id
+ user_id = cls.admin_client.users_v3_client.create_user(
+ **user_dict)['user']['id']
+
+ def try_cleanup_user():
+ # if domain is cleaned up first, user will already be deleted
+ try:
+ cls.admin_client.users_v3_client.delete_user(user_id)
+ except exceptions.NotFound:
+ pass
+
+ cls.addClassResourceCleanup(try_cleanup_user)
+ project_id = cls.admin_client.projects_client.create_project(
+ data_utils.rand_name())['project']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.projects_client.delete_project, project_id)
+ member_role_id = cls.admin_client.roles_v3_client.list_roles(
+ name='member')['roles'][0]['id']
+ cls.admin_client.roles_v3_client.create_user_role_on_project(
+ project_id, user_id, member_role_id)
+ creds = auth.KeystoneV3Credentials(
+ user_id=user_id,
+ password=user_dict['password'],
+ project_id=project_id)
+ auth_provider = clients.get_auth_provider(creds)
+ creds = auth_provider.fill_credentials()
+ client = clients.Manager(credentials=creds)
+ return client, user_id, project_id
+
+ def ec2_credential(self, project_id=None):
+ return {
+ 'tenant_id': project_id or self.project_id
+ }
+
+ @abc.abstractmethod
+ def test_identity_ec2_create_credential(self):
+ """Test identity:ec2_create_credential policy.
+
+ This test must check:
+ * whether the persona can create a credential for themself
+ * whether the persona can create acredential for another user in
+ their own domain
+ * whether the persona can create acredential for another user in
+ another domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_ec2_get_credential(self):
+ """Test identity:ec2_get_credential policy.
+
+ This test must check:
+ * whether the persona can get their own credential
+ * whether the persona can get a credential for a user in another
+ domain
+ * whether the persona can get a credential for a user in their own
+ domain
+ * whether the persona can get a credential that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_ec2_list_credentials(self):
+ """Test identity:list_credentials policy.
+
+ This test must check:
+ * whether the persona can list all credentials for themself
+ * whether the persona can list credentials for a user in their own
+ domain
+ * whether the persona can list credentials for a user in another
+ domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_ec2_delete_credential(self):
+ """Test identity:ec2_delete_credential policy.
+
+ This test must check
+ * whether the persona can delete their own credential
+ * whether the persona can delete a credential for a user in another
+ domain
+ * whether the persona can delete a credential for a user in their own
+ domain
+ * whether the persona can delete a credential that does not exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacEc2CredentialTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_ec2_create_credential(self):
+ # user can create their own credential
+ user_id = self.persona.credentials.user_id
+ resp = self.do_request(
+ 'create_user_ec2_credential',
+ expected_status=201,
+ user_id=user_id,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.addCleanup(self.client.delete_user_ec2_credential,
+ user_id=user_id, access=resp['access'])
+ # user can create credential for other user
+ resp = self.do_request(
+ 'create_user_ec2_credential',
+ expected_status=201,
+ user_id=self.test_user_2,
+ **self.ec2_credential(project_id=self.test_project_2)
+ )['credential']
+ self.addCleanup(self.client.delete_user_ec2_credential,
+ user_id=user_id, access=resp['access'])
+
+ def test_identity_ec2_get_credential(self):
+ # user can get their own credential
+ user_id = self.persona.credentials.user_id
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=user_id,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=user_id, access=cred['access'])
+ self.do_request('show_user_ec2_credential',
+ user_id=user_id, access=cred['access'])
+ # user can get credential for other user
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=self.test_user_2,
+ **self.ec2_credential(project_id=self.test_project_2)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=self.test_user_2, access=cred['access'])
+ self.do_request('show_user_ec2_credential',
+ user_id=self.test_user_2, access=cred['access'])
+ # non-existent credential is Not Found
+ self.do_request(
+ 'show_user_ec2_credential',
+ expected_status=exceptions.NotFound,
+ user_id=self.test_user_2,
+ access=data_utils.rand_uuid_hex())
+
+ def test_identity_ec2_list_credentials(self):
+ # user can list their own credentials
+ user_id = self.persona.credentials.user_id
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=user_id,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=user_id, access=cred['access'])
+ resp = self.do_request('list_user_ec2_credentials',
+ user_id=user_id)['credentials']
+ self.assertIn(cred['access'], [c['access'] for c in resp])
+ # user can list credentials for other user
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=self.test_user_2,
+ **self.ec2_credential(project_id=self.test_project_2)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=self.test_user_2, access=cred['access'])
+ resp = self.do_request('list_user_ec2_credentials',
+ user_id=self.test_user_2)['credentials']
+ self.assertIn(cred['access'], [c['access'] for c in resp])
+
+ def test_identity_ec2_delete_credential(self):
+ # user can delete their own credential
+ user_id = self.persona.credentials.user_id
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=user_id,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.do_request(
+ 'delete_user_ec2_credential',
+ expected_status=204,
+ user_id=user_id, access=cred['access'])
+ # user can delete another user's credential
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=self.test_user_2,
+ **self.ec2_credential(project_id=self.test_project_2)
+ )['credential']
+ self.do_request(
+ 'delete_user_ec2_credential',
+ expected_status=204,
+ user_id=self.test_user_2, access=cred['access'])
+ # non-existent credential is Not Found
+ self.do_request(
+ 'delete_user_ec2_credential',
+ expected_status=exceptions.NotFound,
+ user_id=self.test_user_2,
+ access=data_utils.rand_uuid_hex())
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_ec2_create_credential(self):
+ # user can create their own credential
+ user_id = self.persona.credentials.user_id
+ resp = self.do_request(
+ 'create_user_ec2_credential',
+ expected_status=201,
+ user_id=user_id,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.addCleanup(self.client.delete_user_ec2_credential,
+ user_id=user_id, access=resp['access'])
+ # user cannot create credential for other user
+ self.do_request(
+ 'create_user_ec2_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2,
+ **self.ec2_credential(project_id=self.test_project_2))
+
+ def test_identity_ec2_delete_credential(self):
+ # user can delete their own credential
+ user_id = self.persona.credentials.user_id
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=user_id,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.do_request(
+ 'delete_user_ec2_credential',
+ expected_status=204,
+ user_id=user_id, access=cred['access'])
+ # user cannot delete another user's credential
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=self.test_user_2,
+ **self.ec2_credential(project_id=self.test_project_2)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=self.test_user_2, access=cred['access'])
+ self.do_request(
+ 'delete_user_ec2_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2, access=cred['access'])
+ # non-existent credential is Not Found
+ self.do_request(
+ 'delete_user_ec2_credential',
+ expected_status=exceptions.NotFound,
+ user_id=self.test_user_2,
+ access=data_utils.rand_uuid_hex())
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(IdentityV3RbacEc2CredentialTest, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_ec2_create_credential(self):
+ # user cannot create their own credential
+ user_id = self.persona.credentials.user_id
+ self.do_request(
+ 'create_user_ec2_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=user_id,
+ **self.ec2_credential(project_id=self.test_project_1))
+ # user cannot create credential for user in own domain
+ self.do_request(
+ 'create_user_ec2_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1,
+ **self.ec2_credential(project_id=self.test_project_1))
+ # user cannot create credential for other user
+ self.do_request(
+ 'create_user_ec2_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2,
+ **self.ec2_credential(project_id=self.test_project_2))
+
+ def test_identity_ec2_get_credential(self):
+ # user cannot get their own credential
+ user_id = self.persona.credentials.user_id
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=user_id,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=user_id, access=cred['access'])
+ self.do_request('show_user_ec2_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=user_id, access=cred['access'])
+ # user cannot get credential for user in own domain
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=self.test_user_1,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=self.test_user_1, access=cred['access'])
+ self.do_request('show_user_ec2_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2, access=cred['access'])
+ # user cannot get credential for other user
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=self.test_user_2,
+ **self.ec2_credential(project_id=self.test_project_2)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=self.test_user_2, access=cred['access'])
+ self.do_request('show_user_ec2_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2, access=cred['access'])
+ # non-existent credential is Not Found
+ self.do_request(
+ 'show_user_ec2_credential',
+ expected_status=exceptions.NotFound,
+ user_id=self.test_user_2,
+ access=data_utils.rand_uuid_hex())
+
+ def test_identity_ec2_list_credentials(self):
+ # user cannot list their own credentials
+ user_id = self.persona.credentials.user_id
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=user_id,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=user_id, access=cred['access'])
+ self.do_request('list_user_ec2_credentials',
+ expected_status=exceptions.Forbidden,
+ user_id=user_id)
+ # user cannot list credentials for user in own domain
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=self.test_user_1,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=self.test_user_1, access=cred['access'])
+ self.do_request('list_user_ec2_credentials',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1)
+ # user cannot list credentials for other user
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=self.test_user_2,
+ **self.ec2_credential(project_id=self.test_project_2)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=self.test_user_2, access=cred['access'])
+ self.do_request('list_user_ec2_credentials',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2)
+
+ def test_identity_ec2_delete_credential(self):
+ # user cannot delete their own credential
+ user_id = self.persona.credentials.user_id
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=user_id,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=user_id, access=cred['access'])
+ self.do_request(
+ 'delete_user_ec2_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=user_id, access=cred['access'])
+ # user cannot delete credential for user in own domain
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=self.test_user_1,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=self.test_user_1, access=cred['access'])
+ self.do_request(
+ 'delete_user_ec2_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_1, access=cred['access'])
+ # user cannot delete another user's credential
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=self.test_user_2,
+ **self.ec2_credential(project_id=self.test_project_2)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=self.test_user_2, access=cred['access'])
+ self.do_request(
+ 'delete_user_ec2_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2, access=cred['access'])
+ # non-existent credential is Not Found
+ self.do_request(
+ 'delete_user_ec2_credential',
+ expected_status=exceptions.NotFound,
+ user_id=self.test_user_2,
+ access=data_utils.rand_uuid_hex())
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainAdminTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(SystemReaderTests):
+
+ credentials = ['project_admin', 'system_admin']
+
+ def test_identity_ec2_get_credential(self):
+ # user can get their own credential
+ user_id = self.persona.credentials.user_id
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=user_id,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=user_id, access=cred['access'])
+ self.do_request('show_user_ec2_credential',
+ user_id=user_id, access=cred['access'])
+ # user cannot get credential for other user
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=self.test_user_2,
+ **self.ec2_credential(project_id=self.test_project_2)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=self.test_user_2, access=cred['access'])
+ self.do_request('show_user_ec2_credential',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2, access=cred['access'])
+ # non-existent credential is Not Found
+ self.do_request(
+ 'show_user_ec2_credential',
+ expected_status=exceptions.NotFound,
+ user_id=self.test_user_2,
+ access=data_utils.rand_uuid_hex())
+
+ def test_identity_ec2_list_credentials(self):
+ # user can list their own credentials
+ user_id = self.persona.credentials.user_id
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=user_id,
+ **self.ec2_credential(project_id=self.test_project_1)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=user_id, access=cred['access'])
+ resp = self.do_request('list_user_ec2_credentials',
+ user_id=user_id)['credentials']
+ self.assertIn(cred['access'], [c['access'] for c in resp])
+ # user cannot list credentials for other user
+ cred = self.admin_credentials_client.create_user_ec2_credential(
+ user_id=self.test_user_2,
+ **self.ec2_credential(project_id=self.test_project_2)
+ )['credential']
+ self.addCleanup(
+ self.admin_credentials_client.delete_user_ec2_credential,
+ user_id=self.test_user_2, access=cred['access'])
+ self.do_request('list_user_ec2_credentials',
+ expected_status=exceptions.Forbidden,
+ user_id=self.test_user_2)
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_endpoint.py b/keystone_tempest_plugin/tests/rbac/v3/test_endpoint.py
new file mode 100644
index 0000000..48dfb19
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_endpoint.py
@@ -0,0 +1,245 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacEndpointTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacEndpointTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.endpoints_v3_client
+ admin_client = cls.os_system_admin
+ cls.services_client = admin_client.identity_services_v3_client
+ cls.admin_endpoints_client = admin_client.endpoints_v3_client
+
+ @classmethod
+ def setUpClass(cls):
+ super(IdentityV3RbacEndpointTests, cls).setUpClass()
+ cls.service_id = cls.services_client.create_service(
+ type=data_utils.rand_name(),
+ name=data_utils.rand_name())['service']['id']
+ cls.addClassResourceCleanup(
+ cls.services_client.delete_service,
+ cls.service_id)
+
+ def endpoint(self):
+ return {
+ 'interface': 'public',
+ 'service_id': self.service_id,
+ 'url': 'http://localhost/service'
+ }
+
+ @abc.abstractmethod
+ def test_identity_create_endpoint(self):
+ """Test identity:create_endpoint policy.
+
+ This test must check:
+ * whether the persona can create an endpoint
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_endpoint(self):
+ """Test identity:get_endpoint policy.
+
+ This test must check:
+ * whether the persona can get an endpoint
+ * whether the persona can get an endpoint that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_endpoints(self):
+ """Test identity:list_endpoints policy.
+
+ This test must check:
+ * whether the persona can list all endpoints
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_endpoint(self):
+ """Test identity:update_endpoint policy.
+
+ This test must check:
+ * whether the persona can update an endpoint
+ * whether the persona can update an endpoint that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_endpoint(self):
+ """Test identity:delete_endpoint policy.
+
+ This test must check
+ * whether the persona can delete an endpoint
+ * whether the persona can delete an endpoint that does not exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacEndpointTests, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_endpoint(self):
+ endpoint_id = self.do_request(
+ 'create_endpoint', expected_status=201,
+ **self.endpoint())['endpoint']['id']
+ self.addCleanup(
+ self.admin_endpoints_client.delete_endpoint,
+ endpoint_id=endpoint_id)
+
+ def test_identity_get_endpoint(self):
+ endpoint_id = self.admin_endpoints_client.create_endpoint(
+ **self.endpoint())['endpoint']['id']
+ self.addCleanup(
+ self.admin_endpoints_client.delete_endpoint,
+ endpoint_id=endpoint_id)
+ self.do_request('show_endpoint', endpoint_id=endpoint_id)
+ # user gets a 404 for nonexistent endpoint
+ self.do_request('show_endpoint', expected_status=exceptions.NotFound,
+ endpoint_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_endpoints(self):
+ endpoint_id = self.admin_endpoints_client.create_endpoint(
+ **self.endpoint())['endpoint']['id']
+ self.addCleanup(
+ self.admin_endpoints_client.delete_endpoint,
+ endpoint_id=endpoint_id)
+ resp = self.do_request('list_endpoints')
+ self.assertIn(endpoint_id, [e['id'] for e in resp['endpoints']])
+
+ def test_identity_update_endpoint(self):
+ endpoint_id = self.admin_endpoints_client.create_endpoint(
+ **self.endpoint())['endpoint']['id']
+ self.addCleanup(
+ self.admin_endpoints_client.delete_endpoint,
+ endpoint_id=endpoint_id)
+ self.do_request('update_endpoint',
+ endpoint_id=endpoint_id,
+ interface='internal')
+ # user gets a 404 for nonexistent endpoint
+ self.do_request('update_endpoint', expected_status=exceptions.NotFound,
+ endpoint_id=data_utils.rand_uuid_hex(),
+ interface='internal')
+
+ def test_identity_delete_endpoint(self):
+ endpoint_id = self.admin_endpoints_client.create_endpoint(
+ **self.endpoint())['endpoint']['id']
+ self.do_request('delete_endpoint', expected_status=204,
+ endpoint_id=endpoint_id)
+ # user gets a 404 for nonexistent endpoint
+ self.do_request('delete_endpoint', expected_status=exceptions.NotFound,
+ endpoint_id=data_utils.rand_uuid_hex())
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_endpoint(self):
+ self.do_request(
+ 'create_endpoint', expected_status=exceptions.Forbidden,
+ **self.endpoint())
+
+ def test_identity_update_endpoint(self):
+ endpoint_id = self.admin_endpoints_client.create_endpoint(
+ **self.endpoint())['endpoint']['id']
+ self.addCleanup(
+ self.admin_endpoints_client.delete_endpoint,
+ endpoint_id=endpoint_id)
+ self.do_request('update_endpoint',
+ expected_status=exceptions.Forbidden,
+ endpoint_id=endpoint_id,
+ interface='internal')
+ # user gets a 404 for nonexistent endpoint
+ self.do_request('update_endpoint', expected_status=exceptions.NotFound,
+ endpoint_id=data_utils.rand_uuid_hex(),
+ interface='internal')
+
+ def test_identity_delete_endpoint(self):
+ endpoint_id = self.admin_endpoints_client.create_endpoint(
+ **self.endpoint())['endpoint']['id']
+ self.do_request('delete_endpoint',
+ expected_status=exceptions.Forbidden,
+ endpoint_id=endpoint_id)
+ # user gets a 404 for nonexistent endpoint
+ self.do_request('delete_endpoint', expected_status=exceptions.NotFound,
+ endpoint_id=data_utils.rand_uuid_hex())
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_endpoint(self):
+ endpoint_id = self.admin_endpoints_client.create_endpoint(
+ **self.endpoint())['endpoint']['id']
+ self.addCleanup(
+ self.admin_endpoints_client.delete_endpoint,
+ endpoint_id=endpoint_id)
+ self.do_request('show_endpoint', expected_status=exceptions.Forbidden,
+ endpoint_id=endpoint_id)
+ # user gets a 404 for nonexistent endpoint
+ self.do_request('show_endpoint', expected_status=exceptions.NotFound,
+ endpoint_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_endpoints(self):
+ endpoint_id = self.admin_endpoints_client.create_endpoint(
+ **self.endpoint())['endpoint']['id']
+ self.addCleanup(
+ self.admin_endpoints_client.delete_endpoint,
+ endpoint_id=endpoint_id)
+ self.do_request('list_endpoints', expected_status=exceptions.Forbidden)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_endpoint_group.py b/keystone_tempest_plugin/tests/rbac/v3/test_endpoint_group.py
new file mode 100644
index 0000000..6cca108
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_endpoint_group.py
@@ -0,0 +1,521 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacEndpointGroupTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacEndpointGroupTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.eg_client = cls.persona.endpoint_groups_client
+ cls.ef_client = cls.persona.endpoint_filter_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_eg_client = cls.admin_client.endpoint_groups_client
+ cls.admin_ef_client = cls.admin_client.endpoint_filter_client
+
+ def endpoint_group(self):
+ return {
+ 'name': data_utils.rand_name('endpoint_group'),
+ 'filters': {'interface': 'public'},
+ }
+
+ @abc.abstractmethod
+ def test_identity_create_endpoint_group(self):
+ """Test identity:create_endpoint_group policy.
+
+ This test must check:
+ * whether the persona can create an endpoint group
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_endpoint_group(self):
+ """Test identity:get_endpoint_group policy.
+
+ This test must check:
+ * whether the persona can get an endpoint group
+ * whether the persona can get an endpoint group that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_endpoint_groups(self):
+ """Test identity:list_endpoint_groups policy.
+
+ This test must check:
+ * whether the persona can list all endpoint groups
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_endpoint_group(self):
+ """Test identity:update_endpoint_group policy.
+
+ This test must check:
+ * whether the persona can update an endpoint group
+ * whether the persona can update an endpoint group that does not
+ exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_endpoint_group(self):
+ """Test identity:delete_endpoint_group policy.
+
+ This test must check
+ * whether the persona can delete an endpoint group
+ * whether the persona can delete an endpoint group that does not
+ exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_projects_associated_with_endpoint_group(self):
+ """Test identity:list_projects_associated_with_endpoint_group policy.
+
+ This test must check
+ * whether the persona can list projects associated with an endpoint
+ group
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_endpoints_associated_with_endpoint_group(self):
+ """Test identity:list_endpoints_associated_with_endpoint_group
+
+ This test must check
+ * whether the persona can list endpoints associated with an endpoint
+ group
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_endpoint_group_in_project(self):
+ """Test identity:get_endpoint_group_in_project
+
+ This test must check
+ * whether the persona can check if an endpoint group is associated
+ with a project
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_endpoint_groups_for_project(self):
+ """Test identity:list_endpoint_groups_for_project
+
+ This test must check
+ * whether the persona can list endpoint groups associated with a
+ project
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_add_endpoint_group_to_project(self):
+ """Test identity:add_endpoint_group_to_project
+
+ This test must check
+ * whether the persona can allow a project to access an endpoint group
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_remove_endpoint_group_from_project(self):
+ """Test identity:remove_endpoint_group_from_project
+
+ This test must check
+ * whether the persona can remove an endpoint group from a project
+ """
+ pass
+
+
+class SystemAdminTests(
+ IdentityV3RbacEndpointGroupTests, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_endpoint_group(self):
+ eg = self.do_request('create_endpoint_group', expected_status=201,
+ client=self.eg_client,
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+
+ def test_identity_get_endpoint_group(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ # user can get an endpoint group
+ self.do_request('show_endpoint_group', client=self.eg_client,
+ endpoint_group_id=eg)
+ # nonexistent endpoint group gives a 404
+ self.do_request('show_endpoint_group',
+ expected_status=exceptions.NotFound,
+ client=self.eg_client,
+ endpoint_group_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_endpoint_groups(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ resp = self.do_request('list_endpoint_groups',
+ client=self.eg_client)['endpoint_groups']
+ self.assertIn(eg, [e['id'] for e in resp])
+
+ def test_identity_update_endpoint_group(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ # user can update an endpoint group
+ self.do_request('update_endpoint_group', client=self.eg_client,
+ endpoint_group_id=eg,
+ description=data_utils.arbitrary_string())
+ # nonexistent endpoint group gives a 404
+ self.do_request('update_endpoint_group', client=self.eg_client,
+ expected_status=exceptions.NotFound,
+ endpoint_group_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_endpoint_group(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ # user can delete an endpoint group
+ self.do_request('delete_endpoint_group',
+ expected_status=204,
+ client=self.eg_client,
+ endpoint_group_id=eg)
+ # nonexistent endpoint group gives a 404
+ self.do_request('delete_endpoint_group',
+ expected_status=exceptions.NotFound,
+ client=self.eg_client,
+ endpoint_group_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_projects_associated_with_endpoint_group(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ project = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'))['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ project)
+ self.admin_ef_client.add_endpoint_group_to_project(
+ endpoint_group_id=eg, project_id=project)
+ self.addCleanup(
+ self.admin_ef_client.delete_endpoint_group_from_project,
+ endpoint_group_id=eg, project_id=project)
+ resp = self.do_request('list_projects_for_endpoint_group',
+ client=self.ef_client,
+ endpoint_group_id=eg)['projects']
+ self.assertIn(project, [p['id'] for p in resp])
+
+ def test_identity_list_endpoints_associated_with_endpoint_group(self):
+ service = self.admin_client.identity_services_v3_client.create_service(
+ type=data_utils.rand_name('service'))['service']['id']
+ self.addCleanup(
+ self.admin_client.identity_services_v3_client.delete_service,
+ service)
+ endpoint = self.admin_client.endpoints_v3_client.create_endpoint(
+ interface='public',
+ url='http://localhost/foo',
+ service_id=service)['endpoint']['id']
+ self.addCleanup(self.admin_client.endpoints_v3_client.delete_endpoint,
+ endpoint)
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ resp = self.do_request('list_endpoints_for_endpoint_group',
+ client=self.ef_client,
+ endpoint_group_id=eg)['endpoints']
+ self.assertIn(endpoint, [e['id'] for e in resp])
+
+ def test_identity_get_endpoint_group_in_project(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ project = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'))['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ project)
+ self.admin_ef_client.add_endpoint_group_to_project(
+ endpoint_group_id=eg, project_id=project)
+ self.addCleanup(
+ self.admin_ef_client.delete_endpoint_group_from_project,
+ endpoint_group_id=eg, project_id=project)
+ self.do_request('show_endpoint_group_for_project',
+ client=self.ef_client,
+ endpoint_group_id=eg,
+ project_id=project)
+
+ def test_identity_list_endpoint_groups_for_project(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ project = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'))['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ project)
+ self.admin_ef_client.add_endpoint_group_to_project(
+ endpoint_group_id=eg, project_id=project)
+ self.addCleanup(
+ self.admin_ef_client.delete_endpoint_group_from_project,
+ endpoint_group_id=eg, project_id=project)
+ resp = self.do_request('list_endpoint_groups_for_project',
+ client=self.ef_client,
+ project_id=project)
+ self.assertIn(eg, [e['id'] for e in resp['endpoint_groups']])
+
+ def test_identity_add_endpoint_group_to_project(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ project = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'))['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ project)
+ self.do_request('add_endpoint_group_to_project',
+ client=self.ef_client,
+ expected_status=204,
+ endpoint_group_id=eg,
+ project_id=project)
+ self.addCleanup(
+ self.admin_ef_client.delete_endpoint_group_from_project,
+ endpoint_group_id=eg, project_id=project)
+
+ def test_identity_remove_endpoint_group_from_project(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ project = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'))['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ project)
+ self.admin_ef_client.add_endpoint_group_to_project(
+ endpoint_group_id=eg, project_id=project)
+ self.do_request('delete_endpoint_group_from_project',
+ client=self.ef_client,
+ expected_status=204,
+ endpoint_group_id=eg, project_id=project)
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_endpoint_group(self):
+ self.do_request('create_endpoint_group',
+ expected_status=exceptions.Forbidden,
+ client=self.eg_client,
+ **self.endpoint_group())
+
+ def test_identity_update_endpoint_group(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ # user can update an endpoint group
+ self.do_request('update_endpoint_group', client=self.eg_client,
+ expected_status=exceptions.Forbidden,
+ endpoint_group_id=eg,
+ description=data_utils.arbitrary_string())
+ # nonexistent endpoint group gives a 403
+ self.do_request('update_endpoint_group', client=self.eg_client,
+ expected_status=exceptions.Forbidden,
+ endpoint_group_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_endpoint_group(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ # user cannot delete an endpoint group
+ self.do_request('delete_endpoint_group',
+ expected_status=exceptions.Forbidden,
+ client=self.eg_client,
+ endpoint_group_id=eg)
+ # nonexistent endpoint group gives a 403
+ self.do_request('delete_endpoint_group',
+ expected_status=exceptions.Forbidden,
+ client=self.eg_client,
+ endpoint_group_id=data_utils.rand_uuid_hex())
+
+ def test_identity_add_endpoint_group_to_project(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ project = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'))['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ project)
+ self.do_request('add_endpoint_group_to_project',
+ client=self.ef_client,
+ expected_status=exceptions.Forbidden,
+ endpoint_group_id=eg,
+ project_id=project)
+
+ def test_identity_remove_endpoint_group_from_project(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ project = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'))['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ project)
+ self.admin_ef_client.add_endpoint_group_to_project(
+ endpoint_group_id=eg, project_id=project)
+ self.addCleanup(
+ self.admin_ef_client.delete_endpoint_group_from_project,
+ endpoint_group_id=eg, project_id=project)
+ self.do_request('delete_endpoint_group_from_project',
+ client=self.ef_client,
+ expected_status=exceptions.Forbidden,
+ endpoint_group_id=eg, project_id=project)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_endpoint_group(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ # user cannot get an endpoint group
+ self.do_request('show_endpoint_group', client=self.eg_client,
+ expected_status=exceptions.Forbidden,
+ endpoint_group_id=eg)
+ # nonexistent endpoint group gives a 403
+ self.do_request('show_endpoint_group',
+ expected_status=exceptions.Forbidden,
+ client=self.eg_client,
+ endpoint_group_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_endpoint_groups(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ self.do_request('list_endpoint_groups',
+ expected_status=exceptions.Forbidden,
+ client=self.eg_client)
+
+ def test_identity_list_projects_associated_with_endpoint_group(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ project = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'))['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ project)
+ self.admin_ef_client.add_endpoint_group_to_project(
+ endpoint_group_id=eg, project_id=project)
+ self.addCleanup(
+ self.admin_ef_client.delete_endpoint_group_from_project,
+ endpoint_group_id=eg, project_id=project)
+ self.do_request('list_projects_for_endpoint_group',
+ client=self.ef_client,
+ expected_status=exceptions.Forbidden,
+ endpoint_group_id=eg)
+
+ def test_identity_list_endpoints_associated_with_endpoint_group(self):
+ service = self.admin_client.identity_services_v3_client.create_service(
+ type=data_utils.rand_name('service'))['service']['id']
+ self.addCleanup(
+ self.admin_client.identity_services_v3_client.delete_service,
+ service)
+ endpoint = self.admin_client.endpoints_v3_client.create_endpoint(
+ interface='public',
+ url='http://localhost/foo',
+ service_id=service)['endpoint']['id']
+ self.addCleanup(self.admin_client.endpoints_v3_client.delete_endpoint,
+ endpoint)
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ self.do_request('list_endpoints_for_endpoint_group',
+ client=self.ef_client,
+ expected_status=exceptions.Forbidden,
+ endpoint_group_id=eg)
+
+ def test_identity_get_endpoint_group_in_project(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ project = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'))['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ project)
+ self.admin_ef_client.add_endpoint_group_to_project(
+ endpoint_group_id=eg, project_id=project)
+ self.addCleanup(
+ self.admin_ef_client.delete_endpoint_group_from_project,
+ endpoint_group_id=eg, project_id=project)
+ self.do_request('show_endpoint_group_for_project',
+ client=self.ef_client,
+ expected_status=exceptions.Forbidden,
+ endpoint_group_id=eg,
+ project_id=project)
+
+ def test_identity_list_endpoint_groups_for_project(self):
+ eg = self.admin_eg_client.create_endpoint_group(
+ **self.endpoint_group())['endpoint_group']['id']
+ self.addCleanup(self.admin_eg_client.delete_endpoint_group, eg)
+ project = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'))['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ project)
+ self.admin_ef_client.add_endpoint_group_to_project(
+ endpoint_group_id=eg, project_id=project)
+ self.addCleanup(
+ self.admin_ef_client.delete_endpoint_group_from_project,
+ endpoint_group_id=eg, project_id=project)
+ self.do_request('list_endpoint_groups_for_project',
+ client=self.ef_client,
+ expected_status=exceptions.Forbidden,
+ project_id=project)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_grant.py b/keystone_tempest_plugin/tests/rbac/v3/test_grant.py
new file mode 100644
index 0000000..e88b679
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_grant.py
@@ -0,0 +1,3799 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacGrantTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacGrantTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.roles_v3_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_roles_client = cls.admin_client.roles_v3_client
+
+ @classmethod
+ def resource_setup(cls):
+ super(IdentityV3RbacGrantTest, cls).resource_setup()
+ cls._setup_assignments()
+
+ @classmethod
+ def _setup_assignments(cls):
+ # global role
+ cls.role_id = cls.admin_client.roles_v3_client.create_role(
+ name=data_utils.rand_name('role'))['role']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.roles_v3_client.delete_role, cls.role_id)
+
+ # own domain - if system or project user, this will be the user's
+ # namespace and isn't applicable for RBAC testing
+ # if domain user, this will be the domain on which the user has a role
+ # assignment
+ cls.own_domain = cls.persona.credentials.domain_id
+
+ # domain-specific role in own domain
+ cls.role_own_domain = cls.admin_client.roles_v3_client.create_role(
+ name=data_utils.rand_name('role'),
+ domain_id=cls.own_domain)['role']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.roles_v3_client.delete_role, cls.role_own_domain)
+
+ # arbitrary domain
+ cls.other_domain = cls.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name('domain'))['domain']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.delete_domain,
+ cls.other_domain)
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.update_domain,
+ cls.other_domain,
+ enabled=False)
+
+ # domain-specific role in another domain
+ cls.role_other_domain = cls.admin_client.roles_v3_client.create_role(
+ name=data_utils.rand_name('role'),
+ domain_id=cls.other_domain)['role']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.roles_v3_client.delete_role,
+ cls.role_other_domain)
+
+ # user in own domain
+ cls.user_in_domain = cls.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=cls.own_domain)['user']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.users_v3_client.delete_user,
+ cls.user_in_domain)
+
+ # group in own domain
+ cls.group_in_domain = cls.admin_client.groups_client.create_group(
+ name=data_utils.rand_name('group'),
+ domain_id=cls.own_domain)['group']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.groups_client.delete_group,
+ cls.group_in_domain)
+
+ # project in own domain
+ cls.project_in_domain = (
+ cls.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'),
+ domain_id=cls.own_domain)['project']['id'])
+ cls.addClassResourceCleanup(
+ cls.admin_client.projects_client.delete_project,
+ cls.project_in_domain)
+
+ # stuff in arbitrary domain, useful for testing system users' access to
+ # arbitrary domain and domain users non-access to domains they don't
+ # belong to
+ # user in other domain
+ cls.user_other_domain = cls.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=cls.other_domain)['user']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.users_v3_client.delete_user,
+ cls.user_other_domain)
+
+ # group in other domain
+ cls.group_other_domain = cls.admin_client.groups_client.create_group(
+ name=data_utils.rand_name('group'),
+ domain_id=cls.other_domain)['group']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.groups_client.delete_group,
+ cls.group_other_domain)
+
+ # project in other domain
+ cls.project_other_domain = (
+ cls.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'),
+ domain_id=cls.other_domain)['project']['id'])
+ cls.addClassResourceCleanup(
+ cls.admin_client.projects_client.delete_project,
+ cls.project_other_domain)
+
+ # assignments
+ roles_client = cls.admin_client.roles_v3_client
+ roles_client.create_user_role_on_project(
+ cls.project_in_domain,
+ cls.user_in_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_project(
+ cls.project_in_domain,
+ cls.user_other_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_project(
+ cls.project_other_domain,
+ cls.user_in_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_project(
+ cls.project_other_domain,
+ cls.user_other_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_domain(
+ cls.own_domain,
+ cls.user_in_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_domain(
+ cls.own_domain,
+ cls.user_other_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_domain(
+ cls.other_domain,
+ cls.user_in_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_domain(
+ cls.other_domain,
+ cls.user_other_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_system(
+ cls.user_in_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_system(
+ cls.user_other_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_project(
+ cls.project_in_domain,
+ cls.user_in_domain,
+ cls.role_own_domain)
+ roles_client.create_user_role_on_project(
+ cls.project_in_domain,
+ cls.user_other_domain,
+ cls.role_own_domain)
+ roles_client.create_user_role_on_project(
+ cls.project_other_domain,
+ cls.user_in_domain,
+ cls.role_other_domain)
+ roles_client.create_user_role_on_project(
+ cls.project_other_domain,
+ cls.user_other_domain,
+ cls.role_other_domain)
+ roles_client.create_user_role_on_domain(
+ cls.own_domain,
+ cls.user_in_domain,
+ cls.role_own_domain)
+ roles_client.create_user_role_on_domain(
+ cls.own_domain,
+ cls.user_other_domain,
+ cls.role_own_domain)
+ roles_client.create_user_role_on_domain(
+ cls.other_domain,
+ cls.user_in_domain,
+ cls.role_other_domain)
+ roles_client.create_user_role_on_domain(
+ cls.other_domain,
+ cls.user_other_domain,
+ cls.role_other_domain)
+ roles_client.create_group_role_on_project(
+ cls.project_in_domain,
+ cls.group_in_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_project(
+ cls.project_in_domain,
+ cls.group_other_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_project(
+ cls.project_other_domain,
+ cls.group_in_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_project(
+ cls.project_other_domain,
+ cls.group_other_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_domain(
+ cls.own_domain,
+ cls.group_in_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_domain(
+ cls.own_domain,
+ cls.group_other_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_domain(
+ cls.other_domain,
+ cls.group_in_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_domain(
+ cls.other_domain,
+ cls.group_other_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_system(
+ cls.group_in_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_system(
+ cls.group_other_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_project(
+ cls.project_in_domain,
+ cls.group_in_domain,
+ cls.role_own_domain)
+ roles_client.create_group_role_on_project(
+ cls.project_in_domain,
+ cls.group_other_domain,
+ cls.role_own_domain)
+ roles_client.create_group_role_on_project(
+ cls.project_other_domain,
+ cls.group_in_domain,
+ cls.role_other_domain)
+ roles_client.create_group_role_on_project(
+ cls.project_other_domain,
+ cls.group_other_domain,
+ cls.role_other_domain)
+ roles_client.create_group_role_on_domain(
+ cls.own_domain,
+ cls.group_in_domain,
+ cls.role_own_domain)
+ roles_client.create_group_role_on_domain(
+ cls.own_domain,
+ cls.group_other_domain,
+ cls.role_own_domain)
+ roles_client.create_group_role_on_domain(
+ cls.other_domain,
+ cls.group_in_domain,
+ cls.role_other_domain)
+ roles_client.create_group_role_on_domain(
+ cls.other_domain,
+ cls.group_other_domain,
+ cls.role_other_domain)
+
+ @abc.abstractmethod
+ def test_identity_check_grant(self):
+ """Test identity:check_grant policy.
+
+ This test must check:
+ * whether the persona can check a grant for
+
+ +------+------+-------+---------+--------+--------+
+ | Role | User | Group | Project | Domain | System |
+ +--------------+------+------+-------+---------+--------+--------+
+ | global | X | X | X | X | X | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | own domain | X | X | X | X | X | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | other domain | X | X | X | X | X | |
+ +--------------+------+------+-------+---------+--------+--------+
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_grants(self):
+ """Test identity:list_grants policy.
+
+ This test must check:
+ * whether the persona can list grants for
+ +------+------+-------+---------+--------+--------+
+ | Role | User | Group | Project | Domain | System |
+ +--------------+------+------+-------+---------+--------+--------+
+ | global | X | X | X | X | X | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | own domain | | X | X | X | X | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | other domain | | X | X | X | X | |
+ +--------------+------+------+-------+---------+--------+--------+
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_create_grant(self):
+ """Test identity:create_grant policy.
+
+ This test must check:
+ * whether the persona can create a grant of
+
+ +------+------+-------+---------+--------+--------+
+ | Role | User | Group | Project | Domain | System |
+ +--------------+------+------+-------+---------+--------+--------+
+ | global | X | X | X | X | X | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | own domain | X | X | X | X | X | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | other domain | X | X | X | X | X | |
+ +--------------+------+------+-------+---------+--------+--------+
+
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_revoke_grant(self):
+ """Test identity:revoke_grant policy.
+
+ This test must check:
+ * whether the persona can revoke a grant for
+
+ +------+------+-------+---------+--------+--------+
+ | Role | User | Group | Project | Domain | System |
+ +--------------+------+------+-------+---------+--------+--------+
+ | global | X | X | X | X | X | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | own domain | X | X | X | X | X | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | other domain | X | X | X | X | X | |
+ +--------------+------+------+-------+---------+--------+--------+
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_system_grants_for_user(self):
+ """Test identity:list_system_grants_for_user policy.
+
+ This test must check:
+ * whether the persona can list grants for
+
+ +------+------+-------+---------+--------+--------+
+ | Role | User | Group | Project | Domain | System |
+ +--------------+------+------+-------+---------+--------+--------+
+ | global | X | X | | | | X |
+ +--------------+------+------+-------+---------+--------+--------+
+ | own domain | | X | | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | other domain | | X | | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_check_system_grant_for_user(self):
+ """Test identity:check_system_grant_for_user policy.
+
+ This test must check:
+ * whether the persona can check a grant for
+
+ +------+------+-------+---------+--------+--------+
+ | Role | User | Group | Project | Domain | System |
+ +--------------+------+------+-------+---------+--------+--------+
+ | global | X | X | | | | X |
+ +--------------+------+------+-------+---------+--------+--------+
+ | own domain | X | X | | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | other domain | X | X | | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_create_system_grant_for_user(self):
+ """Test identity:create_system_grant_for_user policy.
+
+ This test must check:
+ * whether the persona can create a grant for
+
+ +------+------+-------+---------+--------+--------+
+ | Role | User | Group | Project | Domain | System |
+ +--------------+------+------+-------+---------+--------+--------+
+ | global | X | X | | | | X |
+ +--------------+------+------+-------+---------+--------+--------+
+ | own domain | X | X | | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | other domain | X | X | | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_revoke_system_grant_for_user(self):
+ """Test identity:revoke_system_grant_for_user policy.
+
+ This test must check:
+ * whether the persona can revoke a grant for
+
+ +------+------+-------+---------+--------+--------+
+ | Role | User | Group | Project | Domain | System |
+ +--------------+------+------+-------+---------+--------+--------+
+ | global | X | X | | | | X |
+ +--------------+------+------+-------+---------+--------+--------+
+ | own domain | X | X | | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | other domain | X | X | | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_system_grants_for_group(self):
+ """Test identity:list_system_grants_for_group policy.
+
+ This test must check:
+ * whether the persona can list grants for
+
+ +------+------+-------+---------+--------+--------+
+ | Role | User | Group | Project | Domain | System |
+ +--------------+------+------+-------+---------+--------+--------+
+ | global | X | | X | | | X |
+ +--------------+------+------+-------+---------+--------+--------+
+ | own domain | | | X | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | other domain | | | X | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_check_system_grant_for_group(self):
+ """Test identity:check_system_grant_for_group policy.
+
+ This test must check:
+ * whether the persona can check a grant for
+
+ +------+------+-------+---------+--------+--------+
+ | Role | User | Group | Project | Domain | System |
+ +--------------+------+------+-------+---------+--------+--------+
+ | global | X | | X | | | X |
+ +--------------+------+------+-------+---------+--------+--------+
+ | own domain | X | | X | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | other domain | X | | X | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_create_system_grant_for_group(self):
+ """Test identity:create_system_grant_for_group policy.
+
+ This test must check:
+ * whether the persona can create a grant for
+
+ +------+------+-------+---------+--------+--------+
+ | Role | User | Group | Project | Domain | System |
+ +--------------+------+------+-------+---------+--------+--------+
+ | global | X | | X | | | X |
+ +--------------+------+------+-------+---------+--------+--------+
+ | own domain | X | | X | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | other domain | X | | X | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_revoke_system_grant_for_group(self):
+ """Test identity:revoke_system_grant_for_group policy.
+
+ This test must check:
+ * whether the persona can revoke a grant for
+
+ +------+------+-------+---------+--------+--------+
+ | Role | User | Group | Project | Domain | System |
+ +--------------+------+------+-------+---------+--------+--------+
+ | global | X | | X | | | X |
+ +--------------+------+------+-------+---------+--------+--------+
+ | own domain | X | | X | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ | other domain | X | | X | | | |
+ +--------------+------+------+-------+---------+--------+--------+
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacGrantTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_check_grant(self):
+ # global role, arbitrary project, arbitrary user
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=204,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary project, arbitrary group
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=204,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary user
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=204,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary group
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=204,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+ # domain-specific role not matching arbitrary project, arbitrary group
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.NotFound,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # domain-specific role not matching arbitrary project, arbitrary group
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.NotFound,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # domain-specific role not matching arbitrary domain, arbitrary user
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.NotFound,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # domain-specific role not matching arbitrary domain, arbitrary group
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.NotFound,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+
+ # domain-specific role, arbitrary project, arbitrary user
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=204,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary project, arbitrary group
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=204,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary domain, arbitrary user
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=204,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary domain, arbitrary group
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=204,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+
+ def test_identity_list_grants(self):
+ # arbitrary project, arbitrary user
+ self.do_request(
+ 'list_user_roles_on_project',
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain)
+ # arbitrary project, arbitrary group
+ self.do_request(
+ 'list_group_roles_on_project',
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain)
+ # arbitrary domain, arbitrary user
+ self.do_request(
+ 'list_user_roles_on_domain',
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain)
+ # arbitrary domain, arbitrary group
+ self.do_request(
+ 'list_group_roles_on_domain',
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain)
+ # other domain-specific tests not applicable to system user
+
+ def test_identity_create_grant(self):
+ # global role, arbitrary project, arbitrary user
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=204,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_project,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary project, arbitrary group
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=204,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_project,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary user
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=204,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_domain,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary group
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=204,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_domain,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # domain-specific, arbitrary project, arbitrary user
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=204,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_project,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific, arbitrary project, arbitrary group
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=204,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_project,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific, arbitrary domain, arbitrary user
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=204,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_domain,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific, arbitrary domain, arbitrary group
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=204,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_domain,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # other domain-specific tests not applicable to system user
+
+ def test_identity_revoke_grant(self):
+ # global role, arbitrary project, arbitrary user
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=204,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary project, arbitrary group
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=204,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary user
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=204,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary group
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=204,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # domain-specific role, arbitrary project, arbitrary user
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=204,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary project, arbitrary group
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=204,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary domain, arbitrary user
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=204,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary domain, arbitrary group
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=204,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # other domain-specific tests not applicable to system user
+
+ def test_identity_list_system_grants_for_user(self):
+ self.do_request('list_user_roles_on_system',
+ user_id=self.user_other_domain)
+
+ def test_identity_check_system_grant_for_user(self):
+ self.do_request('check_user_role_existence_on_system',
+ expected_status=204,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_create_system_grant_for_user(self):
+ self.do_request(
+ 'create_user_role_on_system',
+ expected_status=204,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_system,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_revoke_system_grant_for_user(self):
+ self.admin_roles_client.create_user_role_on_system(
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_system',
+ expected_status=204,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_list_system_grants_for_group(self):
+ self.do_request('list_group_roles_on_system',
+ group_id=self.group_other_domain)
+
+ def test_identity_check_system_grant_for_group(self):
+ self.do_request('check_role_from_group_on_system_existence',
+ expected_status=204,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_create_system_grant_for_group(self):
+ self.do_request(
+ 'create_group_role_on_system',
+ expected_status=204,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_system,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_revoke_system_grant_for_group(self):
+ self.admin_roles_client.create_group_role_on_system(
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_system',
+ expected_status=204,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_grant(self):
+ # global role, arbitrary project, arbitrary user
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_project,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary project, arbitrary group
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_project,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary user
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_domain,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary group
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_domain,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # domain-specific, arbitrary project, arbitrary user
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_project,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific, arbitrary project, arbitrary group
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_project,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific, arbitrary domain, arbitrary user
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_domain,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific, arbitrary domain, arbitrary group
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_domain,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # other domain-specific tests not applicable to system user
+
+ def test_identity_revoke_grant(self):
+ # global role, arbitrary project, arbitrary user
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary project, arbitrary group
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary user
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary group
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # domain-specific role, arbitrary project, arbitrary user
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary project, arbitrary group
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary domain, arbitrary user
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary domain, arbitrary group
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # other domain-specific tests not applicable to system user
+
+ def test_identity_create_system_grant_for_user(self):
+ self.do_request(
+ 'create_user_role_on_system',
+ expected_status=exceptions.Forbidden,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_system,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_revoke_system_grant_for_user(self):
+ self.admin_roles_client.create_user_role_on_system(
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_system,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_system',
+ expected_status=exceptions.Forbidden,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_create_system_grant_for_group(self):
+ self.do_request(
+ 'create_group_role_on_system',
+ expected_status=exceptions.Forbidden,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_revoke_system_grant_for_group(self):
+ self.admin_roles_client.create_group_role_on_system(
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_system,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_system',
+ expected_status=exceptions.Forbidden,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(IdentityV3RbacGrantTest, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_check_grant(self):
+ ###################################################
+ # RESOURCE IN OWN DOMAIN - IDENTITY IN OWN DOMAIN #
+ ###################################################
+ # global role, project in own domain, user in own domain
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=204,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, project in own domain, group in own domain
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=204,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # global role, own domain, user in own domain
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=204,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, own domain, group in own domain
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=204,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # role in own domain, project in own domain, user in own domain
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=204,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in own domain, group in own domain
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=204,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, domain in own domain, user in own domain
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=204,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, domain in own domain, group in own domain
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=204,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in own domain, user in own domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in own domain, group in own domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, domain in own domain, user in own domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, domain in own domain, group in own domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ #####################################################
+ # RESOURCE IN OWN DOMAIN - IDENTITY IN OTHER DOMAIN #
+ #####################################################
+ # global role, project in own domain, user in other domain
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, project in own domain, group in other domain
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, own domain, user in other domain
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, own domain, group in other domain
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # role in own domain, project in own domain, user in other domain
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in own domain, group in other domain
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, domain in own domain, user in other domain
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, domain in own domain, group in other domain
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in own domain, user in other domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in own domain, group in other domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, domain in own domain, user in other domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, domain in own domain, group in other domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+
+ #####################################################
+ # RESOURCE IN OTHER DOMAIN - IDENTITY IN OWN DOMAIN #
+ #####################################################
+ # global role, project in other domain, user in own domain
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, project in other domain, group in own domain
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # global role, other domain, user in own domain
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, other domain, group in own domain
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # role in own domain, project in other domain, user in own domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in other domain, group in own domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, user in own domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, group in own domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in other domain, user in own domain
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in other domain, group in own domain
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, user in own domain
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, group in own domain
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ #######################################################
+ # RESOURCE IN OTHER DOMAIN - IDENTITY IN OTHER DOMAIN #
+ #######################################################
+ # global role, project in other domain, user in other domain
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, project in other domain, group in other domain
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, other domain, user in other domain
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, other domain, group in other domain
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # role in own domain, project in other domain, user in other domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in other domain, group in other domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, user in other domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, group in other domain
+ # (none created, should 403)
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in other domain, user in other domain
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in other domain, group in other domain
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, user in other domain
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, group in other domain
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+
+ def test_identity_list_grants(self):
+ ###################################################
+ # RESOURCE IN OWN DOMAIN - IDENTITY IN OWN DOMAIN #
+ ###################################################
+ # project in other domain, user in other domain
+ self.do_request(
+ 'list_user_roles_on_project',
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain)
+ # project in other domain, group in other domain
+ self.do_request(
+ 'list_group_roles_on_project',
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain)
+ # other domain, user in other domain
+ self.do_request(
+ 'list_user_roles_on_domain',
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain)
+ # other domain, group in other domain
+ self.do_request(
+ 'list_group_roles_on_domain',
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain)
+ #####################################################
+ # RESOURCE IN OWN DOMAIN - IDENTITY IN OTHER DOMAIN #
+ #####################################################
+ # project in other domain, user in other domain
+ self.do_request(
+ 'list_user_roles_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain)
+ # project in other domain, group in other domain
+ self.do_request(
+ 'list_group_roles_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain)
+ # other domain, user in other domain
+ self.do_request(
+ 'list_user_roles_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain)
+ # other domain, group in other domain
+ self.do_request(
+ 'list_group_roles_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain)
+ #####################################################
+ # RESOURCE IN OTHER DOMAIN - IDENTITY IN OWN DOMAIN #
+ #####################################################
+ # project in other domain, user in other domain
+ self.do_request(
+ 'list_user_roles_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain)
+ # project in other domain, group in other domain
+ self.do_request(
+ 'list_group_roles_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain)
+ # other domain, user in other domain
+ self.do_request(
+ 'list_user_roles_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain)
+ # other domain, group in other domain
+ self.do_request(
+ 'list_group_roles_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain)
+ #######################################################
+ # RESOURCE IN OTHER DOMAIN - IDENTITY IN OTHER DOMAIN #
+ #######################################################
+ # project in other domain, user in other domain
+ self.do_request(
+ 'list_user_roles_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain)
+ # project in other domain, group in other domain
+ self.do_request(
+ 'list_group_roles_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain)
+ # other domain, user in other domain
+ self.do_request(
+ 'list_user_roles_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain)
+ # other domain, group in other domain
+ self.do_request(
+ 'list_group_roles_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain)
+
+ def test_identity_create_grant(self):
+ ###################################################
+ # RESOURCE IN OWN DOMAIN - IDENTITY IN OWN DOMAIN #
+ ###################################################
+ # global role, project in own domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=204,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, project in own domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=204,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # global role, own domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=204,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, own domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=204,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # role in own domain, project in own domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=204,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in own domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=204,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=204,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=204,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in own domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in own domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ #####################################################
+ # RESOURCE IN OWN DOMAIN - IDENTITY IN OTHER DOMAIN #
+ #####################################################
+ # global role, project in own domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, project in own domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, own domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, own domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # role in own domain, project in own domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in own domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in own domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in own domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ #####################################################
+ # RESOURCE IN OTHER DOMAIN - IDENTITY IN OWN DOMAIN #
+ #####################################################
+ # global role, project in other domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, project in other domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # global role, other domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, other domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # role in own domain, project in other domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in other domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in other domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in other domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ #######################################################
+ # RESOURCE IN OTHER DOMAIN - IDENTITY IN OTHER DOMAIN #
+ #######################################################
+ # global role, project in other domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, project in other domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, other domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, other domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # role in own domain, project in other domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in other domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in other domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in other domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+
+ def test_identity_revoke_grant(self):
+ ###################################################
+ # RESOURCE IN OWN DOMAIN - IDENTITY IN OWN DOMAIN #
+ ###################################################
+ # global role, project in own domain, user in own domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=204,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, project in own domain, group in own domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=204,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # global role, own domain, user in own domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=204,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, own domain, group in own domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=204,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # role in own domain, project in own domain, user in own domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=204,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in own domain, group in own domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=204,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, user in own domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=204,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, group in own domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=204,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in own domain, user in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in own domain, group in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, user in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, group in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ #####################################################
+ # RESOURCE IN OWN DOMAIN - IDENTITY IN OTHER DOMAIN #
+ #####################################################
+ # global role, project in own domain, user in other domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, project in own domain, group in other domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, own domain, user in other domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, own domain, group in other domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # role in own domain, project in own domain, user in other domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in own domain, group in other domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, user in other domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, group in other domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in own domain, user in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in own domain, group in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, user in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, group in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ #####################################################
+ # RESOURCE IN OTHER DOMAIN - IDENTITY IN OWN DOMAIN #
+ #####################################################
+ # global role, project in other domain, user in own domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, project in other domain, group in own domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # global role, other domain, user in own domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, other domain, group in own domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # role in own domain, project in other domain, user in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in other domain, group in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, user in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, group in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in other domain, user in own domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in other domain, group in own domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, user in own domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, group in own domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ #######################################################
+ # RESOURCE IN OTHER DOMAIN - IDENTITY IN OTHER DOMAIN #
+ #######################################################
+ # global role, project in other domain, user in other domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, project in other domain, group in other domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, other domain, user in other domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, other domain, group in other domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # role in own domain, project in other domain, user in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in other domain, group in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, user in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, group in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in other domain, user in other domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in other domain, group in other domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, user in other domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, group in other domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+
+ def test_identity_list_system_grants_for_user(self):
+ self.do_request('list_user_roles_on_system',
+ expected_status=exceptions.Forbidden,
+ user_id=self.user_other_domain)
+ self.do_request('list_user_roles_on_system',
+ expected_status=exceptions.Forbidden,
+ user_id=self.user_other_domain)
+
+ def test_identity_check_system_grant_for_user(self):
+ self.do_request('check_user_role_existence_on_system',
+ exceptions.Forbidden,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request('check_user_role_existence_on_system',
+ exceptions.Forbidden,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_create_system_grant_for_user(self):
+ self.do_request(
+ 'create_user_role_on_system',
+ expected_status=exceptions.Forbidden,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'create_user_role_on_system',
+ expected_status=exceptions.Forbidden,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_revoke_system_grant_for_user(self):
+ # user in own domain
+ self.admin_roles_client.create_user_role_on_system(
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_system,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_system',
+ expected_status=exceptions.Forbidden,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # user in other domain
+ self.admin_roles_client.create_user_role_on_system(
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_system,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_system',
+ expected_status=exceptions.Forbidden,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_list_system_grants_for_group(self):
+ self.do_request('list_group_roles_on_system',
+ expected_status=exceptions.Forbidden,
+ group_id=self.group_in_domain)
+ self.do_request('list_group_roles_on_system',
+ expected_status=exceptions.Forbidden,
+ group_id=self.group_other_domain)
+
+ def test_identity_check_system_grant_for_group(self):
+ self.do_request('check_role_from_group_on_system_existence',
+ exceptions.Forbidden,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request('check_role_from_group_on_system_existence',
+ exceptions.Forbidden,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_create_system_grant_for_group(self):
+ self.do_request(
+ 'create_group_role_on_system',
+ expected_status=exceptions.Forbidden,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'create_group_role_on_system',
+ expected_status=exceptions.Forbidden,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_revoke_system_grant_for_group(self):
+ # group in own domain
+ self.admin_roles_client.create_group_role_on_system(
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_system,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_system',
+ expected_status=exceptions.Forbidden,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # group in other domain
+ self.admin_roles_client.create_group_role_on_system(
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_system,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_system',
+ expected_status=exceptions.Forbidden,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+ def test_identity_create_grant(self):
+ ###################################################
+ # RESOURCE IN OWN DOMAIN - IDENTITY IN OWN DOMAIN #
+ ###################################################
+ # global role, project in own domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, project in own domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # global role, own domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, own domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # role in own domain, project in own domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in own domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in own domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in own domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ #####################################################
+ # RESOURCE IN OWN DOMAIN - IDENTITY IN OTHER DOMAIN #
+ #####################################################
+ # global role, project in own domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, project in own domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, own domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, own domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # role in own domain, project in own domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in own domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in own domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in own domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ #####################################################
+ # RESOURCE IN OTHER DOMAIN - IDENTITY IN OWN DOMAIN #
+ #####################################################
+ # global role, project in other domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, project in other domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # global role, other domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, other domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # role in own domain, project in other domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in other domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in other domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in other domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, user in own domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, group in own domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ #######################################################
+ # RESOURCE IN OTHER DOMAIN - IDENTITY IN OTHER DOMAIN #
+ #######################################################
+ # global role, project in other domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, project in other domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, other domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, other domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # role in own domain, project in other domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in other domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in other domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in other domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, user in other domain
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, group in other domain
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+
+ def test_identity_revoke_grant(self):
+ ###################################################
+ # RESOURCE IN OWN DOMAIN - IDENTITY IN OWN DOMAIN #
+ ###################################################
+ # global role, project in own domain, user in own domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, project in own domain, group in own domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # global role, own domain, user in own domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, own domain, group in own domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # role in own domain, project in own domain, user in own domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in own domain, group in own domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, user in own domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, group in own domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in own domain, user in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in own domain, group in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, user in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, group in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ #####################################################
+ # RESOURCE IN OWN DOMAIN - IDENTITY IN OTHER DOMAIN #
+ #####################################################
+ # global role, project in own domain, user in other domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, project in own domain, group in other domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, own domain, user in other domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, own domain, group in other domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # role in own domain, project in own domain, user in other domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in own domain, group in other domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, user in other domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, own domain, group in other domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in own domain, user in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in own domain, group in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_in_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, user in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, own domain, group in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.own_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ #####################################################
+ # RESOURCE IN OTHER DOMAIN - IDENTITY IN OWN DOMAIN #
+ #####################################################
+ # global role, project in other domain, user in own domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, project in other domain, group in own domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # global role, other domain, user in own domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ # global role, other domain, group in own domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # role in own domain, project in other domain, user in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in other domain, group in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, user in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, group in own domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in other domain, user in own domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in other domain, group in own domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, user in own domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_in_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, group in own domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_in_domain,
+ role_id=self.role_other_domain)
+ #######################################################
+ # RESOURCE IN OTHER DOMAIN - IDENTITY IN OTHER DOMAIN #
+ #######################################################
+ # global role, project in other domain, user in other domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, project in other domain, group in other domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, other domain, user in other domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, other domain, group in other domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # role in own domain, project in other domain, user in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, project in other domain, group in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, user in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # role in own domain, other domain, group in other domain
+ # role assignment does not exist, should 403
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # role in other domain, project in other domain, user in other domain
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, project in other domain, group in other domain
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, user in other domain
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # role in other domain, other domain, group in other domain
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+
+ def test_identity_create_system_grant_for_user(self):
+ self.do_request(
+ 'create_user_role_on_system',
+ expected_status=exceptions.Forbidden,
+ user_id=self.user_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'create_user_role_on_system',
+ expected_status=exceptions.Forbidden,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_revoke_system_grant_for_user(self):
+ # group in own domain
+ self.admin_roles_client.create_group_role_on_system(
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_system,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_system',
+ expected_status=exceptions.Forbidden,
+ group_id=self.group_in_domain,
+ role_id=self.role_id)
+ # group in other domain
+ self.admin_roles_client.create_group_role_on_system(
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_system,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_system',
+ expected_status=exceptions.Forbidden,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(IdentityV3RbacGrantTest, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+ def test_identity_check_grant(self):
+ # global role, arbitrary project, arbitrary user
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary project, arbitrary group
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary user
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary group
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+ # domain-specific role not matching arbitrary project, arbitrary group
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # domain-specific role not matching arbitrary project, arbitrary group
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+ # domain-specific role not matching arbitrary domain, arbitrary user
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_own_domain)
+ # domain-specific role not matching arbitrary domain, arbitrary group
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_own_domain)
+
+ # domain-specific role, arbitrary project, arbitrary user
+ self.do_request(
+ 'check_user_role_existence_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary project, arbitrary group
+ self.do_request(
+ 'check_role_from_group_on_project_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary domain, arbitrary user
+ self.do_request(
+ 'check_user_role_existence_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary domain, arbitrary group
+ self.do_request(
+ 'check_role_from_group_on_domain_existence',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+
+ def test_identity_list_grants(self):
+ # arbitrary project, arbitrary user
+ self.do_request(
+ 'list_user_roles_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain)
+ # arbitrary project, arbitrary group
+ self.do_request(
+ 'list_group_roles_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain)
+ # arbitrary domain, arbitrary user
+ self.do_request(
+ 'list_user_roles_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain)
+ # arbitrary domain, arbitrary group
+ self.do_request(
+ 'list_group_roles_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain)
+ # other domain-specific tests not applicable to system user
+
+ def test_identity_create_grant(self):
+ # global role, arbitrary project, arbitrary user
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary project, arbitrary group
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary user
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary group
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # domain-specific, arbitrary project, arbitrary user
+ self.do_request(
+ 'create_user_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_project,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific, arbitrary project, arbitrary group
+ self.do_request(
+ 'create_group_role_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_group_on_project,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific, arbitrary domain, arbitrary user
+ self.do_request(
+ 'create_user_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.addCleanup(
+ self.admin_roles_client.delete_role_from_user_on_domain,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific, arbitrary domain, arbitrary group
+ self.do_request(
+ 'create_group_role_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # other domain-specific tests not applicable to system user
+
+ def test_identity_revoke_grant(self):
+ # global role, arbitrary project, arbitrary user
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary project, arbitrary group
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary user
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ # global role, arbitrary domain, arbitrary group
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ # domain-specific role, arbitrary project, arbitrary user
+ self.admin_roles_client.create_user_role_on_project(
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary project, arbitrary group
+ self.admin_roles_client.create_group_role_on_project(
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary domain, arbitrary user
+ self.admin_roles_client.create_user_role_on_domain(
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_user_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ user_id=self.user_other_domain,
+ role_id=self.role_other_domain)
+ # domain-specific role, arbitrary domain, arbitrary group
+ self.admin_roles_client.create_group_role_on_domain(
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ self.do_request(
+ 'delete_role_from_group_on_domain',
+ expected_status=exceptions.Forbidden,
+ domain_id=self.other_domain,
+ group_id=self.group_other_domain,
+ role_id=self.role_other_domain)
+ # other domain-specific tests not applicable to system user
+
+ def test_identity_list_system_grants_for_user(self):
+ self.do_request('list_user_roles_on_system',
+ expected_status=exceptions.Forbidden,
+ user_id=self.user_other_domain)
+
+ def test_identity_check_system_grant_for_user(self):
+ self.do_request('check_user_role_existence_on_system',
+ exceptions.Forbidden,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_create_system_grant_for_user(self):
+ self.do_request(
+ 'create_user_role_on_system',
+ expected_status=exceptions.Forbidden,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_revoke_system_grant_for_user(self):
+ self.admin_roles_client.create_user_role_on_system(
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_user_on_system',
+ exceptions.Forbidden,
+ user_id=self.user_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_list_system_grants_for_group(self):
+ self.do_request('list_group_roles_on_system',
+ exceptions.Forbidden,
+ group_id=self.group_other_domain)
+
+ def test_identity_check_system_grant_for_group(self):
+ self.do_request('check_role_from_group_on_system_existence',
+ exceptions.Forbidden,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_create_system_grant_for_group(self):
+ self.do_request(
+ 'create_group_role_on_system',
+ expected_status=exceptions.Forbidden,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+ def test_identity_revoke_system_grant_for_group(self):
+ self.admin_roles_client.create_group_role_on_system(
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+ self.do_request(
+ 'delete_role_from_group_on_system',
+ expected_status=exceptions.Forbidden,
+ group_id=self.group_other_domain,
+ role_id=self.role_id)
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectMemberTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_group.py b/keystone_tempest_plugin/tests/rbac/v3/test_group.py
new file mode 100644
index 0000000..c3ce1d9
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_group.py
@@ -0,0 +1,1152 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacGroupTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacGroupTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.groups_client
+ cls.users_client = cls.persona.users_v3_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_groups_client = cls.admin_client.groups_client
+ cls.admin_users_client = cls.admin_client.users_v3_client
+ cls.admin_domains_client = cls.admin_client.domains_client
+
+ def setUp(self):
+ super(IdentityV3RbacGroupTest, self).setUp()
+ self.own_domain = self.persona.credentials.domain_id
+ self.other_domain = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.addCleanup(self.admin_domains_client.delete_domain,
+ self.other_domain)
+ self.addCleanup(self.admin_domains_client.update_domain,
+ domain_id=self.other_domain, enabled=False)
+
+ def group(self, domain_id=None):
+ group = {}
+ name = data_utils.rand_name('group')
+ group['name'] = name
+ if domain_id:
+ group['domain_id'] = domain_id
+ return group
+
+ @abc.abstractmethod
+ def test_identity_create_group(self):
+ """Test identity:create_group policy.
+
+ This test must check:
+ * whether the persona can create an arbitrary group
+ * whether the persona can create a group in another domain
+ * whether the persona can create a group in their own domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_group(self):
+ """Test identity:get_group policy.
+
+ This test must check:
+ * whether the persona can get an arbitrary group
+ * whether the persona can get a group in another domain
+ * whether the persona can get a group in their own domain
+ * whether the persona can get a group that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_groups(self):
+ """Test identity:list_groups policy.
+
+ This test must check:
+ * whether the persona can list all groups
+ * whether the result list is appropriately filtered to domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_groups_for_user(self):
+ """Test identity:list_groups_for_user policy.
+
+ This test must check:
+ * whether the persona can list groups for an arbitrary user
+ * whether the persona can see groups in their own domain for user in
+ their own domain
+ * whether the persona can see groups in another domain for user in
+ their own domain
+ * whether the persona can see groups in their own domain for user in
+ another domain
+ * whether the persona can see groups in another domain for user in
+ another domain
+ * whether the persona can list groups for a nonexistent user
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_group(self):
+ """Test identity:update_groups policy.
+
+ This test must check:
+ * whether the persona can update an arbitrary group
+ * whether the persona can update a group in another domain
+ * whether the persona can update a group in their own domain
+ * whether the persona can update a group that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_group(self):
+ """Test identity:delete_group policy.
+
+ This test must check
+ * whether the persona can delete an arbitrary group
+ * whether the persona can delete a group in another domain
+ * whether the persona can delete a group in their own domain
+ * whether the persona can delete a group that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_users_in_group(self):
+ """Test identity:list_users_in_group policy.
+
+ This test must check
+ * whether the persona can list users in an arbitrary group
+ * whether the persona can see users in their own domain for group in
+ their own domain
+ * whether the persona can see users in another domain for group in
+ their own domain
+ * whether the persona can see users in their own domain for group in
+ another domain
+ * whether the persona can see users in another domain for group in
+ another domain
+ * whether the persona can list users for a nonexistent group
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_add_user_to_group(self):
+ """Test identity:add_user_to_group policy.
+
+ This test must check
+ * whether the persona can add an arbitrary user to an arbitrary group
+ * whether the persona can add a user in their own domain to a group
+ in their own domain
+ * whether the persona can add a user in another domain to a group in
+ their own domain
+ * whether the persona can add a user in their own domain to a group
+ in another domain
+ * whether the persona can add a user in another domain to a group in
+ their own domain
+ * whether the persona can add a nonexistent user to a group
+ * whether the persona can add a user to a nonexistent group
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_remove_user_from_group(self):
+ """Test identity:remove_user_from_group policy.
+
+ This test must check
+ * whether the persona can remove an arbitrary user from an arbitrary
+ group
+ * whether the persona can remove a user in their own domain from a
+ group in their own domain
+ * whether the persona can remove a user in another domain from a
+ group in their own domain
+ * whether the persona can remove a user in their own domain from a
+ group in another domain
+ * whether the persona can remove a user in another domain from a
+ group in their own domain
+ * whether the persona can remove a nonexistent user from a group
+ * whether the persona can remove a user from a nonexistent group
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_check_user_in_group(self):
+ """Test identity:check_user_in_group policy.
+
+ This test must check
+ * whether the persona can check if an arbitrary user is in an
+ arbitrary group
+ * whether the persona can check if a user in their own domain is in a
+ group in their own domain
+ * whether the persona can check if a user in another domain is in a
+ group in their own domain
+ * whether the persona can check if a user in their own domain is in a
+ group in another domain
+ * whether the persona can check if a user in another domain is in a
+ group in another domain
+ * whether the persona can check if a nonexistent user is in a group
+ * whether the persona can check if a user is in a nonexistent group
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacGroupTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_group(self):
+ resp = self.do_request('create_group', expected_status=201,
+ **self.group())
+ self.addCleanup(self.admin_groups_client.delete_group,
+ resp['group']['id'])
+
+ def test_identity_get_group(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ # user can get an arbitrary group
+ self.do_request('show_group', group_id=group['id'])
+ # user gets a 404 for nonexistent group
+ self.do_request('show_group', expected_status=exceptions.NotFound,
+ group_id='fakegroup')
+
+ def test_identity_list_groups(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ resp = self.do_request('list_groups')
+ self.assertIn(group['id'], set(g['id'] for g in resp['groups']))
+
+ def test_identity_list_groups_for_user(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ user = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'))['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user['id'])
+ self.admin_groups_client.add_group_user(group['id'], user['id'])
+ resp = self.do_request('list_user_groups', client=self.users_client,
+ user_id=user['id'])
+ self.assertIn(group['id'], set(g['id'] for g in resp['groups']))
+ self.do_request('list_user_groups', client=self.users_client,
+ expected_status=exceptions.NotFound,
+ user_id='fakeuser')
+
+ def test_identity_update_group(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ # user can update an arbitrary group
+ group_update = {
+ 'group_id': group['id'],
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', **group_update)
+ # user gets a 404 for nonexistent group
+ group_update = {
+ 'group_id': 'fakegroup',
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', expected_status=exceptions.NotFound,
+ **group_update)
+
+ def test_identity_delete_group(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ # user can delete an arbitrary group
+ self.do_request('delete_group', expected_status=204,
+ group_id=group['id'])
+ # user gets a 404 for nonexistent group
+ self.do_request('delete_group', expected_status=exceptions.NotFound,
+ group_id='fakegroup')
+
+ def test_identity_list_users_in_group(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ user = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'))['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user['id'])
+ self.admin_groups_client.add_group_user(group['id'], user['id'])
+ resp = self.do_request('list_group_users', group_id=group['id'])
+ user_ids = set(u['id'] for u in resp['users'])
+ self.assertEqual(1, len(user_ids))
+ self.assertIn(user['id'], user_ids)
+
+ def test_identity_add_user_to_group(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ user = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'))['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user['id'])
+ # user can add a user to a group
+ self.do_request('add_group_user', expected_status=204,
+ group_id=group['id'], user_id=user['id'])
+ # user gets a 404 for nonexistent group
+ self.do_request('add_group_user', expected_status=exceptions.NotFound,
+ group_id='fakegroup', user_id=user['id'])
+ # user gets a 404 for nonexistent user
+ self.do_request('add_group_user', expected_status=exceptions.NotFound,
+ group_id=group['id'], user_id='fakeuser')
+
+ def test_identity_remove_user_from_group(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ user = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'))['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user['id'])
+ self.admin_groups_client.add_group_user(group['id'], user['id'])
+ # user can remove a user from a group
+ self.do_request('delete_group_user', expected_status=204,
+ group_id=group['id'], user_id=user['id'])
+ # user gets a 404 for nonexistent group
+ self.do_request('delete_group_user',
+ expected_status=exceptions.NotFound,
+ group_id='fakegroup', user_id=user['id'])
+ # user gets a 404 for nonexistent user
+ self.do_request('delete_group_user',
+ expected_status=exceptions.NotFound,
+ group_id=group['id'], user_id='fakeuser')
+
+ def test_identity_check_user_in_group(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ user = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'))['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user['id'])
+ self.admin_groups_client.add_group_user(group['id'], user['id'])
+ # user can check if a user is in a group
+ self.do_request('check_group_user_existence', expected_status=204,
+ group_id=group['id'], user_id=user['id'])
+ # user gets a 404 for nonexistent group
+ self.do_request('check_group_user_existence',
+ expected_status=exceptions.NotFound,
+ group_id='fakegroup', user_id=user['id'])
+ # user gets a 404 for nonexistent user
+ self.do_request('check_group_user_existence',
+ expected_status=exceptions.NotFound,
+ group_id=group['id'], user_id='fakeuser')
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_group(self):
+ self.do_request('create_group', expected_status=exceptions.Forbidden,
+ **self.group())
+
+ def test_identity_update_group(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ # user cannot update an arbitrary group
+ group_update = {
+ 'group_id': group['id'],
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', expected_status=exceptions.Forbidden,
+ **group_update)
+ # user gets a 403 for nonexistent group
+ group_update = {
+ 'group_id': 'fakegroup',
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', expected_status=exceptions.Forbidden,
+ **group_update)
+
+ def test_identity_delete_group(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ # user cannot delete an arbitrary group
+ self.do_request('delete_group', expected_status=exceptions.Forbidden,
+ group_id=group['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('delete_group', expected_status=exceptions.Forbidden,
+ group_id=group['id'])
+
+ def test_identity_add_user_to_group(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ user = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'))['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user['id'])
+ # user cannot add a user to a group
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group['id'], user_id=user['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id='fakegroup', user_id=user['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group['id'], user_id='fakeuser')
+
+ def test_identity_remove_user_from_group(self):
+ group = self.admin_groups_client.create_group(**self.group())['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ user = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'))['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user['id'])
+ self.admin_groups_client.add_group_user(group['id'], user['id'])
+ # user cannot remove a user from a group
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group['id'], user_id=user['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id='fakegroup', user_id=user['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group['id'], user_id='fakeuser')
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(IdentityV3RbacGroupTest, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_create_group(self):
+ # user can create group in own domain
+ resp = self.do_request('create_group', expected_status=201,
+ **self.group(domain_id=self.own_domain))
+ self.addCleanup(self.admin_groups_client.delete_group,
+ resp['group']['id'])
+ # user cannot create group in another domain
+ resp = self.do_request('create_group',
+ expected_status=exceptions.Forbidden,
+ **self.group(domain_id=self.other_domain))
+
+ def test_identity_get_group(self):
+ group = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ # user can get group in own domain
+ self.do_request('show_group', group_id=group['id'])
+ # user cannot get group in other domain
+ group = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ self.do_request('show_group', expected_status=exceptions.Forbidden,
+ group_id=group['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('show_group', expected_status=exceptions.Forbidden,
+ group_id='fakegroup')
+
+ def test_identity_list_groups(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ resp = self.do_request('list_groups')
+ # user can get groups in own domain
+ self.assertIn(group1['id'], set(g['id'] for g in resp['groups']))
+ # user cannot get groups in other domain
+ self.assertNotIn(group2['id'], set(g['id'] for g in resp['groups']))
+
+ def test_identity_list_groups_for_user(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ user1 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ user2 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.other_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user2['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user2['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user2['id'])
+ resp = self.do_request('list_user_groups', client=self.users_client,
+ user_id=user1['id'])
+ # user can list groups in own domain for user in own domain
+ self.assertIn(group1['id'], set(g['id'] for g in resp['groups']))
+ # user cannot list groups in other domain for user in own domain
+ self.assertNotIn(group2['id'], set(g['id'] for g in resp['groups']))
+ # user cannot list groups for user in other domain
+ resp = self.do_request('list_user_groups', client=self.users_client,
+ expected_status=exceptions.Forbidden,
+ user_id=user2['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('list_user_groups', client=self.users_client,
+ expected_status=exceptions.Forbidden,
+ user_id='fakeuser')
+
+ def test_identity_update_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ # user can update a group in own domain
+ group_update = {
+ 'group_id': group1['id'],
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', **group_update)
+ # user cannot update a group in other domain
+ group_update = {
+ 'group_id': group2['id'],
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', expected_status=exceptions.Forbidden,
+ **group_update)
+ # user gets a 403 for nonexistent group
+ group_update = {
+ 'group_id': 'fakegroup',
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', expected_status=exceptions.Forbidden,
+ **group_update)
+
+ def test_identity_delete_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ group2 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ # user can delete a group in own domain
+ self.do_request('delete_group', expected_status=204,
+ group_id=group1['id'])
+ # user cannot delete a group in other domain
+ self.do_request('delete_group', expected_status=exceptions.Forbidden,
+ group_id=group2['id'])
+ # user gets a 404 for nonexistent group
+ self.do_request('delete_group', expected_status=exceptions.NotFound,
+ group_id='fakegroup')
+
+ def test_identity_list_users_in_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ user1 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ user2 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.other_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user2['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user2['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user2['id'])
+ resp = self.do_request('list_group_users', group_id=group1['id'])
+ # user can list users in own domain for group in own domain
+ self.assertIn(user1['id'], set(u['id'] for u in resp['users']))
+ # user cannot list users in another domain for group in own domain
+ self.assertNotIn(user2['id'], set(u['id'] for u in resp['users']))
+ # user cannot list users for group in another domain
+ self.do_request('list_group_users',
+ expected_status=exceptions.Forbidden,
+ group_id=group2['id'])
+
+ def test_identity_add_user_to_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ user1 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user1['id'])
+ user2 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user2['id'])
+ # user can add a user in own domain to a group in own domain
+ self.do_request('add_group_user', expected_status=204,
+ group_id=group1['id'], user_id=user1['id'])
+ # user can add a user in another domain to a group in own domain
+ self.do_request('add_group_user', expected_status=204,
+ group_id=group1['id'], user_id=user2['id'])
+ # user cannot add a user in own domain to a group in another domain
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user1['id'])
+ # user cannot add a user in another domain to a group in another domain
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user2['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id='fakegroup', user_id=user1['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id='fakeuser')
+
+ def test_identity_remove_user_from_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ user1 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user1['id'])
+ user2 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user2['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user2['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user2['id'])
+ # user can remove a user in own domain from a group in own domain
+ self.do_request('delete_group_user', expected_status=204,
+ group_id=group1['id'], user_id=user1['id'])
+ # user can remove a user in another domain from a group in own
+ # domain
+ self.do_request('delete_group_user', expected_status=204,
+ group_id=group1['id'], user_id=user2['id'])
+ # user cannot remove a user in own domain from a group in another
+ # domain
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user1['id'])
+ # user cannot remove a user in another domain from a group in another
+ # domain
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user2['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id='fakegroup', user_id=user1['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id='fakeuser')
+
+ def test_identity_check_user_in_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ user1 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user1['id'])
+ user2 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user2['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user2['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user2['id'])
+ # user can check if a user in own domain is in a group in own domain
+ self.do_request('check_group_user_existence', expected_status=204,
+ group_id=group1['id'], user_id=user1['id'])
+ # user can check if a user in another domain is in a group in own
+ # domain
+ self.do_request('check_group_user_existence',
+ expected_status=204,
+ group_id=group1['id'], user_id=user2['id'])
+ # user cannot check if a user in own domain is in a group in another
+ # domain
+ self.do_request('check_group_user_existence',
+ expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user1['id'])
+ # user cannot check if a user in another domain is in a group in
+ # another domain
+ self.do_request('check_group_user_existence',
+ expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user2['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('check_group_user_existence',
+ expected_status=exceptions.Forbidden,
+ group_id='fakegroup', user_id=user1['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('check_group_user_existence',
+ expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id='fakeuser')
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+ def test_identity_create_group(self):
+ # user cannot create group in own domain
+ self.do_request('create_group',
+ expected_status=exceptions.Forbidden,
+ **self.group(domain_id=self.own_domain))
+ # user cannot create group in another domain
+ self.do_request('create_group',
+ expected_status=exceptions.Forbidden,
+ **self.group(domain_id=self.other_domain))
+
+ def test_identity_update_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ # user cannot update a group in own domain
+ group_update = {
+ 'group_id': group1['id'],
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', expected_status=exceptions.Forbidden,
+ **group_update)
+ # user cannot update a group in other domain
+ group_update = {
+ 'group_id': group2['id'],
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', expected_status=exceptions.Forbidden,
+ **group_update)
+ # user gets a 403 for nonexistent group
+ group_update = {
+ 'group_id': 'fakegroup',
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', expected_status=exceptions.Forbidden,
+ **group_update)
+
+ def test_identity_delete_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ group2 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ # user cannot delete a group in own domain
+ self.do_request('delete_group', expected_status=exceptions.Forbidden,
+ group_id=group1['id'])
+ # user cannot delete a group in other domain
+ self.do_request('delete_group', expected_status=exceptions.Forbidden,
+ group_id=group2['id'])
+ # user gets a 404 for nonexistent group
+ self.do_request('delete_group', expected_status=exceptions.NotFound,
+ group_id='fakegroup')
+
+ def test_identity_add_user_to_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ user1 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user1['id'])
+ user2 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user2['id'])
+ # user cannot add a user in own domain to a group in own domain
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id=user1['id'])
+ # user cannot add a user in another domain to a group in own domain
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id=user2['id'])
+ # user cannot add a user in own domain to a group in another domain
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user1['id'])
+ # user cannot add a user in another domain to a group in another domain
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user2['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id='fakegroup', user_id=user1['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id='fakeuser')
+
+ def test_identity_remove_user_from_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ user1 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user1['id'])
+ user2 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user2['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user2['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user2['id'])
+ # user cannot remove a user in own domain from a group in own domain
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id=user1['id'])
+ # user cannot remove a user in another domain from a group in own
+ # domain
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id=user2['id'])
+ # user cannot remove a user in own domain from a group in another
+ # domain
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user1['id'])
+ # user cannot remove a user in another domain from a group in another
+ # domain
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user2['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id='fakegroup', user_id=user1['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id='fakeuser')
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(IdentityV3RbacGroupTest, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+ def test_identity_create_group(self):
+ # user cannot create group in own domain
+ self.do_request('create_group', expected_status=exceptions.Forbidden,
+ **self.group(domain_id=self.own_domain))
+ # user cannot create group in another domain
+ self.do_request('create_group',
+ expected_status=exceptions.Forbidden,
+ **self.group(domain_id=self.other_domain))
+
+ def test_identity_get_group(self):
+ group = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ # user cannot get group in own domain
+ self.do_request('show_group', expected_status=exceptions.Forbidden,
+ group_id=group['id'])
+ # user cannot get group in other domain
+ group = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group['id'])
+ self.do_request('show_group', expected_status=exceptions.Forbidden,
+ group_id=group['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('show_group', expected_status=exceptions.Forbidden,
+ group_id='fakegroup')
+
+ def test_identity_list_groups(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ self.do_request('list_groups', expected_status=exceptions.Forbidden)
+
+ def test_identity_list_groups_for_user(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ user1 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ user2 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.other_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user2['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user2['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user2['id'])
+ # user cannot list groups for user in own domain
+ self.do_request('list_user_groups', client=self.users_client,
+ expected_status=exceptions.Forbidden,
+ user_id=user1['id'])
+ # user cannot list groups for user in other domain
+ self.do_request('list_user_groups', client=self.users_client,
+ expected_status=exceptions.Forbidden,
+ user_id=user2['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('list_user_groups', client=self.users_client,
+ expected_status=exceptions.Forbidden,
+ user_id='fakeuser')
+
+ def test_identity_update_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ # user cannot update a group in own domain
+ group_update = {
+ 'group_id': group1['id'],
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', expected_status=exceptions.Forbidden,
+ **group_update)
+ # user cannot update a group in other domain
+ group_update = {
+ 'group_id': group2['id'],
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', expected_status=exceptions.Forbidden,
+ **group_update)
+ # user gets a 403 for nonexistent group
+ group_update = {
+ 'group_id': 'fakegroup',
+ 'description': data_utils.arbitrary_string
+ }
+ self.do_request('update_group', expected_status=exceptions.Forbidden,
+ **group_update)
+
+ def test_identity_delete_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ group2 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ # user cannot delete a group in own domain
+ self.do_request('delete_group', expected_status=exceptions.Forbidden,
+ group_id=group1['id'])
+ # user cannot delete a group in other domain
+ self.do_request('delete_group', expected_status=exceptions.Forbidden,
+ group_id=group2['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('delete_group', expected_status=exceptions.NotFound,
+ group_id='fakegroup')
+
+ def test_identity_list_users_in_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ user1 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(domain_id=self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ user2 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.other_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user2['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user2['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user2['id'])
+ # user cannot list users for group in own domain
+ self.do_request('list_group_users',
+ expected_status=exceptions.Forbidden,
+ group_id=group1['id'])
+ # user cannot list users for group in another domain
+ self.do_request('list_group_users',
+ expected_status=exceptions.Forbidden,
+ group_id=group2['id'])
+
+ def test_identity_add_user_to_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ user1 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user1['id'])
+ user2 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user2['id'])
+ # user cannot add a user in own domain to a group in own domain
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id=user1['id'])
+ # user cannot add a user in another domain to a group in own domain
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id=user2['id'])
+ # user cannot add a user in own domain to a group in another domain
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user1['id'])
+ # user cannot add a user in another domain to a group in another domain
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user2['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id='fakegroup', user_id=user1['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('add_group_user', expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id='fakeuser')
+
+ def test_identity_remove_user_from_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ user1 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user1['id'])
+ user2 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user2['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user2['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user2['id'])
+ # user cannot remove a user in own domain from a group in own domain
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id=user1['id'])
+ # user cannot remove a user in another domain from a group in own
+ # domain
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id=user2['id'])
+ # user cannot remove a user in own domain from a group in another
+ # domain
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user1['id'])
+ # user cannot remove a user in another domain from a group in another
+ # domain
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user2['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id='fakegroup', user_id=user1['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('delete_group_user',
+ expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id='fakeuser')
+
+ def test_identity_check_user_in_group(self):
+ group1 = self.admin_groups_client.create_group(
+ **self.group(self.own_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group1['id'])
+ group2 = self.admin_groups_client.create_group(
+ **self.group(self.other_domain))['group']
+ self.addCleanup(self.admin_groups_client.delete_group, group2['id'])
+ user1 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user1['id'])
+ user2 = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=self.own_domain)['user']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user,
+ user2['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group1['id'], user2['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user1['id'])
+ self.admin_groups_client.add_group_user(group2['id'], user2['id'])
+ # user cannot check if a user in own domain is in a group in own domain
+ self.do_request('check_group_user_existence',
+ expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id=user1['id'])
+ # user cannot check if a user in another domain is in a group in own
+ # domain
+ self.do_request('check_group_user_existence',
+ expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id=user2['id'])
+ # user cannot check if a user in own domain is in a group in another
+ # domain
+ self.do_request('check_group_user_existence',
+ expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user1['id'])
+ # user cannot check if a user in another domain is in a group in
+ # another domain
+ self.do_request('check_group_user_existence',
+ expected_status=exceptions.Forbidden,
+ group_id=group2['id'], user_id=user2['id'])
+ # user gets a 403 for nonexistent group
+ self.do_request('check_group_user_existence',
+ expected_status=exceptions.Forbidden,
+ group_id='fakegroup', user_id=user1['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('check_group_user_existence',
+ expected_status=exceptions.Forbidden,
+ group_id=group1['id'], user_id='fakeuser')
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_identity_provider.py b/keystone_tempest_plugin/tests/rbac/v3/test_identity_provider.py
new file mode 100644
index 0000000..819508c
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_identity_provider.py
@@ -0,0 +1,283 @@
+# Copyright 2020 SUSE LLC #
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin import clients
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacIdentityProviderTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacIdentityProviderTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.keystone_manager = clients.Manager(cls.persona.credentials)
+ persona_mgr = clients.Manager(cls.persona.credentials)
+ cls.client = persona_mgr.identity_providers_client
+ cls.admin_client = cls.os_system_admin
+ admin_mgr = clients.Manager(cls.admin_client.credentials)
+ cls.admin_idp_client = admin_mgr.identity_providers_client
+
+ @abc.abstractmethod
+ def test_identity_create_identity_provider(self):
+ """Test identity:create_identity_provider policy.
+
+ This test must check:
+ * whether the persona can create an identity provider
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_identity_provider(self):
+ """Test identity:get_identity_provider policy.
+
+ This test must check:
+ * whether the persona can get an identity provider
+ * whether the persona can get an identity provider that does not
+ exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_identity_providers(self):
+ """Test identity:list_identity_providers policy.
+
+ This test must check:
+ * whether the persona can list all identity providers
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_identity_provider(self):
+ """Test identity:update_identity_provider policy.
+
+ This test must check:
+ * whether the persona can update an identity provider
+ * whether the persona can update an identity provider that does not
+ exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_identity_provider(self):
+ """Test identity:delete_identity_provider policy.
+
+ This test must check
+ * whether the persona can delete an identity provider
+ * whether the persona can delete an identity provider that does not
+ exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacIdentityProviderTests,
+ base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_identity_provider(self):
+ idp = self.do_request(
+ 'create_identity_provider', expected_status=201,
+ idp_id=data_utils.rand_name()
+ )['identity_provider']
+ self.addCleanup(
+ self.admin_client.domains_client.delete_domain, idp['domain_id'])
+ self.addCleanup(
+ self.admin_client.domains_client.update_domain,
+ idp['domain_id'], enabled=False)
+ self.addCleanup(
+ self.admin_idp_client.delete_identity_provider, idp['id'])
+
+ def test_identity_get_identity_provider(self):
+ idp = self.admin_idp_client.create_identity_provider(
+ idp_id=data_utils.rand_name())['identity_provider']
+ self.addCleanup(
+ self.admin_client.domains_client.delete_domain, idp['domain_id'])
+ self.addCleanup(
+ self.admin_client.domains_client.update_domain,
+ idp['domain_id'], enabled=False)
+ self.addCleanup(
+ self.admin_idp_client.delete_identity_provider, idp['id'])
+ self.do_request('show_identity_provider', idp_id=idp['id'])
+ # user gets a 404 for nonexistent idp
+ self.do_request('show_identity_provider',
+ expected_status=exceptions.NotFound,
+ idp_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_identity_providers(self):
+ idp = self.admin_idp_client.create_identity_provider(
+ idp_id=data_utils.rand_name())['identity_provider']
+ self.addCleanup(
+ self.admin_client.domains_client.delete_domain, idp['domain_id'])
+ self.addCleanup(
+ self.admin_client.domains_client.update_domain,
+ idp['domain_id'], enabled=False)
+ self.addCleanup(
+ self.admin_idp_client.delete_identity_provider, idp['id'])
+ resp = self.do_request('list_identity_providers')
+ self.assertIn(idp['id'], [i['id'] for i in resp['identity_providers']])
+
+ def test_identity_update_identity_provider(self):
+ idp = self.admin_idp_client.create_identity_provider(
+ idp_id=data_utils.rand_name())['identity_provider']
+ self.addCleanup(
+ self.admin_client.domains_client.delete_domain, idp['domain_id'])
+ self.addCleanup(
+ self.admin_client.domains_client.update_domain,
+ idp['domain_id'], enabled=False)
+ self.addCleanup(
+ self.admin_idp_client.delete_identity_provider, idp['id'])
+ self.do_request('update_identity_provider',
+ idp_id=idp['id'],
+ description=data_utils.arbitrary_string())
+ # user gets a 404 for nonexistent idp
+ self.do_request('update_identity_provider',
+ expected_status=exceptions.NotFound,
+ idp_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_identity_provider(self):
+ idp = self.admin_idp_client.create_identity_provider(
+ idp_id=data_utils.rand_name())['identity_provider']
+ self.addCleanup(
+ self.admin_client.domains_client.delete_domain, idp['domain_id'])
+ self.addCleanup(
+ self.admin_client.domains_client.update_domain,
+ idp['domain_id'], enabled=False)
+ self.do_request('delete_identity_provider', expected_status=204,
+ idp_id=idp['id'])
+ # user gets a 404 for nonexistent idp
+ self.do_request('delete_identity_provider',
+ expected_status=exceptions.NotFound,
+ idp_id=data_utils.rand_uuid_hex())
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_identity_provider(self):
+ self.do_request('create_identity_provider',
+ expected_status=exceptions.Forbidden,
+ idp_id=data_utils.rand_name())
+
+ def test_identity_update_identity_provider(self):
+ idp = self.admin_idp_client.create_identity_provider(
+ idp_id=data_utils.rand_name())['identity_provider']
+ self.addCleanup(
+ self.admin_client.domains_client.delete_domain, idp['domain_id'])
+ self.addCleanup(
+ self.admin_client.domains_client.update_domain,
+ idp['domain_id'], enabled=False)
+ self.addCleanup(
+ self.admin_idp_client.delete_identity_provider, idp['id'])
+ self.do_request('update_identity_provider',
+ expected_status=exceptions.Forbidden,
+ idp_id=idp['id'],
+ description=data_utils.arbitrary_string())
+ # user gets a 403 for nonexistent idp
+ self.do_request('update_identity_provider',
+ expected_status=exceptions.Forbidden,
+ idp_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_identity_provider(self):
+ idp = self.admin_idp_client.create_identity_provider(
+ idp_id=data_utils.rand_name())['identity_provider']
+ self.addCleanup(
+ self.admin_client.domains_client.delete_domain, idp['domain_id'])
+ self.addCleanup(
+ self.admin_client.domains_client.update_domain,
+ idp['domain_id'], enabled=False)
+ self.addCleanup(
+ self.admin_idp_client.delete_identity_provider, idp['id'])
+ self.do_request('delete_identity_provider',
+ expected_status=exceptions.Forbidden,
+ idp_id=idp['id'])
+ # user gets a 403 for nonexistent idp
+ self.do_request('delete_identity_provider',
+ expected_status=exceptions.Forbidden,
+ idp_id=data_utils.rand_uuid_hex())
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_identity_provider(self):
+ idp = self.admin_idp_client.create_identity_provider(
+ idp_id=data_utils.rand_name())['identity_provider']
+ self.addCleanup(
+ self.admin_client.domains_client.delete_domain, idp['domain_id'])
+ self.addCleanup(
+ self.admin_client.domains_client.update_domain,
+ idp['domain_id'], enabled=False)
+ self.addCleanup(
+ self.admin_idp_client.delete_identity_provider, idp['id'])
+ self.do_request('show_identity_provider',
+ expected_status=exceptions.Forbidden,
+ idp_id=idp['id'])
+ # user gets a 403 for nonexistent idp
+ self.do_request('show_identity_provider',
+ expected_status=exceptions.Forbidden,
+ idp_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_identity_providers(self):
+ idp = self.admin_idp_client.create_identity_provider(
+ idp_id=data_utils.rand_name())['identity_provider']
+ self.addCleanup(
+ self.admin_client.domains_client.delete_domain, idp['domain_id'])
+ self.addCleanup(
+ self.admin_client.domains_client.update_domain,
+ idp['domain_id'], enabled=False)
+ self.addCleanup(
+ self.admin_idp_client.delete_identity_provider, idp['id'])
+ self.do_request('list_identity_providers',
+ expected_status=exceptions.Forbidden)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_implied_role.py b/keystone_tempest_plugin/tests/rbac/v3/test_implied_role.py
new file mode 100644
index 0000000..73765e4
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_implied_role.py
@@ -0,0 +1,257 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacImpliedRoleTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacImpliedRoleTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.roles_v3_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_roles_client = cls.admin_client.roles_v3_client
+
+ @classmethod
+ def resource_setup(cls):
+ super(IdentityV3RbacImpliedRoleTest, cls).resource_setup()
+ cls.prior_role = cls.admin_roles_client.create_role(
+ name=data_utils.rand_name('prior_role'))['role']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_roles_client.delete_role, cls.prior_role)
+ cls.implied_role = cls.admin_roles_client.create_role(
+ name=data_utils.rand_name('implied_role'))['role']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_roles_client.delete_role, cls.implied_role)
+
+ @abc.abstractmethod
+ def test_identity_create_implied_role(self):
+ """Test identity:create_implied_role policy.
+
+ This test must check:
+ * whether the persona can create an implied role
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_implied_role(self):
+ """Test identity:get_implied_role policy.
+
+ This test must check:
+ * whether the persona can get an implied role
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_implied_roles(self):
+ """Test identity:list_implied_roles policy.
+
+ This test must check:
+ * whether the persona can list implied roles
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_role_inference_rules(self):
+ """Test identity:list_role_inference_rules policy.
+
+ This test must check:
+ * whether the persona can list role inference rules
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_implied_role(self):
+ """Test identity:delete_implied_role policy.
+
+ This test must check
+ * whether the persona can delete an implied role
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_check_implied_role(self):
+ """Test identity:check_implied_role policy.
+
+ This test must check:
+ * whether the persona can check an association between two roles
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacImpliedRoleTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_implied_role(self):
+ self.do_request('create_role_inference_rule',
+ expected_status=201,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+ self.addCleanup(self.admin_roles_client.delete_role_inference_rule,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+
+ def test_identity_get_implied_role(self):
+ self.admin_roles_client.create_role_inference_rule(
+ prior_role=self.prior_role, implies_role=self.implied_role)
+ self.addCleanup(self.admin_roles_client.delete_role_inference_rule,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+ self.do_request('show_role_inference_rule',
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+
+ def test_identity_list_implied_roles(self):
+ self.admin_roles_client.create_role_inference_rule(
+ prior_role=self.prior_role, implies_role=self.implied_role)
+ self.addCleanup(self.admin_roles_client.delete_role_inference_rule,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+ self.do_request('list_role_inferences_rules',
+ prior_role=self.prior_role)
+
+ def test_identity_list_role_inference_rules(self):
+ self.admin_roles_client.create_role_inference_rule(
+ prior_role=self.prior_role, implies_role=self.implied_role)
+ self.addCleanup(self.admin_roles_client.delete_role_inference_rule,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+ self.do_request('list_all_role_inference_rules')
+
+ def test_identity_delete_implied_role(self):
+ self.admin_roles_client.create_role_inference_rule(
+ prior_role=self.prior_role, implies_role=self.implied_role)
+ self.do_request('delete_role_inference_rule',
+ expected_status=204,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+
+ def test_identity_check_implied_role(self):
+ self.admin_roles_client.create_role_inference_rule(
+ prior_role=self.prior_role, implies_role=self.implied_role)
+ self.addCleanup(self.admin_roles_client.delete_role_inference_rule,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+ self.do_request('check_role_inference_rule',
+ expected_status=204,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_implied_role(self):
+ self.do_request('create_role_inference_rule',
+ expected_status=exceptions.Forbidden,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+
+ def test_identity_delete_implied_role(self):
+ self.admin_roles_client.create_role_inference_rule(
+ prior_role=self.prior_role, implies_role=self.implied_role)
+ self.addCleanup(self.admin_roles_client.delete_role_inference_rule,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+ self.do_request('delete_role_inference_rule',
+ expected_status=exceptions.Forbidden,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_implied_role(self):
+ self.admin_roles_client.create_role_inference_rule(
+ prior_role=self.prior_role, implies_role=self.implied_role)
+ self.addCleanup(self.admin_roles_client.delete_role_inference_rule,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+ self.do_request('show_role_inference_rule',
+ expected_status=exceptions.Forbidden,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+
+ def test_identity_list_implied_roles(self):
+ self.admin_roles_client.create_role_inference_rule(
+ prior_role=self.prior_role, implies_role=self.implied_role)
+ self.addCleanup(self.admin_roles_client.delete_role_inference_rule,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+ self.do_request('list_role_inferences_rules',
+ expected_status=exceptions.Forbidden,
+ prior_role=self.prior_role)
+
+ def test_identity_list_role_inference_rules(self):
+ self.admin_roles_client.create_role_inference_rule(
+ prior_role=self.prior_role, implies_role=self.implied_role)
+ self.addCleanup(self.admin_roles_client.delete_role_inference_rule,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+ self.do_request('list_all_role_inference_rules',
+ expected_status=exceptions.Forbidden)
+
+ def test_identity_check_implied_role(self):
+ self.admin_roles_client.create_role_inference_rule(
+ prior_role=self.prior_role, implies_role=self.implied_role)
+ self.addCleanup(self.admin_roles_client.delete_role_inference_rule,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+ self.do_request('check_role_inference_rule',
+ expected_status=exceptions.Forbidden,
+ prior_role=self.prior_role,
+ implies_role=self.implied_role)
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_limit.py b/keystone_tempest_plugin/tests/rbac/v3/test_limit.py
new file mode 100644
index 0000000..d2efc6c
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_limit.py
@@ -0,0 +1,391 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin import clients
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacLimitTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacLimitTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ persona_mgr = clients.Manager(cls.persona.credentials)
+ cls.client = persona_mgr.limits_client
+ cls.admin_client = cls.os_system_admin
+ admin_mgr = clients.Manager(cls.admin_client.credentials)
+ cls.admin_reglim_client = admin_mgr.registered_limits_client
+ cls.admin_limits_client = admin_mgr.limits_client
+
+ @classmethod
+ def resource_setup(cls):
+ cls.region_id = cls.admin_client.regions_client.create_region(
+ region_id=data_utils.rand_name())['region']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.regions_client.delete_region,
+ cls.region_id)
+ svc_client = cls.admin_client.identity_services_v3_client
+ cls.service_id = svc_client.create_service(
+ type=data_utils.rand_name())['service']['id']
+ cls.addClassResourceCleanup(svc_client.delete_service, cls.service_id)
+ cls.own_domain = cls.persona.credentials.domain_id
+ cls.other_domain = cls.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.delete_domain, cls.other_domain)
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.update_domain,
+ domain_id=cls.other_domain,
+ enabled=False)
+ cls.own_project = cls.persona.credentials.project_id
+ # if project-scoped, use existing project
+ # else create project in domain
+ if not cls.own_project:
+ cls.own_project = cls.admin_client.projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=cls.own_domain)['project']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.projects_client.delete_project,
+ cls.own_project)
+ cls.other_project = cls.admin_client.projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=cls.other_domain)['project']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.projects_client.delete_project, cls.other_project)
+ cls.reg_limit = cls.admin_reglim_client.create_registered_limits(
+ payload=[{
+ "service_id": cls.service_id,
+ "region_id": cls.region_id,
+ "resource_name": data_utils.rand_name(),
+ "default_limit": 5
+ }])['registered_limits'][0]
+ cls.addClassResourceCleanup(
+ cls.admin_reglim_client.delete_registered_limit,
+ registered_limit_id=cls.reg_limit['id'])
+
+ def limits(self, project_id=None):
+ return [
+ {
+ "service_id": self.service_id,
+ "region_id": self.region_id,
+ "project_id": project_id or self.other_project,
+ "resource_name": self.reg_limit['resource_name'],
+ "resource_limit": 10
+ }
+ ]
+
+ @abc.abstractmethod
+ def test_identity_get_limit_model(self):
+ """Test identity:get_limit_model policy.
+
+ This test must check:
+ * whether the persona can get the limit model
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_create_limits(self):
+ """Test identity:create_limits policy.
+
+ This test must check:
+ * whether the persona can create a project limit for a project in any
+ domain
+ * whether the persona can create a project limit for a project in own
+ domain
+ * whether the persona can create a project limit for own project
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_limits(self):
+ """Test identity:list_limits policy.
+
+ This test must check:
+ * whether the persona can list limits for any project
+ * whether the persona can list limits for projects in own domain
+ * whether the persona can list limits for own project
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_limit(self):
+ """Test identity:get_limit policy.
+
+ This test must check:
+ * whether the persona can get a project limit for a project in any
+ domain
+ * whether the persona can get a project limit for a project in own
+ domain
+ * whether the persona can get a project limit for own project
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_limit(self):
+ """Test identity:update_limit policy.
+
+ This test must check:
+ * whether the persona can update a project limit for a project in any
+ domain
+ * whether the persona can update a project limit for a project in own
+ domain
+ * whether the persona can update a project limit for own project
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_limit(self):
+ """Test identity:delete_limit policy.
+
+ This test must check:
+ * whether the persona can delete a project limit for a project limit
+ in any domain
+ * whether the persona can delete a project limit for a project limit
+ in own domain
+ * whether the persona can delete a project limit for a project limit
+ own project
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacLimitTests, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_get_limit_model(self):
+ self.do_request('limits_model')
+
+ def test_identity_create_limits(self):
+ resp = self.do_request('create_limits',
+ expected_status=201,
+ payload=self.limits())
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=resp['limits'][0]['id'])
+
+ def test_identity_list_limits(self):
+ reg_limit_id = self.admin_limits_client.create_limits(
+ payload=self.limits())['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_id)
+ resp = self.do_request('list_limits')
+ self.assertIn(
+ reg_limit_id, [rl['id'] for rl in resp['limits']])
+
+ def test_identity_get_limit(self):
+ reg_limit_id = self.admin_limits_client.create_limits(
+ payload=self.limits())['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_id)
+ self.do_request('show_limit',
+ limit_id=reg_limit_id)
+
+ def test_identity_update_limit(self):
+ reg_limit_id = self.admin_limits_client.create_limits(
+ payload=self.limits())['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_id)
+ updated = {'description': data_utils.arbitrary_string()}
+ self.do_request('update_limit',
+ limit_id=reg_limit_id,
+ limit=updated)
+
+ def test_identity_delete_limit(self):
+ reg_limit_id = self.admin_limits_client.create_limits(
+ payload=self.limits())['limits'][0]['id']
+ self.do_request('delete_limit',
+ expected_status=204,
+ limit_id=reg_limit_id)
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_limits(self):
+ self.do_request('create_limits',
+ expected_status=exceptions.Forbidden,
+ payload=self.limits())
+
+ def test_identity_update_limit(self):
+ reg_limit_id = self.admin_limits_client.create_limits(
+ payload=self.limits())['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_id)
+ updated = {'description': data_utils.arbitrary_string()}
+ self.do_request('update_limit',
+ expected_status=exceptions.Forbidden,
+ limit_id=reg_limit_id,
+ limit=updated)
+
+ def test_identity_delete_limit(self):
+ reg_limit_id = self.admin_limits_client.create_limits(
+ payload=self.limits())['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_id)
+ self.do_request('delete_limit',
+ expected_status=exceptions.Forbidden,
+ limit_id=reg_limit_id)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(IdentityV3RbacLimitTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_limit_model(self):
+ self.do_request('limits_model')
+
+ def test_identity_create_limits(self):
+ # cannot create limit in arbitrary project
+ self.do_request('create_limits',
+ expected_status=exceptions.Forbidden,
+ payload=self.limits())
+ # cannot create limit in project in own domain
+ self.do_request('create_limits',
+ expected_status=exceptions.Forbidden,
+ payload=self.limits(project_id=self.own_project))
+
+ def test_identity_list_limits(self):
+ # random project
+ reg_limit_1 = self.admin_limits_client.create_limits(
+ payload=self.limits())['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_1)
+ # project in own domain
+ reg_limit_2 = self.admin_limits_client.create_limits(
+ payload=self.limits(project_id=self.own_project)
+ )['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_2)
+ resp = self.do_request('list_limits')
+ # should not see limit for other project
+ self.assertNotIn(
+ reg_limit_1, [rl['id'] for rl in resp['limits']])
+ # should see limit for project in own domain
+ self.assertIn(
+ reg_limit_2, [rl['id'] for rl in resp['limits']])
+
+ def test_identity_get_limit(self):
+ # random project
+ reg_limit_1 = self.admin_limits_client.create_limits(
+ payload=self.limits())['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_1)
+ # project in own domain
+ reg_limit_2 = self.admin_limits_client.create_limits(
+ payload=self.limits(project_id=self.own_project)
+ )['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_2)
+ # cannot get limit for other project
+ self.do_request('show_limit',
+ expected_status=exceptions.Forbidden,
+ limit_id=reg_limit_1)
+ # can get limit for project in own domain
+ self.do_request('show_limit',
+ limit_id=reg_limit_2)
+
+ def test_identity_update_limit(self):
+ # cannot update limit for arbitrary project
+ reg_limit_id = self.admin_limits_client.create_limits(
+ payload=self.limits())['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_id)
+ updated = {'description': data_utils.arbitrary_string()}
+ self.do_request('update_limit',
+ expected_status=exceptions.Forbidden,
+ limit_id=reg_limit_id,
+ limit=updated)
+ # cannot update limit for project in own domain
+ reg_limit_id = self.admin_limits_client.create_limits(
+ payload=self.limits(project_id=self.own_project)
+ )['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_id)
+ updated = {'description': data_utils.arbitrary_string()}
+ self.do_request('update_limit',
+ expected_status=exceptions.Forbidden,
+ limit_id=reg_limit_id,
+ limit=updated)
+
+ def test_identity_delete_limit(self):
+ # cannot delete limit for arbitrary project
+ reg_limit_id = self.admin_limits_client.create_limits(
+ payload=self.limits())['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_id)
+ self.do_request('delete_limit',
+ expected_status=exceptions.Forbidden,
+ limit_id=reg_limit_id)
+
+ # cannot delete limit for project in own domain
+ reg_limit_id = self.admin_limits_client.create_limits(
+ payload=self.limits(project_id=self.own_project)
+ )['limits'][0]['id']
+ self.addCleanup(
+ self.admin_limits_client.delete_limit,
+ limit_id=reg_limit_id)
+ self.do_request('delete_limit',
+ expected_status=exceptions.Forbidden,
+ limit_id=reg_limit_id)
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectMemberTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_mapping.py b/keystone_tempest_plugin/tests/rbac/v3/test_mapping.py
new file mode 100644
index 0000000..00b2e6b
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_mapping.py
@@ -0,0 +1,255 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin import clients
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacMappingTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacMappingTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.keystone_manager = clients.Manager(cls.persona.credentials)
+ persona_mgr = clients.Manager(cls.persona.credentials)
+ cls.client = persona_mgr.mapping_rules_client
+ admin_client = cls.os_system_admin
+ admin_mgr = clients.Manager(admin_client.credentials)
+ cls.admin_mapping_client = admin_mgr.mapping_rules_client
+
+ @abc.abstractmethod
+ def test_identity_create_mapping(self):
+ """Test identity:create_mapping policy.
+
+ This test must check:
+ * whether the persona can create a mapping
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_mapping(self):
+ """Test identity:get_mapping policy.
+
+ This test must check:
+ * whether the persona can get a mapping
+ * whether the persona can get a mapping that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_mappings(self):
+ """Test identity:list_mappings policy.
+
+ This test must check:
+ * whether the persona can list all mappings
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_mapping(self):
+ """Test identity:update_mapping policy.
+
+ This test must check:
+ * whether the persona can update a mapping
+ * whether the persona can update a mapping that does not
+ exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_mapping(self):
+ """Test identity:delete_mapping policy.
+
+ This test must check
+ * whether the persona can delete a mapping
+ * whether the persona can delete a mapping that does not
+ exist
+ """
+ pass
+
+
+_RULES = {
+ "rules":
+ [{
+ "local": [],
+ "remote": [{"type": data_utils.rand_name()}]
+ }]
+}
+
+
+class SystemAdminTests(IdentityV3RbacMappingTests, base.BaseIdentityTest):
+ credentials = ['system_admin']
+
+ def test_identity_create_mapping(self):
+ mapping_id = self.do_request(
+ 'create_mapping_rule', expected_status=201,
+ mapping_id=data_utils.rand_name(),
+ rules=_RULES
+ )['mapping']['id']
+ self.addCleanup(self.admin_mapping_client.delete_mapping_rule,
+ mapping_id)
+
+ def test_identity_get_mapping(self):
+ mapping_id = self.admin_mapping_client.create_mapping_rule(
+ mapping_id=data_utils.rand_name(),
+ rules=_RULES)['mapping']['id']
+ self.addCleanup(self.admin_mapping_client.delete_mapping_rule,
+ mapping_id)
+ self.do_request('show_mapping_rule', mapping_id=mapping_id)
+ # user gets a 404 for nonexistent mapping
+ self.do_request('show_mapping_rule',
+ expected_status=exceptions.NotFound,
+ mapping_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_mappings(self):
+ mapping_id = self.admin_mapping_client.create_mapping_rule(
+ mapping_id=data_utils.rand_name(),
+ rules=_RULES)['mapping']['id']
+ self.addCleanup(self.admin_mapping_client.delete_mapping_rule,
+ mapping_id)
+ resp = self.do_request('list_mapping_rules')
+ self.assertIn(mapping_id, [i['id'] for i in resp['mappings']])
+
+ def test_identity_update_mapping(self):
+ mapping_id = self.admin_mapping_client.create_mapping_rule(
+ mapping_id=data_utils.rand_name(),
+ rules=_RULES)['mapping']['id']
+ self.addCleanup(self.admin_mapping_client.delete_mapping_rule,
+ mapping_id)
+ self.do_request('update_mapping_rule',
+ mapping_id=mapping_id,
+ rules=_RULES)
+ # user gets a 404 for nonexistent mapping
+ self.do_request('update_mapping_rule',
+ expected_status=exceptions.NotFound,
+ mapping_id=data_utils.rand_uuid_hex(),
+ rules=_RULES)
+
+ def test_identity_delete_mapping(self):
+ mapping_id = self.admin_mapping_client.create_mapping_rule(
+ mapping_id=data_utils.rand_name(),
+ rules=_RULES)['mapping']['id']
+ self.do_request('delete_mapping_rule', expected_status=204,
+ mapping_id=mapping_id)
+ # user gets a 404 for nonexistent mapping
+ self.do_request('delete_mapping_rule',
+ expected_status=exceptions.NotFound,
+ mapping_id=mapping_id)
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_mapping(self):
+ self.do_request('create_mapping_rule',
+ expected_status=exceptions.Forbidden,
+ mapping_id=data_utils.rand_name(),
+ rules=_RULES)
+
+ def test_identity_update_mapping(self):
+ mapping_id = self.admin_mapping_client.create_mapping_rule(
+ mapping_id=data_utils.rand_name(),
+ rules=_RULES)['mapping']['id']
+ self.addCleanup(self.admin_mapping_client.delete_mapping_rule,
+ mapping_id)
+ self.do_request('update_mapping_rule',
+ expected_status=exceptions.Forbidden,
+ mapping_id=mapping_id,
+ rules=_RULES)
+ # user gets a 403 for nonexistent mapping
+ self.do_request('update_mapping_rule',
+ expected_status=exceptions.Forbidden,
+ mapping_id=data_utils.rand_uuid_hex(),
+ rules=_RULES)
+
+ def test_identity_delete_mapping(self):
+ mapping_id = self.admin_mapping_client.create_mapping_rule(
+ mapping_id=data_utils.rand_name(),
+ rules=_RULES)['mapping']['id']
+ self.addCleanup(self.admin_mapping_client.delete_mapping_rule,
+ mapping_id)
+ self.do_request('delete_mapping_rule',
+ expected_status=exceptions.Forbidden,
+ mapping_id=mapping_id)
+ # user gets a 403 for nonexistent mapping
+ self.do_request('delete_mapping_rule',
+ expected_status=exceptions.Forbidden,
+ mapping_id=mapping_id)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_mapping(self):
+ mapping_id = self.admin_mapping_client.create_mapping_rule(
+ mapping_id=data_utils.rand_name(),
+ rules=_RULES)['mapping']['id']
+ self.addCleanup(self.admin_mapping_client.delete_mapping_rule,
+ mapping_id)
+ self.do_request('show_mapping_rule',
+ expected_status=exceptions.Forbidden,
+ mapping_id=mapping_id)
+ # user gets a 403 for nonexistent mapping
+ self.do_request('show_mapping_rule',
+ expected_status=exceptions.Forbidden,
+ mapping_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_mappings(self):
+ mapping_id = self.admin_mapping_client.create_mapping_rule(
+ mapping_id=data_utils.rand_name(),
+ rules=_RULES)['mapping']['id']
+ self.addCleanup(self.admin_mapping_client.delete_mapping_rule,
+ mapping_id)
+ self.do_request('list_mapping_rules',
+ expected_status=exceptions.Forbidden)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_policy.py b/keystone_tempest_plugin/tests/rbac/v3/test_policy.py
new file mode 100644
index 0000000..53cdeb5
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_policy.py
@@ -0,0 +1,232 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacPolicyTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacPolicyTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.policies_client
+ admin_client = cls.os_system_admin
+ cls.admin_policies_client = admin_client.policies_client
+
+ def policy(self):
+ return {
+ 'blob': data_utils.rand_uuid_hex(),
+ 'type': data_utils.rand_uuid_hex()
+ }
+
+ @abc.abstractmethod
+ def test_identity_create_policy(self):
+ """Test identity:create_policy policy.
+
+ This test must check:
+ * whether the persona can create a policy
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_policy(self):
+ """Test identity:get_policy policy.
+
+ This test must check:
+ * whether the persona can get a policy
+ * whether the persona can get a policy that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_policies(self):
+ """Test identity:list_policies policy.
+
+ This test must check:
+ * whether the persona can list all policies
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_policy(self):
+ """Test identity:update_policy policy.
+
+ This test must check:
+ * whether the persona can update a policy
+ * whether the persona can update a policy that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_policy(self):
+ """Test identity:delete_policy policy.
+
+ This test must check
+ * whether the persona can delete a policy
+ * whether the persona can delete a policy that does not exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacPolicyTests, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_policy(self):
+ policy_id = self.do_request(
+ 'create_policy', expected_status=201,
+ **self.policy())['policy']['id']
+ self.addCleanup(
+ self.admin_policies_client.delete_policy,
+ policy_id=policy_id)
+
+ def test_identity_get_policy(self):
+ policy_id = self.admin_policies_client.create_policy(
+ **self.policy())['policy']['id']
+ self.addCleanup(
+ self.admin_policies_client.delete_policy,
+ policy_id=policy_id)
+ self.do_request('show_policy', policy_id=policy_id)
+ # user gets a 404 for nonexistent policy
+ self.do_request('show_policy', expected_status=exceptions.NotFound,
+ policy_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_policies(self):
+ policy_id = self.admin_policies_client.create_policy(
+ **self.policy())['policy']['id']
+ self.addCleanup(
+ self.admin_policies_client.delete_policy,
+ policy_id=policy_id)
+ resp = self.do_request('list_policies')
+ self.assertIn(policy_id, [e['id'] for e in resp['policies']])
+
+ def test_identity_update_policy(self):
+ policy_id = self.admin_policies_client.create_policy(
+ **self.policy())['policy']['id']
+ self.addCleanup(
+ self.admin_policies_client.delete_policy,
+ policy_id=policy_id)
+ self.do_request('update_policy',
+ policy_id=policy_id,
+ blob=data_utils.rand_uuid_hex())
+ # user gets a 404 for nonexistent policy
+ self.do_request('update_policy', expected_status=exceptions.NotFound,
+ policy_id=data_utils.rand_uuid_hex(),
+ blob=data_utils.rand_uuid_hex())
+
+ def test_identity_delete_policy(self):
+ policy_id = self.admin_policies_client.create_policy(
+ **self.policy())['policy']['id']
+ self.do_request('delete_policy', expected_status=204,
+ policy_id=policy_id)
+ # user gets a 404 for nonexistent policy
+ self.do_request('delete_policy', expected_status=exceptions.NotFound,
+ policy_id=data_utils.rand_uuid_hex())
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_policy(self):
+ self.do_request(
+ 'create_policy', expected_status=exceptions.Forbidden,
+ **self.policy())
+
+ def test_identity_update_policy(self):
+ policy_id = self.admin_policies_client.create_policy(
+ **self.policy())['policy']['id']
+ self.addCleanup(
+ self.admin_policies_client.delete_policy,
+ policy_id=policy_id)
+ self.do_request('update_policy', expected_status=exceptions.Forbidden,
+ policy_id=policy_id,
+ blob=data_utils.rand_uuid_hex())
+ # user gets a 403 for nonexistent policy
+ self.do_request('update_policy', expected_status=exceptions.Forbidden,
+ policy_id=data_utils.rand_uuid_hex(),
+ blob=data_utils.rand_uuid_hex())
+
+ def test_identity_delete_policy(self):
+ policy_id = self.admin_policies_client.create_policy(
+ **self.policy())['policy']['id']
+ self.do_request('delete_policy',
+ expected_status=exceptions.Forbidden,
+ policy_id=policy_id)
+ # user gets a 403 for nonexistent policy
+ self.do_request('delete_policy', expected_status=exceptions.Forbidden,
+ policy_id=data_utils.rand_uuid_hex())
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_policy(self):
+ policy_id = self.admin_policies_client.create_policy(
+ **self.policy())['policy']['id']
+ self.addCleanup(
+ self.admin_policies_client.delete_policy,
+ policy_id=policy_id)
+ self.do_request('show_policy', expected_status=exceptions.Forbidden,
+ policy_id=policy_id)
+ # user gets a 403 for nonexistent policy
+ self.do_request('show_policy', expected_status=exceptions.Forbidden,
+ policy_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_policies(self):
+ policy_id = self.admin_policies_client.create_policy(
+ **self.policy())['policy']['id']
+ self.addCleanup(
+ self.admin_policies_client.delete_policy,
+ policy_id=policy_id)
+ self.do_request('list_policies', expected_status=exceptions.Forbidden)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_policy_association.py b/keystone_tempest_plugin/tests/rbac/v3/test_policy_association.py
new file mode 100644
index 0000000..5c3f514
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_policy_association.py
@@ -0,0 +1,469 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacPolicyAssociationTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacPolicyAssociationTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.policies_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_policies_client = cls.admin_client.policies_client
+
+ @classmethod
+ def resource_setup(cls):
+ super(IdentityV3RbacPolicyAssociationTests, cls).resource_setup()
+ cls.policy_id = cls.admin_policies_client.create_policy(
+ blob=data_utils.rand_uuid_hex(),
+ type=data_utils.rand_uuid_hex())['policy']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_policies_client.delete_policy,
+ policy_id=cls.policy_id)
+ cls.region_id = cls.admin_client.regions_client.create_region(
+ region_id=data_utils.rand_name())['region']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.regions_client.delete_region,
+ cls.region_id)
+ svc_client = cls.admin_client.identity_services_v3_client
+ cls.service_id = svc_client.create_service(
+ type=data_utils.rand_name())['service']['id']
+ cls.addClassResourceCleanup(svc_client.delete_service, cls.service_id)
+ cls.endpoint_id = cls.admin_client.endpoints_v3_client.create_endpoint(
+ interface='public',
+ url='http://localhost/foo',
+ service_id=cls.service_id)['endpoint']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.endpoints_v3_client.delete_endpoint,
+ endpoint_id=cls.endpoint_id)
+
+ @abc.abstractmethod
+ def test_identity_create_policy_association_for_endpoint(self):
+ """Test identity:create_policy_association_for_endpoint policy.
+
+ This test must check:
+ * whether the persona can associate a policy with an endpoint
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_create_policy_association_for_service(self):
+ """Test identity:create_policy_association_for_service policy.
+
+ This test must check:
+ * whether the persona can associate a policy with a service
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_create_policy_association_for_region_and_service(self):
+ """Test identity:create_policy_association_for_region_and_service.
+
+ This test must check:
+ * whether the persona can associate a policy with a region and
+ service
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_check_policy_association_for_endpoint(self):
+ """Test identity:check_policy_association_for_endpoint policy.
+
+ This test must check:
+ * whether the persona can check a policy association for an endpoint
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_check_policy_association_for_service(self):
+ """Test identity:check_policy_association_for_service policy.
+
+ This test must check:
+ * whether the persona can check a policy association for a service
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_check_policy_association_for_region_and_service(self):
+ """Test identity:check_policy_association_for_region_and_service.
+
+ This test must check:
+ * whether the persona can check a policy association for a region and
+ service
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_policy_for_endpoint(self):
+ """Test identity:get_policy_for_endpoint policy.
+
+ This test must check:
+ * whether the persona can get a policy for an endpoint
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_endpoints_for_policy(self):
+ """Test identity:list_endpoints_for_policy policy.
+
+ This test must check:
+ * whether the persona can list endpoints for a policy
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_policy_association_for_endpoint(self):
+ """Test identity:delete_policy_association_for_endpoint policy.
+
+ This test must check
+ * whether the persona can delete a policy association for an endpoint
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_policy_association_for_service(self):
+ """Test identity:delete_policy_association_for_service policy.
+
+ This test must check
+ * whether the persona can delete a policy association for a service
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_policy_association_for_region_and_service(self):
+ """Test identity:delete_policy_association_for_region_and_service policy.
+
+ This test must check
+ * whether the persona can delete a policy association for a region
+ and service
+ """
+ pass
+
+
+class SystemAdminTests(
+ IdentityV3RbacPolicyAssociationTests, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_policy_association_for_endpoint(self):
+ self.do_request(
+ 'update_policy_association_for_endpoint',
+ expected_status=204,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.addCleanup(
+ self.admin_policies_client.delete_policy_association_for_endpoint,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+
+ def test_identity_create_policy_association_for_service(self):
+ self.do_request(
+ 'update_policy_association_for_service',
+ expected_status=204,
+ policy_id=self.policy_id, service_id=self.service_id)
+ self.addCleanup(
+ self.admin_policies_client.delete_policy_association_for_service,
+ policy_id=self.policy_id, service_id=self.service_id)
+
+ def test_identity_create_policy_association_for_region_and_service(self):
+ self.do_request(
+ 'update_policy_association_for_region_and_service',
+ expected_status=204,
+ policy_id=self.policy_id, service_id=self.service_id,
+ region_id=self.region_id)
+ delete_fn = getattr(
+ self.admin_policies_client,
+ 'delete_policy_association_for_region_and_service'
+ )
+ self.addCleanup(delete_fn,
+ policy_id=self.policy_id,
+ service_id=self.service_id,
+ region_id=self.region_id)
+
+ def test_identity_check_policy_association_for_endpoint(self):
+ self.admin_policies_client.update_policy_association_for_endpoint(
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.addCleanup(
+ self.admin_policies_client.delete_policy_association_for_endpoint,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.do_request(
+ 'show_policy_association_for_endpoint',
+ expected_status=204,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+
+ def test_identity_check_policy_association_for_service(self):
+ self.admin_policies_client.update_policy_association_for_service(
+ policy_id=self.policy_id, service_id=self.service_id)
+ self.addCleanup(
+ self.admin_policies_client.delete_policy_association_for_service,
+ policy_id=self.policy_id, service_id=self.service_id)
+ self.do_request(
+ 'show_policy_association_for_service',
+ expected_status=204,
+ policy_id=self.policy_id, service_id=self.service_id)
+
+ def test_identity_check_policy_association_for_region_and_service(self):
+ update_fn = getattr(
+ self.admin_policies_client,
+ 'update_policy_association_for_region_and_service'
+ )
+ update_fn(policy_id=self.policy_id,
+ service_id=self.service_id,
+ region_id=self.region_id)
+ delete_fn = getattr(
+ self.admin_policies_client,
+ 'delete_policy_association_for_region_and_service'
+ )
+ self.addCleanup(delete_fn,
+ policy_id=self.policy_id,
+ service_id=self.service_id,
+ region_id=self.region_id)
+ self.do_request(
+ 'show_policy_association_for_region_and_service',
+ expected_status=204,
+ policy_id=self.policy_id,
+ service_id=self.service_id,
+ region_id=self.region_id)
+
+ def test_identity_get_policy_for_endpoint(self):
+ self.admin_policies_client.update_policy_association_for_endpoint(
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.addCleanup(
+ self.admin_policies_client.delete_policy_association_for_endpoint,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.do_request(
+ 'show_policy_for_endpoint',
+ expected_status=200,
+ endpoint_id=self.endpoint_id)
+
+ def test_identity_list_endpoints_for_policy(self):
+ self.admin_policies_client.update_policy_association_for_endpoint(
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.addCleanup(
+ self.admin_policies_client.delete_policy_association_for_endpoint,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.do_request(
+ 'list_endpoints_for_policy',
+ expected_status=200,
+ policy_id=self.policy_id)
+
+ def test_identity_delete_policy_association_for_endpoint(self):
+ self.admin_policies_client.update_policy_association_for_endpoint(
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.do_request(
+ 'delete_policy_association_for_endpoint',
+ expected_status=204,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+
+ def test_identity_delete_policy_association_for_service(self):
+ self.admin_policies_client.update_policy_association_for_service(
+ policy_id=self.policy_id, service_id=self.service_id)
+ self.do_request(
+ 'delete_policy_association_for_service',
+ expected_status=204,
+ policy_id=self.policy_id, service_id=self.service_id)
+
+ def test_identity_delete_policy_association_for_region_and_service(self):
+ update_fn = getattr(
+ self.admin_policies_client,
+ 'update_policy_association_for_region_and_service'
+ )
+ update_fn(policy_id=self.policy_id,
+ service_id=self.service_id,
+ region_id=self.region_id)
+ self.do_request(
+ 'delete_policy_association_for_region_and_service',
+ expected_status=204,
+ policy_id=self.policy_id,
+ service_id=self.service_id,
+ region_id=self.region_id)
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_policy_association_for_endpoint(self):
+ self.do_request(
+ 'update_policy_association_for_endpoint',
+ expected_status=exceptions.Forbidden,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+
+ def test_identity_create_policy_association_for_service(self):
+ self.do_request(
+ 'update_policy_association_for_service',
+ expected_status=exceptions.Forbidden,
+ policy_id=self.policy_id, service_id=self.service_id)
+
+ def test_identity_create_policy_association_for_region_and_service(self):
+ self.do_request(
+ 'update_policy_association_for_region_and_service',
+ expected_status=exceptions.Forbidden,
+ policy_id=self.policy_id, service_id=self.service_id,
+ region_id=self.region_id)
+
+ def test_identity_delete_policy_association_for_endpoint(self):
+ self.admin_policies_client.update_policy_association_for_endpoint(
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.addCleanup(
+ self.admin_policies_client.delete_policy_association_for_endpoint,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.do_request(
+ 'delete_policy_association_for_endpoint',
+ expected_status=exceptions.Forbidden,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+
+ def test_identity_delete_policy_association_for_service(self):
+ self.admin_policies_client.update_policy_association_for_service(
+ policy_id=self.policy_id, service_id=self.service_id)
+ self.addCleanup(
+ self.admin_policies_client.delete_policy_association_for_service,
+ policy_id=self.policy_id, service_id=self.service_id)
+ self.do_request(
+ 'delete_policy_association_for_service',
+ expected_status=exceptions.Forbidden,
+ policy_id=self.policy_id, service_id=self.service_id)
+
+ def test_identity_delete_policy_association_for_region_and_service(self):
+ update_fn = getattr(
+ self.admin_policies_client,
+ 'update_policy_association_for_region_and_service'
+ )
+ update_fn(policy_id=self.policy_id,
+ service_id=self.service_id,
+ region_id=self.region_id)
+ delete_fn = getattr(
+ self.admin_policies_client,
+ 'delete_policy_association_for_region_and_service'
+ )
+ self.addCleanup(delete_fn,
+ policy_id=self.policy_id,
+ service_id=self.service_id,
+ region_id=self.region_id)
+ self.do_request(
+ 'delete_policy_association_for_region_and_service',
+ expected_status=exceptions.Forbidden,
+ policy_id=self.policy_id,
+ service_id=self.service_id,
+ region_id=self.region_id)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_check_policy_association_for_endpoint(self):
+ self.admin_policies_client.update_policy_association_for_endpoint(
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.addCleanup(
+ self.admin_policies_client.delete_policy_association_for_endpoint,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.do_request(
+ 'show_policy_association_for_endpoint',
+ expected_status=exceptions.Forbidden,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+
+ def test_identity_check_policy_association_for_service(self):
+ self.admin_policies_client.update_policy_association_for_service(
+ policy_id=self.policy_id, service_id=self.service_id)
+ self.addCleanup(
+ self.admin_policies_client.delete_policy_association_for_service,
+ policy_id=self.policy_id, service_id=self.service_id)
+ self.do_request(
+ 'show_policy_association_for_service',
+ expected_status=exceptions.Forbidden,
+ policy_id=self.policy_id, service_id=self.service_id)
+
+ def test_identity_check_policy_association_for_region_and_service(self):
+ update_fn = getattr(
+ self.admin_policies_client,
+ 'update_policy_association_for_region_and_service'
+ )
+ update_fn(policy_id=self.policy_id,
+ service_id=self.service_id,
+ region_id=self.region_id)
+ delete_fn = getattr(
+ self.admin_policies_client,
+ 'delete_policy_association_for_region_and_service'
+ )
+ self.addCleanup(delete_fn,
+ policy_id=self.policy_id,
+ service_id=self.service_id,
+ region_id=self.region_id)
+ self.do_request(
+ 'show_policy_association_for_region_and_service',
+ expected_status=exceptions.Forbidden,
+ policy_id=self.policy_id,
+ service_id=self.service_id,
+ region_id=self.region_id)
+
+ def test_identity_get_policy_for_endpoint(self):
+ self.admin_policies_client.update_policy_association_for_endpoint(
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.addCleanup(
+ self.admin_policies_client.delete_policy_association_for_endpoint,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.do_request(
+ 'show_policy_for_endpoint',
+ expected_status=exceptions.Forbidden,
+ endpoint_id=self.endpoint_id)
+
+ def test_identity_list_endpoints_for_policy(self):
+ self.admin_policies_client.update_policy_association_for_endpoint(
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.addCleanup(
+ self.admin_policies_client.delete_policy_association_for_endpoint,
+ policy_id=self.policy_id, endpoint_id=self.endpoint_id)
+ self.do_request(
+ 'list_endpoints_for_policy',
+ expected_status=exceptions.Forbidden,
+ policy_id=self.policy_id)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_project.py b/keystone_tempest_plugin/tests/rbac/v3/test_project.py
new file mode 100644
index 0000000..81b64e6
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_project.py
@@ -0,0 +1,467 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacProjectsTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacProjectsTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.projects_client
+ cls.users_client = cls.persona.users_v3_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_projects_client = cls.admin_client.projects_client
+
+ @abc.abstractmethod
+ def test_identity_create_project(self):
+ """Test identity:create_project policy.
+
+ This test must check:
+ * whether the persona can create a project
+ * whether the persona can create a project in their own domain
+ * whether the persona can create a project in another domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_project(self):
+ """Test identity:get_project policy.
+
+ This test must check:
+ * whether the persona can get a project
+ * whether the persona can get a project in their own domain
+ * whether the persona can get a project in another domain
+ * whether the persona can get a project that does not exist
+ * whether the persona can get their own project
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_projects(self):
+ """Test identity:list_projects policy.
+
+ This test must check:
+ * whether the persona can list all projects
+ * whether the persona can list all projects in their own domain
+ * whether the persona can list all projects in another domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_user_projects(self):
+ """Test identity:list_user_projects policy.
+
+ This test must check:
+ * whether the persona can list projects of a user
+ * whether the persona can list projects of a user in their own domain
+ * whether the persona can list projects of a user in another domain
+ * whether the persona can list projects for themself
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_project(self):
+ """Test identity:update_project policy.
+
+ This test must check:
+ * whether the persona can update a project
+ * whether the persona can update a project in their own domain
+ * whether the persona can update a project in another domain
+ * whether the persona can update a project that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_project(self):
+ """Test identity:delete_project policy.
+
+ This test must check
+ * whether the persona can delete a project
+ * whether the persona can delete a project in their own domain
+ * whether the persona can delete a project in another domain
+ * whether the persona can delete a project that does not exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacProjectsTests, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_project(self):
+ project_id = self.do_request(
+ 'create_project', expected_status=201, name=data_utils.rand_name()
+ )['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+
+ def test_identity_get_project(self):
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('show_project', project_id=project_id)
+ # user gets a 404 for nonexistent project
+ self.do_request('show_project', expected_status=exceptions.NotFound,
+ project_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_projects(self):
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ resp = self.do_request('list_projects')
+ self.assertIn(project_id, [p['id'] for p in resp['projects']])
+
+ def test_identity_list_user_projects(self):
+ user_id = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name())['user']['id']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user, user_id)
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ role_id = self.admin_client.roles_v3_client.create_role(
+ name=data_utils.rand_name())['role']['id']
+ self.addCleanup(self.admin_client.roles_v3_client.delete_role,
+ role_id)
+ self.admin_client.roles_v3_client.create_user_role_on_project(
+ project_id, user_id, role_id)
+ # user can list projects for arbitrary user
+ resp = self.do_request('list_user_projects', client=self.users_client,
+ user_id=user_id)
+ self.assertIn(project_id, [p['id'] for p in resp['projects']])
+ # user can list projects for self
+ resp = self.do_request('list_user_projects', client=self.users_client,
+ user_id=self.persona.credentials.user_id)
+ self.assertEqual(0, len([p['id'] for p in resp['projects']]))
+
+ def test_identity_update_project(self):
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('update_project',
+ project_id=project_id,
+ description=data_utils.arbitrary_string())
+ # user gets a 404 for nonexistent domain
+ self.do_request('update_project', expected_status=exceptions.NotFound,
+ project_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_project(self):
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.do_request('delete_project', expected_status=204,
+ project_id=project_id)
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_project(self):
+ self.do_request('create_project', expected_status=exceptions.Forbidden,
+ name=data_utils.rand_name())
+
+ def test_identity_update_project(self):
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('update_project', expected_status=exceptions.Forbidden,
+ project_id=project_id,
+ description=data_utils.arbitrary_string())
+ # user gets a 403 for nonexistent domain
+ self.do_request('update_project', expected_status=exceptions.Forbidden,
+ project_id=data_utils.rand_uuid_hex())
+
+ def test_identity_delete_project(self):
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('delete_project', expected_status=exceptions.Forbidden,
+ project_id=project_id)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(IdentityV3RbacProjectsTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def setUp(self):
+ super(DomainAdminTests, self).setUp()
+ self.own_domain = self.persona.credentials.domain_id
+ self.other_domain = self.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.addCleanup(self.admin_client.domains_client.delete_domain,
+ self.other_domain)
+ self.addCleanup(self.admin_client.domains_client.update_domain,
+ domain_id=self.other_domain, enabled=False)
+
+ def test_identity_create_project(self):
+ # user can create project in own domain
+ project_id = self.do_request(
+ 'create_project', expected_status=201, name=data_utils.rand_name(),
+ domain_id=self.own_domain
+ )['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ # user cannot create project in other domain
+ self.do_request(
+ 'create_project', expected_status=exceptions.Forbidden,
+ name=data_utils.rand_name(), domain_id=self.other_domain
+ )
+
+ def test_identity_get_project(self):
+ # user can get project in own domain
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.own_domain)['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('show_project', project_id=project_id)
+ # user cannot get project in other domain
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.other_domain)['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('show_project', expected_status=exceptions.Forbidden,
+ project_id=project_id)
+ # user gets a 403 for nonexistent project
+ self.do_request('show_project', expected_status=exceptions.Forbidden,
+ project_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_projects(self):
+ # user can list projects but cannot see project in other domain
+ own_project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.own_domain)['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project,
+ own_project_id)
+ other_project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.other_domain)['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project,
+ other_project_id)
+ resp = self.do_request('list_projects')
+ self.assertIn(own_project_id, [d['id'] for d in resp['projects']])
+ self.assertNotIn(other_project_id, [d['id'] for d in resp['projects']])
+
+ def test_identity_list_user_projects(self):
+ # user can list projects for user in own domain
+ user_id = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name(),
+ domain_id=self.own_domain)['user']['id']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user, user_id)
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ role_id = self.admin_client.roles_v3_client.create_role(
+ name=data_utils.rand_name())['role']['id']
+ self.addCleanup(self.admin_client.roles_v3_client.delete_role,
+ role_id)
+ self.admin_client.roles_v3_client.create_user_role_on_project(
+ project_id, user_id, role_id)
+ resp = self.do_request('list_user_projects', client=self.users_client,
+ user_id=user_id)
+ self.assertIn(project_id, [p['id'] for p in resp['projects']])
+ # user cannot list projects for user in other domain
+ user_id = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name(),
+ domain_id=self.other_domain)['user']['id']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user, user_id)
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ role_id = self.admin_client.roles_v3_client.create_role(
+ name=data_utils.rand_name())['role']['id']
+ self.addCleanup(self.admin_client.roles_v3_client.delete_role,
+ role_id)
+ self.admin_client.roles_v3_client.create_user_role_on_project(
+ project_id, user_id, role_id)
+ self.do_request('list_user_projects', client=self.users_client,
+ expected_status=exceptions.Forbidden,
+ user_id=user_id)
+ # user can list projects for self
+ resp = self.do_request('list_user_projects', client=self.users_client,
+ user_id=self.persona.credentials.user_id)
+ self.assertEqual(0, len([p['id'] for p in resp['projects']]))
+
+ def test_identity_update_project(self):
+ # user can update project in own domain
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.own_domain)['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('update_project',
+ project_id=project_id,
+ description=data_utils.arbitrary_string())
+ # user cannot update project in other domain
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.other_domain)['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('update_project',
+ expected_status=exceptions.Forbidden,
+ project_id=project_id,
+ description=data_utils.arbitrary_string())
+ # user gets a 403 for nonexistent domain
+ self.do_request('update_project', expected_status=exceptions.Forbidden,
+ project_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_project(self):
+ # user can delete project in own domain
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.own_domain)['project']['id']
+ self.do_request('delete_project', expected_status=204,
+ project_id=project_id)
+ # user cannot delete project in other domain
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.other_domain)['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('delete_project', expected_status=exceptions.Forbidden,
+ project_id=project_id)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+ def test_identity_create_project(self):
+ # user cannot create project in own domain
+ self.do_request(
+ 'create_project', expected_status=exceptions.Forbidden,
+ name=data_utils.rand_name(),
+ domain_id=self.own_domain
+ )
+ # user cannot create project in other domain
+ self.do_request(
+ 'create_project', expected_status=exceptions.Forbidden,
+ name=data_utils.rand_name(), domain_id=self.other_domain
+ )
+
+ def test_identity_update_project(self):
+ # user cannot update project in own domain
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.own_domain)['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('update_project',
+ expected_status=exceptions.Forbidden,
+ project_id=project_id,
+ description=data_utils.arbitrary_string())
+ # user cannot update project in other domain
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.other_domain)['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('update_project',
+ expected_status=exceptions.Forbidden,
+ project_id=project_id,
+ description=data_utils.arbitrary_string())
+ # user gets a 403 for nonexistent domain
+ self.do_request('update_project', expected_status=exceptions.Forbidden,
+ project_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_project(self):
+ # user cannot delete project in own domain
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.own_domain)['project']['id']
+ self.do_request('delete_project', expected_status=exceptions.Forbidden,
+ project_id=project_id)
+ # user cannot delete project in other domain
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.other_domain)['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('delete_project', expected_status=exceptions.Forbidden,
+ project_id=project_id)
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+ def test_identity_get_project(self):
+ # user cannot get arbitrary project
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.own_domain)['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ self.do_request('show_project', expected_status=exceptions.Forbidden,
+ project_id=project_id)
+ # user gets a 403 for nonexistent project
+ self.do_request('show_project', expected_status=exceptions.Forbidden,
+ project_id=data_utils.rand_uuid_hex())
+ # user can get own project
+ self.do_request('show_project',
+ project_id=self.persona.credentials.project_id)
+
+ def test_identity_list_projects(self):
+ # user cannot list projects
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project,
+ project_id)
+ self.do_request('list_projects', expected_status=exceptions.Forbidden)
+
+ def test_identity_list_user_projects(self):
+ # user can list projects for other user
+ user_id = self.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name())['user']['id']
+ self.addCleanup(self.admin_client.users_v3_client.delete_user, user_id)
+ project_id = self.admin_projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.addCleanup(self.admin_projects_client.delete_project, project_id)
+ role_id = self.admin_client.roles_v3_client.create_role(
+ name=data_utils.rand_name())['role']['id']
+ self.addCleanup(self.admin_client.roles_v3_client.delete_role,
+ role_id)
+ self.admin_client.roles_v3_client.create_user_role_on_project(
+ project_id, user_id, role_id)
+ self.do_request('list_user_projects', client=self.users_client,
+ expected_status=exceptions.Forbidden,
+ user_id=user_id)
+ # user can list projects for self
+ resp = self.do_request('list_user_projects', client=self.users_client,
+ user_id=self.persona.credentials.user_id)
+ self.assertIn(self.persona.credentials.project_id,
+ [p['id'] for p in resp['projects']])
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_project_endpoint.py b/keystone_tempest_plugin/tests/rbac/v3/test_project_endpoint.py
new file mode 100644
index 0000000..442ca9e
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_project_endpoint.py
@@ -0,0 +1,251 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacProjectEndpointsTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacProjectEndpointsTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.endpoint_filter_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_ef_client = cls.admin_client.endpoint_filter_client
+
+ @classmethod
+ def resource_setup(cls):
+ super(IdentityV3RbacProjectEndpointsTests, cls).resource_setup()
+ cls.project_id = cls.admin_client.projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.projects_client.delete_project,
+ project_id=cls.project_id)
+ service = cls.admin_client.identity_services_v3_client.create_service(
+ type=data_utils.rand_name())['service']
+ cls.addClassResourceCleanup(
+ cls.admin_client.identity_services_v3_client.delete_service,
+ service['id'])
+ cls.endpoint_id = cls.admin_client.endpoints_v3_client.create_endpoint(
+ interface='public',
+ url='http://localhost/foo',
+ service_id=service['id'])['endpoint']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.endpoints_v3_client.delete_endpoint,
+ endpoint_id=cls.endpoint_id)
+
+ @abc.abstractmethod
+ def test_identity_add_endpoint_to_project(self):
+ """Test identity:add_endpoint_to_project policy.
+
+ This test must check:
+ * whether the persona can allow a project to access an endpoint
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_check_endpoint_in_project(self):
+ """Test identity:check_endpoint_in_project policy.
+
+ This test must check:
+ * whether the persona can check if a project has access to an
+ endpoint
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_projects_for_endpoint(self):
+ """Test identity:list_projects_for_endpoint policy.
+
+ This test must check:
+ * whether the persona can list all projects that have access to an
+ endpoint
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_endpoints_for_project(self):
+ """Test identity:list_endpoints_for_project policy.
+
+ This test must check:
+ * whether the persona can list all endpoints to which a project has
+ access
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_remove_endpoint_from_project(self):
+ """Test identity:remove_endpoint_from_project policy.
+
+ This test must check
+ * whether the persona can remove a project's access to an endpoint
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacProjectEndpointsTests):
+
+ credentials = ['system_admin']
+
+ def test_identity_add_endpoint_to_project(self):
+ self.do_request('add_endpoint_to_project',
+ expected_status=204,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.addCleanup(self.admin_ef_client.delete_endpoint_from_project,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+
+ def test_identity_check_endpoint_in_project(self):
+ self.admin_ef_client.add_endpoint_to_project(
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.addCleanup(self.admin_ef_client.delete_endpoint_from_project,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.do_request('check_endpoint_in_project',
+ expected_status=204,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+
+ def test_identity_list_projects_for_endpoint(self):
+ self.admin_ef_client.add_endpoint_to_project(
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.addCleanup(self.admin_ef_client.delete_endpoint_from_project,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ resp = self.do_request('list_projects_for_endpoint',
+ endpoint_id=self.endpoint_id)
+ self.assertIn(self.project_id, [p['id'] for p in resp['projects']])
+
+ def test_identity_list_endpoints_for_project(self):
+ self.admin_ef_client.add_endpoint_to_project(
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.addCleanup(self.admin_ef_client.delete_endpoint_from_project,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ resp = self.do_request('list_endpoints_in_project',
+ project_id=self.project_id)
+ self.assertIn(self.endpoint_id, [e['id'] for e in resp['endpoints']])
+
+ def test_identity_remove_endpoint_from_project(self):
+ self.admin_ef_client.add_endpoint_to_project(
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.do_request('delete_endpoint_from_project',
+ expected_status=204,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_add_endpoint_to_project(self):
+ self.do_request('add_endpoint_to_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+
+ def test_identity_remove_endpoint_from_project(self):
+ self.admin_ef_client.add_endpoint_to_project(
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.addCleanup(self.admin_ef_client.delete_endpoint_from_project,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.do_request('delete_endpoint_from_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_check_endpoint_in_project(self):
+ self.admin_ef_client.add_endpoint_to_project(
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.addCleanup(self.admin_ef_client.delete_endpoint_from_project,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.do_request('check_endpoint_in_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+
+ def test_identity_list_projects_for_endpoint(self):
+ self.admin_ef_client.add_endpoint_to_project(
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.addCleanup(self.admin_ef_client.delete_endpoint_from_project,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.do_request('list_projects_for_endpoint',
+ expected_status=exceptions.Forbidden,
+ endpoint_id=self.endpoint_id)
+
+ def test_identity_list_endpoints_for_project(self):
+ self.admin_ef_client.add_endpoint_to_project(
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.addCleanup(self.admin_ef_client.delete_endpoint_from_project,
+ project_id=self.project_id,
+ endpoint_id=self.endpoint_id)
+ self.do_request('list_endpoints_in_project',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_id)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_project_tag.py b/keystone_tempest_plugin/tests/rbac/v3/test_project_tag.py
new file mode 100644
index 0000000..3e6c4a6
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_project_tag.py
@@ -0,0 +1,599 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacProjectTagTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacProjectTagTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.project_tags_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_project_tags_client = cls.admin_client.project_tags_client
+
+ @abc.abstractmethod
+ def test_identity_create_project_tag(self):
+ """Test identity:create_project_tag policy.
+
+ This test must check:
+ * whether the persona can create a tag for an arbitrary project
+ * whether the persona can create a tag for a project in their own
+ domain
+ * whether the persona can create a tag for a project in another
+ domain
+ * whether the persona can create a tag for their own project
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_project_tag(self):
+ """Test identity:get_project_tag policy.
+
+ This test must check:
+ * whether the persona can get a tag for an arbitrary project
+ * whether the persona can get a tag for a project in their own domain
+ * whether the persona can get a tag for a project in another domain
+ * whether the persona can get tag for their own project
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_project_tags(self):
+ """Test identity:list_project_tags policy.
+
+ This test must check:
+ * whether the persona can list tags for an arbitrary project
+ * whether the persona can list tags for a project in their own domain
+ * whether the persona can list tags for a project in another domain
+ * whether the persona can list tags for their own project
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_project_tags(self):
+ """Test identity:update_project_tags policy.
+
+ This test must check:
+ * whether the persona can update all tags for an project
+ * whether the persona can update all tags for a project in their own
+ domain
+ * whether the persona can update all tags for a project in another
+ domain
+ * whether the persona can update all tags for their own project
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_project_tag(self):
+ """Test identity:delete_project_tag policy.
+
+ This test must check
+ * whether the persona can delete a single tag for an arbitrary
+ project
+ * whether the persona can delete a single tag for a project in their
+ own domain
+ * whether the persona can delete a single tag for a project in
+ another domain
+ * whether the persona can delete a single tag for their own project
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_project_tags(self):
+ """Test identity:delete_project_tag policy.
+
+ This test must check
+ * whether the persona can delete all tags for an arbitrary project
+ * whether the persona can delete all tags for a project in their own
+ domain
+ * whether the persona can delete all tags for a project in another
+ domain
+ * whether the persona can delete all tags for their own project
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacProjectTagTests, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def setUp(self):
+ super(SystemAdminTests, self).setUp()
+ self.project_id = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.addCleanup(
+ self.admin_client.projects_client.delete_project, self.project_id)
+
+ def test_identity_create_project_tag(self):
+ self.do_request(
+ 'update_project_tag', expected_status=201,
+ project_id=self.project_id,
+ tag=data_utils.rand_uuid_hex()
+ )
+
+ def test_identity_get_project_tag(self):
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.project_id, tag=tag)
+ self.do_request('check_project_tag_existence',
+ expected_status=204,
+ project_id=self.project_id, tag=tag)
+
+ def test_identity_list_project_tags(self):
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.project_id, tag=tag)
+ resp = self.do_request('list_project_tags', project_id=self.project_id)
+ self.assertIn(tag, resp['tags'])
+
+ def test_identity_update_project_tags(self):
+ self.do_request('update_all_project_tags',
+ project_id=self.project_id,
+ tags=[data_utils.rand_uuid_hex()])
+
+ def test_identity_delete_project_tag(self):
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.project_id, tag=tag)
+ self.do_request('delete_project_tag', expected_status=204,
+ project_id=self.project_id,
+ tag=tag)
+
+ def test_identity_delete_project_tags(self):
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.project_id, tag=tag)
+ self.do_request('delete_all_project_tags', expected_status=204,
+ project_id=self.project_id)
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_project_tag(self):
+ self.do_request(
+ 'update_project_tag', expected_status=exceptions.Forbidden,
+ project_id=self.project_id,
+ tag=data_utils.rand_uuid_hex()
+ )
+
+ def test_identity_update_project_tags(self):
+ self.do_request('update_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_id,
+ tags=[data_utils.rand_uuid_hex()])
+
+ def test_identity_delete_project_tag(self):
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.project_id, tag=tag)
+ self.do_request('delete_project_tag',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_id,
+ tag=tag)
+
+ def test_identity_delete_project_tags(self):
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.project_id, tag=tag)
+ self.do_request('delete_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.project_id)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(IdentityV3RbacProjectTagTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def setUp(self):
+ super(DomainAdminTests, self).setUp()
+ self.own_domain = self.persona.credentials.domain_id
+ self.other_domain = self.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name())['domain']['id']
+ self.addCleanup(self.admin_client.domains_client.delete_domain,
+ self.other_domain)
+ self.addCleanup(self.admin_client.domains_client.update_domain,
+ domain_id=self.other_domain, enabled=False)
+ project_client = self.admin_client.projects_client
+ self.own_project_id = project_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.own_domain)['project']['id']
+ self.addCleanup(
+ project_client.delete_project,
+ self.own_project_id)
+ self.other_project_id = project_client.create_project(
+ name=data_utils.rand_name(),
+ domain_id=self.other_domain)['project']['id']
+ self.addCleanup(project_client.delete_project, self.other_project_id)
+
+ def test_identity_create_project_tag(self):
+ # user can add tags to project in own domain
+ tag = data_utils.rand_uuid_hex()
+ self.do_request(
+ 'update_project_tag', expected_status=201,
+ project_id=self.own_project_id,
+ tag=tag
+ )
+ # user cannot add tags to project in other domain
+ tag = data_utils.rand_uuid_hex()
+ self.do_request(
+ 'update_project_tag', expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id,
+ tag=tag
+ )
+
+ def test_identity_get_project_tag(self):
+ # user can get tag for project in own domain
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.own_project_id, tag=tag)
+ self.do_request('check_project_tag_existence',
+ expected_status=204,
+ project_id=self.own_project_id, tag=tag)
+ # user cannot get tag for project in other domain
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.other_project_id, tag=tag)
+ self.do_request('check_project_tag_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id, tag=tag)
+
+ def test_identity_list_project_tags(self):
+ # user can list tags for project in own domain
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.own_project_id, tag=tag)
+ resp = self.do_request('list_project_tags',
+ project_id=self.own_project_id)
+ self.assertIn(tag, resp['tags'])
+ # user cannot list tags for project in other domain
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.other_project_id, tag=tag)
+ self.do_request('list_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id)
+
+ def test_identity_update_project_tags(self):
+ # user can update tags for project in own domain
+ tag = data_utils.rand_uuid_hex()
+ self.do_request('update_all_project_tags',
+ project_id=self.own_project_id,
+ tags=[tag])
+ # user cannot update tags for project in other domain
+ tag = data_utils.rand_uuid_hex()
+ self.do_request('update_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id,
+ tags=[tag])
+
+ def test_identity_delete_project_tag(self):
+ # user can delete tag for project in own domain
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.own_project_id, tag=tag)
+ self.do_request('delete_project_tag', expected_status=204,
+ project_id=self.own_project_id,
+ tag=tag)
+ # user cannot delete tag for project in other domain
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.other_project_id, tag=tag)
+ self.do_request('delete_project_tag',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id,
+ tag=tag)
+
+ def test_identity_delete_project_tags(self):
+ # user can delete tags for project in own domain
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.own_project_id, tag=tag)
+ self.do_request('delete_all_project_tags', expected_status=204,
+ project_id=self.own_project_id)
+ # user cannot delete tags for project in other domain
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.other_project_id, tag=tag)
+ self.do_request('delete_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+ def test_identity_create_project_tag(self):
+ # user cannot add tags to project in own domain
+ tag = data_utils.rand_uuid_hex()
+ self.do_request(
+ 'update_project_tag', expected_status=exceptions.Forbidden,
+ project_id=self.own_project_id,
+ tag=tag
+ )
+ # user cannot add tags to project in other domain
+ tag = data_utils.rand_uuid_hex()
+ self.do_request(
+ 'update_project_tag', expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id,
+ tag=tag
+ )
+
+ def test_identity_update_project_tags(self):
+ # user cannot update tags for project in own domain
+ tag = data_utils.rand_uuid_hex()
+ self.do_request('update_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.own_project_id,
+ tags=[tag])
+ # user cannot update tags for project in other domain
+ tag = data_utils.rand_uuid_hex()
+ self.do_request('update_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id,
+ tags=[tag])
+
+ def test_identity_delete_project_tag(self):
+ # user cannot delete tag for project in own domain
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.own_project_id, tag=tag)
+ self.do_request('delete_project_tag',
+ expected_status=exceptions.Forbidden,
+ project_id=self.own_project_id,
+ tag=tag)
+ # user cannot delete tag for project in other domain
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.other_project_id, tag=tag)
+ self.do_request('delete_project_tag',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id,
+ tag=tag)
+
+ def test_identity_delete_project_tags(self):
+ # user cannot delete tags for project in own domain
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.own_project_id, tag=tag)
+ self.do_request('delete_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.own_project_id)
+ # user cannot delete tags for project in other domain
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.other_project_id, tag=tag)
+ self.do_request('delete_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id)
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(IdentityV3RbacProjectTagTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+ def setUp(self):
+ super(ProjectAdminTests, self).setUp()
+ self.own_project_id = self.persona.credentials.project_id
+ project_client = self.admin_client.projects_client
+ self.other_project_id = project_client.create_project(
+ name=data_utils.rand_name())['project']['id']
+ self.addCleanup(project_client.delete_project, self.other_project_id)
+
+ def test_identity_create_project_tag(self):
+ # user can add tags to own project
+ tag = data_utils.rand_uuid_hex()
+ self.do_request(
+ 'update_project_tag', expected_status=201,
+ project_id=self.own_project_id,
+ tag=tag
+ )
+ self.addCleanup(self.admin_project_tags_client.delete_project_tag,
+ project_id=self.own_project_id,
+ tag=tag)
+ # user cannot add tags to arbitrary project
+ tag = data_utils.rand_uuid_hex()
+ self.do_request(
+ 'update_project_tag', expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id,
+ tag=tag
+ )
+
+ def test_identity_get_project_tag(self):
+ # user can get tag for own project
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.own_project_id, tag=tag)
+ self.addCleanup(self.admin_project_tags_client.delete_project_tag,
+ project_id=self.own_project_id,
+ tag=tag)
+ self.do_request('check_project_tag_existence',
+ expected_status=204,
+ project_id=self.own_project_id, tag=tag)
+ # user cannot get tag for arbitrary project
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.other_project_id, tag=tag)
+ self.do_request('check_project_tag_existence',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id, tag=tag)
+
+ def test_identity_list_project_tags(self):
+ # user can list tags for own project
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.own_project_id, tag=tag)
+ self.addCleanup(self.admin_project_tags_client.delete_project_tag,
+ project_id=self.own_project_id,
+ tag=tag)
+ resp = self.do_request('list_project_tags',
+ project_id=self.own_project_id)
+ self.assertIn(tag, resp['tags'])
+ # user cannot list tags for arbitrary project
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.other_project_id, tag=tag)
+ self.do_request('list_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id)
+
+ def test_identity_update_project_tags(self):
+ # user can update tags for own project
+ tag = data_utils.rand_uuid_hex()
+ self.do_request('update_all_project_tags',
+ project_id=self.own_project_id,
+ tags=[tag])
+ self.addCleanup(self.admin_project_tags_client.delete_project_tag,
+ project_id=self.own_project_id,
+ tag=tag)
+ # user cannot update tags for arbitrary project
+ tag = data_utils.rand_uuid_hex()
+ self.do_request('update_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id,
+ tags=[tag])
+
+ def test_identity_delete_project_tag(self):
+ # user can delete tag for own project
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.own_project_id, tag=tag)
+ self.do_request('delete_project_tag', expected_status=204,
+ project_id=self.own_project_id,
+ tag=tag)
+ # user cannot delete tag for arbitrary project
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.other_project_id, tag=tag)
+ self.do_request('delete_project_tag',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id,
+ tag=tag)
+
+ def test_identity_delete_project_tags(self):
+ # user can delete tags for own project
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.own_project_id, tag=tag)
+ self.do_request('delete_all_project_tags', expected_status=204,
+ project_id=self.own_project_id)
+ # user cannot delete tags for arbitrary project
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.other_project_id, tag=tag)
+ self.do_request('delete_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id)
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+ def test_identity_create_project_tag(self):
+ # user cannot add tags to own project
+ tag = data_utils.rand_uuid_hex()
+ self.do_request(
+ 'update_project_tag', expected_status=exceptions.Forbidden,
+ project_id=self.own_project_id,
+ tag=tag
+ )
+ # user cannot add tags to arbitrary project
+ tag = data_utils.rand_uuid_hex()
+ self.do_request(
+ 'update_project_tag', expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id,
+ tag=tag
+ )
+
+ def test_identity_update_project_tags(self):
+ # user cannot update tags for own project
+ tag = data_utils.rand_uuid_hex()
+ self.do_request('update_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.own_project_id,
+ tags=[tag])
+ # user cannot update tags for arbitrary project
+ tag = data_utils.rand_uuid_hex()
+ self.do_request('update_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id,
+ tags=[tag])
+
+ def test_identity_delete_project_tag(self):
+ # user cannot delete tag for own project
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.own_project_id, tag=tag)
+ self.addCleanup(self.admin_project_tags_client.delete_project_tag,
+ project_id=self.own_project_id,
+ tag=tag)
+ self.do_request('delete_project_tag',
+ expected_status=exceptions.Forbidden,
+ project_id=self.own_project_id,
+ tag=tag)
+ # user cannot delete tag for arbitrary project
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.other_project_id, tag=tag)
+ self.do_request('delete_project_tag',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id,
+ tag=tag)
+
+ def test_identity_delete_project_tags(self):
+ # user cannot delete tags for own project
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.own_project_id, tag=tag)
+ self.addCleanup(self.admin_project_tags_client.delete_project_tag,
+ project_id=self.own_project_id,
+ tag=tag)
+ self.do_request('delete_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.own_project_id)
+ # user cannot delete tags for arbitrary project
+ tag = data_utils.rand_uuid_hex()
+ self.admin_project_tags_client.update_project_tag(
+ project_id=self.other_project_id, tag=tag)
+ self.do_request('delete_all_project_tags',
+ expected_status=exceptions.Forbidden,
+ project_id=self.other_project_id)
+
+
+class ProjectReaderTests(ProjectMemberTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_protocol.py b/keystone_tempest_plugin/tests/rbac/v3/test_protocol.py
new file mode 100644
index 0000000..5f9d9a2
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_protocol.py
@@ -0,0 +1,302 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin import clients
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacProtocolTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacProtocolTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.keystone_manager = clients.Manager(cls.persona.credentials)
+ persona_mgr = clients.Manager(cls.persona.credentials)
+ cls.client = persona_mgr.identity_providers_client
+ admin_client = cls.os_system_admin
+ admin_mgr = clients.Manager(admin_client.credentials)
+ cls.admin_idp_client = admin_mgr.identity_providers_client
+ cls.admin_mapping_client = admin_mgr.mapping_rules_client
+
+ @classmethod
+ def setUpClass(cls):
+ super(IdentityV3RbacProtocolTests, cls).setUpClass()
+ cls.idp_id = cls.admin_idp_client.create_identity_provider(
+ idp_id=data_utils.rand_name())['identity_provider']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_idp_client.delete_identity_provider, cls.idp_id)
+ rules = {
+ "rules":
+ [{
+ "local": [],
+ "remote": [{"type": data_utils.rand_name()}]
+ }]
+ }
+ cls.mapping_id = cls.admin_mapping_client.create_mapping_rule(
+ mapping_id=data_utils.rand_name(), rules=rules)['mapping']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_mapping_client.delete_mapping_rule,
+ mapping_id=cls.mapping_id)
+
+ @abc.abstractmethod
+ def test_identity_create_protocol(self):
+ """Test identity:create_protocol policy.
+
+ This test must check:
+ * whether the persona can create a protocol
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_protocol(self):
+ """Test identity:get_protocol policy.
+
+ This test must check:
+ * whether the persona can get a protocol
+ * whether the persona can get a protocol that does not
+ exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_protocols(self):
+ """Test identity:list_protocols policy.
+
+ This test must check:
+ * whether the persona can list all identity providers
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_protocol(self):
+ """Test identity:update_protocol policy.
+
+ This test must check:
+ * whether the persona can update a protocol
+ * whether the persona can update a protocol that does not
+ exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_protocol(self):
+ """Test identity:delete_protocol policy.
+
+ This test must check
+ * whether the persona can delete a protocol
+ * whether the persona can delete a protocol that does not
+ exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacProtocolTests, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_protocol(self):
+ protocol_id = self.do_request(
+ 'add_protocol_and_mapping', expected_status=201,
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_name(),
+ mapping_id=self.mapping_id
+ )['protocol']['id']
+ self.addCleanup(self.admin_idp_client.delete_protocol_and_mapping,
+ idp_id=self.idp_id,
+ protocol_id=protocol_id)
+
+ def test_identity_get_protocol(self):
+ protocol_id = self.admin_idp_client.add_protocol_and_mapping(
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_name(),
+ mapping_id=self.mapping_id)['protocol']['id']
+ self.addCleanup(self.admin_idp_client.delete_protocol_and_mapping,
+ idp_id=self.idp_id,
+ protocol_id=protocol_id)
+ self.do_request('get_protocol_and_mapping',
+ idp_id=self.idp_id,
+ protocol_id=protocol_id)
+ # user gets a 404 for nonexistent idp
+ self.do_request('get_protocol_and_mapping',
+ expected_status=exceptions.NotFound,
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_protocols(self):
+ protocol_id = self.admin_idp_client.add_protocol_and_mapping(
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_name(),
+ mapping_id=self.mapping_id)['protocol']['id']
+ self.addCleanup(self.admin_idp_client.delete_protocol_and_mapping,
+ idp_id=self.idp_id,
+ protocol_id=protocol_id)
+ resp = self.do_request('list_protocols_and_mappings',
+ idp_id=self.idp_id)
+ self.assertIn(protocol_id, [p['id'] for p in resp['protocols']])
+
+ def test_identity_update_protocol(self):
+ protocol_id = self.admin_idp_client.add_protocol_and_mapping(
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_name(),
+ mapping_id=self.mapping_id)['protocol']['id']
+ self.addCleanup(self.admin_idp_client.delete_protocol_and_mapping,
+ idp_id=self.idp_id,
+ protocol_id=protocol_id)
+ self.do_request('update_protocol_mapping',
+ idp_id=self.idp_id,
+ protocol_id=protocol_id,
+ mapping_id=self.mapping_id)
+ # user gets a 404 for nonexistent protocol
+ self.do_request('update_protocol_mapping',
+ expected_status=exceptions.NotFound,
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_uuid_hex(),
+ mapping_id=self.mapping_id)
+
+ def test_identity_delete_protocol(self):
+ protocol_id = self.admin_idp_client.add_protocol_and_mapping(
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_name(),
+ mapping_id=self.mapping_id)['protocol']['id']
+ self.do_request('delete_protocol_and_mapping', expected_status=204,
+ idp_id=self.idp_id,
+ protocol_id=protocol_id)
+ # user gets a 404 for nonexistent idp
+ self.do_request('delete_protocol_and_mapping',
+ expected_status=exceptions.NotFound,
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_uuid_hex())
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_protocol(self):
+ self.do_request('add_protocol_and_mapping',
+ expected_status=exceptions.Forbidden,
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_name(),
+ mapping_id=self.mapping_id)
+
+ def test_identity_update_protocol(self):
+ protocol_id = self.admin_idp_client.add_protocol_and_mapping(
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_name(),
+ mapping_id=self.mapping_id)['protocol']['id']
+ self.addCleanup(self.admin_idp_client.delete_protocol_and_mapping,
+ idp_id=self.idp_id,
+ protocol_id=protocol_id)
+ self.do_request('update_protocol_mapping',
+ expected_status=exceptions.Forbidden,
+ idp_id=self.idp_id,
+ protocol_id=protocol_id,
+ mapping_id=self.mapping_id)
+ # user gets a 403 for nonexistent protocol
+ self.do_request('update_protocol_mapping',
+ expected_status=exceptions.Forbidden,
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_uuid_hex(),
+ mapping_id=self.mapping_id)
+
+ def test_identity_delete_protocol(self):
+ protocol_id = self.admin_idp_client.add_protocol_and_mapping(
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_name(),
+ mapping_id=self.mapping_id)['protocol']['id']
+ self.addCleanup(self.admin_idp_client.delete_protocol_and_mapping,
+ idp_id=self.idp_id,
+ protocol_id=protocol_id)
+ self.do_request('delete_protocol_and_mapping',
+ expected_status=exceptions.Forbidden,
+ idp_id=self.idp_id,
+ protocol_id=protocol_id)
+ # user gets a 403 for nonexistent protocol
+ self.do_request('delete_protocol_and_mapping',
+ expected_status=exceptions.Forbidden,
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_uuid_hex())
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_protocol(self):
+ protocol_id = self.admin_idp_client.add_protocol_and_mapping(
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_name(),
+ mapping_id=self.mapping_id)['protocol']['id']
+ self.addCleanup(self.admin_idp_client.delete_protocol_and_mapping,
+ idp_id=self.idp_id,
+ protocol_id=protocol_id)
+ self.do_request('get_protocol_and_mapping',
+ expected_status=exceptions.Forbidden,
+ idp_id=self.idp_id,
+ protocol_id=protocol_id)
+ # user gets a 403 for nonexistent idp
+ self.do_request('get_protocol_and_mapping',
+ expected_status=exceptions.Forbidden,
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_protocols(self):
+ protocol_id = self.admin_idp_client.add_protocol_and_mapping(
+ idp_id=self.idp_id,
+ protocol_id=data_utils.rand_name(),
+ mapping_id=self.mapping_id)['protocol']['id']
+ self.addCleanup(self.admin_idp_client.delete_protocol_and_mapping,
+ idp_id=self.idp_id,
+ protocol_id=protocol_id)
+ self.do_request('list_protocols_and_mappings',
+ expected_status=exceptions.Forbidden,
+ idp_id=self.idp_id)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_region.py b/keystone_tempest_plugin/tests/rbac/v3/test_region.py
new file mode 100644
index 0000000..e58206a
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_region.py
@@ -0,0 +1,209 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacRegionTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacRegionTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.regions_client
+ admin_client = cls.os_system_admin
+ cls.admin_regions_client = admin_client.regions_client
+
+ def region(self):
+ return {'region_id': data_utils.rand_uuid_hex()}
+
+ @abc.abstractmethod
+ def test_identity_create_region(self):
+ """Test identity:create_region policy.
+
+ This test must check:
+ * whether the persona can create a region
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_region(self):
+ """Test identity:get_region policy.
+
+ This test must check:
+ * whether the persona can get a region
+ * whether the persona can get a region that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_regions(self):
+ """Test identity:list_regions policy.
+
+ This test must check:
+ * whether the persona can list all regions
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_region(self):
+ """Test identity:update_region policy.
+
+ This test must check:
+ * whether the persona can update a region
+ * whether the persona can update a region that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_region(self):
+ """Test identity:delete_region policy.
+
+ This test must check
+ * whether the persona can delete a region
+ * whether the persona can delete a region that does not exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacRegionTests, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_region(self):
+ region_id = self.do_request(
+ 'create_region', expected_status=201,
+ **self.region())['region']['id']
+ self.addCleanup(
+ self.admin_regions_client.delete_region,
+ region_id=region_id)
+
+ def test_identity_get_region(self):
+ region_id = self.admin_regions_client.create_region(
+ **self.region())['region']['id']
+ self.addCleanup(
+ self.admin_regions_client.delete_region,
+ region_id=region_id)
+ self.do_request('show_region', region_id=region_id)
+ # user gets a 404 for nonexistent region
+ self.do_request('show_region', expected_status=exceptions.NotFound,
+ region_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_regions(self):
+ region_id = self.admin_regions_client.create_region(
+ **self.region())['region']['id']
+ self.addCleanup(
+ self.admin_regions_client.delete_region,
+ region_id=region_id)
+ resp = self.do_request('list_regions')
+ self.assertIn(region_id, [e['id'] for e in resp['regions']])
+
+ def test_identity_update_region(self):
+ region_id = self.admin_regions_client.create_region(
+ **self.region())['region']['id']
+ self.addCleanup(
+ self.admin_regions_client.delete_region,
+ region_id=region_id)
+ self.do_request('update_region',
+ region_id=region_id,
+ description=data_utils.rand_uuid_hex())
+ # user gets a 404 for nonexistent region
+ self.do_request('update_region', expected_status=exceptions.NotFound,
+ region_id=data_utils.rand_uuid_hex(),
+ description=data_utils.rand_uuid_hex())
+
+ def test_identity_delete_region(self):
+ region_id = self.admin_regions_client.create_region(
+ **self.region())['region']['id']
+ self.do_request('delete_region', expected_status=204,
+ region_id=region_id)
+ # user gets a 404 for nonexistent region
+ self.do_request('delete_region', expected_status=exceptions.NotFound,
+ region_id=data_utils.rand_uuid_hex())
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_region(self):
+ self.do_request(
+ 'create_region', expected_status=exceptions.Forbidden,
+ **self.region())
+
+ def test_identity_update_region(self):
+ region_id = self.admin_regions_client.create_region(
+ **self.region())['region']['id']
+ self.addCleanup(
+ self.admin_regions_client.delete_region,
+ region_id=region_id)
+ self.do_request('update_region', expected_status=exceptions.Forbidden,
+ region_id=region_id,
+ description=data_utils.rand_uuid_hex())
+ # user gets a 403 for nonexistent region
+ self.do_request('update_region', expected_status=exceptions.Forbidden,
+ region_id=data_utils.rand_uuid_hex(),
+ description=data_utils.rand_uuid_hex())
+
+ def test_identity_delete_region(self):
+ region_id = self.admin_regions_client.create_region(
+ **self.region())['region']['id']
+ self.do_request('delete_region',
+ expected_status=exceptions.Forbidden,
+ region_id=region_id)
+ # user gets a 403 for nonexistent region
+ self.do_request('delete_region', expected_status=exceptions.Forbidden,
+ region_id=data_utils.rand_uuid_hex())
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_registered_limit.py b/keystone_tempest_plugin/tests/rbac/v3/test_registered_limit.py
new file mode 100644
index 0000000..c18ed01
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_registered_limit.py
@@ -0,0 +1,222 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin import clients
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacRegisteredLimitTests(
+ rbac_base.IdentityV3RbacBaseTests, metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacRegisteredLimitTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ persona_mgr = clients.Manager(cls.persona.credentials)
+ cls.client = persona_mgr.registered_limits_client
+ cls.admin_client = cls.os_system_admin
+ admin_mgr = clients.Manager(cls.admin_client.credentials)
+ cls.admin_reglim_client = admin_mgr.registered_limits_client
+
+ @classmethod
+ def resource_setup(cls):
+ cls.region_id = cls.admin_client.regions_client.create_region(
+ region_id=data_utils.rand_name())['region']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.regions_client.delete_region,
+ cls.region_id)
+ svc_client = cls.admin_client.identity_services_v3_client
+ cls.service_id = svc_client.create_service(
+ type=data_utils.rand_name())['service']['id']
+ cls.addClassResourceCleanup(svc_client.delete_service, cls.service_id)
+
+ def registered_limits(self):
+ return [
+ {
+ "service_id": self.service_id,
+ "region_id": self.region_id,
+ "resource_name": data_utils.rand_name(),
+ "default_limit": 5,
+ "description": data_utils.arbitrary_string()
+ }
+ ]
+
+ @abc.abstractmethod
+ def test_identity_create_registered_limits(self):
+ """Test identity:create_registered_limits policy.
+
+ This test must check:
+ * whether the persona can create a registered limit
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_registered_limits(self):
+ """Test identity:list_registered_limits policy.
+
+ This test must check:
+ * whether the persona can list registered limits
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_registered_limit(self):
+ """Test identity:get_registered_limit policy.
+
+ This test must check:
+ * whether the persona can get a registered limit
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_registered_limit(self):
+ """Test identity:update_registered_limit policy.
+
+ This test must check:
+ * whether the persona can update a registered limit
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_registered_limit(self):
+ """Test identity:delete_registered_limit policy.
+
+ This test must check:
+ * whether the persona can delete a registered limit
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacRegisteredLimitTests,
+ base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_registered_limits(self):
+ resp = self.do_request('create_registered_limits',
+ expected_status=201,
+ payload=self.registered_limits())
+ self.addCleanup(
+ self.admin_reglim_client.delete_registered_limit,
+ registered_limit_id=resp['registered_limits'][0]['id'])
+
+ def test_identity_list_registered_limits(self):
+ reg_limit_id = self.admin_reglim_client.create_registered_limits(
+ payload=self.registered_limits())['registered_limits'][0]['id']
+ self.addCleanup(
+ self.admin_reglim_client.delete_registered_limit,
+ registered_limit_id=reg_limit_id)
+ resp = self.do_request('list_registered_limits')
+ self.assertIn(
+ reg_limit_id, [rl['id'] for rl in resp['registered_limits']])
+
+ def test_identity_get_registered_limit(self):
+ reg_limit_id = self.admin_reglim_client.create_registered_limits(
+ payload=self.registered_limits())['registered_limits'][0]['id']
+ self.addCleanup(
+ self.admin_reglim_client.delete_registered_limit,
+ registered_limit_id=reg_limit_id)
+ self.do_request('show_registered_limit',
+ registered_limit_id=reg_limit_id)
+
+ def test_identity_update_registered_limit(self):
+ reg_limit_id = self.admin_reglim_client.create_registered_limits(
+ payload=self.registered_limits())['registered_limits'][0]['id']
+ self.addCleanup(
+ self.admin_reglim_client.delete_registered_limit,
+ registered_limit_id=reg_limit_id)
+ updated = {'description': data_utils.arbitrary_string()}
+ self.do_request('update_registered_limit',
+ registered_limit_id=reg_limit_id,
+ registered_limit=updated)
+
+ def test_identity_delete_registered_limit(self):
+ reg_limit_id = self.admin_reglim_client.create_registered_limits(
+ payload=self.registered_limits())['registered_limits'][0]['id']
+ self.do_request('delete_registered_limit',
+ expected_status=204,
+ registered_limit_id=reg_limit_id)
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_registered_limits(self):
+ self.do_request('create_registered_limits',
+ expected_status=exceptions.Forbidden,
+ payload=self.registered_limits())
+
+ def test_identity_update_registered_limit(self):
+ reg_limit_id = self.admin_reglim_client.create_registered_limits(
+ payload=self.registered_limits())['registered_limits'][0]['id']
+ self.addCleanup(
+ self.admin_reglim_client.delete_registered_limit,
+ registered_limit_id=reg_limit_id)
+ updated = {'description': data_utils.arbitrary_string()}
+ self.do_request('update_registered_limit',
+ expected_status=exceptions.Forbidden,
+ registered_limit_id=reg_limit_id,
+ registered_limit=updated)
+
+ def test_identity_delete_registered_limit(self):
+ reg_limit_id = self.admin_reglim_client.create_registered_limits(
+ payload=self.registered_limits())['registered_limits'][0]['id']
+ self.addCleanup(
+ self.admin_reglim_client.delete_registered_limit,
+ registered_limit_id=reg_limit_id)
+ self.do_request('delete_registered_limit',
+ expected_status=exceptions.Forbidden,
+ registered_limit_id=reg_limit_id)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests):
+
+ credentials = ['domain_admin', 'system_admin']
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectMemberTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_role.py b/keystone_tempest_plugin/tests/rbac/v3/test_role.py
new file mode 100644
index 0000000..a9815e8
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_role.py
@@ -0,0 +1,390 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacRoleTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacRoleTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.roles_v3_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_roles_client = cls.admin_client.roles_v3_client
+
+ @classmethod
+ def resource_setup(cls):
+ super(IdentityV3RbacRoleTest, cls).resource_setup()
+ cls.own_domain = cls.persona.credentials.domain_id
+ cls.domain_id = cls.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name('domain'))['domain']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.delete_domain,
+ cls.domain_id)
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.update_domain,
+ cls.domain_id,
+ enabled=False)
+
+ def role(self, domain_id=None):
+ role = {}
+ name = data_utils.rand_name('role')
+ role['name'] = name
+ if domain_id:
+ role['domain_id'] = domain_id
+ return role
+
+ @abc.abstractmethod
+ def test_identity_create_role(self):
+ """Test identity:create_role policy.
+
+ This test must check:
+ * whether the persona can create a role
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_role(self):
+ """Test identity:get_role policy.
+
+ This test must check:
+ * whether the persona can get a role
+ * whether the persona can get a role that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_roles(self):
+ """Test identity:list_roles policy.
+
+ This test must check:
+ * whether the persona can list roles
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_role(self):
+ """Test identity:update_role policy.
+
+ This test must check:
+ * whether the persona can update a role
+ * whether the persona can update a role that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_role(self):
+ """Test identity:delete_role policy.
+
+ This test must check
+ * whether the persona can delete a role
+ * whether the persona can delete a role that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_create_domain_role(self):
+ """Test identity:create_domain_role policy.
+
+ This test must check:
+ * whether the persona can create a domain role in their own domain
+ * whether the persona can create a domain role in another domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_domain_role(self):
+ """Test identity:get_domain_role policy.
+
+ This test must check:
+ * whether the persona can get a domain role in their own domain
+ * whether the persona can get a domain role in another domain
+ * whether the persona can get a domain role that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_domain_roles(self):
+ """Test identity:list_domain_roles policy.
+
+ This test must check:
+ * whether the persona can list domain roles for their own domain
+ * whether the persona can list domain roles for another domain
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_domain_role(self):
+ """Test identity:update_domain_role policy.
+
+ This test must check:
+ * whether the persona can update a domain role for their own domain
+ * whether the persona can update a domain role for another domain
+ * whether the persona can update a domain role that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_domain_role(self):
+ """Test identity:delete_domain_role policy.
+
+ This test must check
+ * whether the persona can delete a domain role for their own domain
+ * whether the persona can delete a domain role for another domain
+ * whether the persona can delete a domain role that does not exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacRoleTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_role(self):
+ # user can create role
+ resp = self.do_request('create_role',
+ expected_status=201,
+ **self.role())
+ self.addCleanup(self.admin_roles_client.delete_role,
+ resp['role']['id'])
+
+ def test_identity_get_role(self):
+ # user can get role
+ role = self.admin_roles_client.create_role(**self.role())['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('show_role', role_id=role['id'])
+ # user gets a 404 for nonexistent role
+ self.do_request('show_role', expected_status=exceptions.NotFound,
+ role_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_roles(self):
+ # user can list roles
+ role = self.admin_roles_client.create_role(**self.role())['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('list_roles')
+
+ def test_identity_update_role(self):
+ # user can update role
+ role = self.admin_roles_client.create_role(**self.role())['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('update_role',
+ role_id=role['id'],
+ description=data_utils.arbitrary_string())
+ # user gets a 404 for nonexistent role
+ self.do_request('update_role', expected_status=exceptions.NotFound,
+ role_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_role(self):
+ # user can delete role
+ role = self.admin_roles_client.create_role(**self.role())['role']
+ self.do_request('delete_role', expected_status=204, role_id=role['id'])
+ # user gets a 404 for nonexistent role
+ self.do_request('delete_role', expected_status=exceptions.NotFound,
+ role_id=data_utils.rand_uuid_hex())
+
+ def test_identity_create_domain_role(self):
+ # user can create domain role
+ resp = self.do_request('create_role',
+ expected_status=201,
+ **self.role(domain_id=self.domain_id))
+ self.addCleanup(self.admin_roles_client.delete_role,
+ resp['role']['id'])
+
+ def test_identity_get_domain_role(self):
+ # user can get domain role
+ role = self.admin_roles_client.create_role(
+ **self.role(domain_id=self.domain_id))['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('show_role', role_id=role['id'])
+ # user gets a 404 for nonexistent domain role
+ self.do_request('show_role', expected_status=exceptions.NotFound,
+ role_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_domain_roles(self):
+ # user can list domain roles
+ role = self.admin_roles_client.create_role(
+ **self.role(domain_id=self.domain_id))['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('list_roles', domain_id=self.domain_id)
+
+ def test_identity_update_domain_role(self):
+ # user can update domain role
+ role = self.admin_roles_client.create_role(
+ **self.role(domain_id=self.domain_id))['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('update_role',
+ role_id=role['id'],
+ description=data_utils.arbitrary_string())
+ # user gets a 404 for nonexistent domain role
+ self.do_request('update_role', expected_status=exceptions.NotFound,
+ role_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_domain_role(self):
+ # user can delete role in other domain
+ role = self.admin_roles_client.create_role(
+ **self.role(domain_id=self.domain_id))['role']
+ self.do_request('delete_role', expected_status=204, role_id=role['id'])
+ # user gets a 404 for nonexistent role
+ self.do_request('delete_role', expected_status=exceptions.NotFound,
+ role_id=data_utils.rand_uuid_hex())
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_role(self):
+ # user cannot create role
+ self.do_request('create_role',
+ expected_status=exceptions.Forbidden,
+ **self.role())
+
+ def test_identity_update_role(self):
+ # user cannot update role
+ role = self.admin_roles_client.create_role(
+ **self.role())['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('update_role', expected_status=exceptions.Forbidden,
+ role_id=role['id'],
+ description=data_utils.arbitrary_string())
+ # user gets a 404 for nonexistent role
+ self.do_request('update_role', expected_status=exceptions.NotFound,
+ role_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_role(self):
+ # user can delete role
+ role = self.admin_roles_client.create_role(
+ **self.role())['role']
+ self.do_request('delete_role', expected_status=exceptions.Forbidden,
+ role_id=role['id'])
+ # user gets a 404 for nonexistent domain role
+ self.do_request('delete_role', expected_status=exceptions.NotFound,
+ role_id=data_utils.rand_uuid_hex())
+
+ def test_identity_create_domain_role(self):
+ # user cannot create domain role
+ self.do_request('create_role',
+ expected_status=exceptions.Forbidden,
+ **self.role(domain_id=self.domain_id))
+
+ def test_identity_update_domain_role(self):
+ # user cannot update domain role
+ role = self.admin_roles_client.create_role(
+ **self.role(domain_id=self.domain_id))['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('update_role', expected_status=exceptions.Forbidden,
+ role_id=role['id'],
+ description=data_utils.arbitrary_string())
+ # user gets a 404 for nonexistent domain role
+ self.do_request('update_role', expected_status=exceptions.NotFound,
+ role_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_domain_role(self):
+ # user can delete domain role
+ role = self.admin_roles_client.create_role(
+ **self.role(domain_id=self.domain_id))['role']
+ self.do_request('delete_role', expected_status=exceptions.Forbidden,
+ role_id=role['id'])
+ # user gets a 404 for nonexistent domain role
+ self.do_request('delete_role', expected_status=exceptions.NotFound,
+ role_id=data_utils.rand_uuid_hex())
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_role(self):
+ # user cannot get role
+ role = self.admin_roles_client.create_role(
+ **self.role())['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('show_role', expected_status=exceptions.Forbidden,
+ role_id=role['id'])
+ # user gets a 404 for nonexistent role
+ self.do_request('show_role', expected_status=exceptions.NotFound,
+ role_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_roles(self):
+ # user cannot list roles
+ role = self.admin_roles_client.create_role(**self.role())['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('list_roles', expected_status=exceptions.Forbidden)
+
+ def test_identity_get_domain_role(self):
+ # user cannot get domain role in own domain
+ role = self.admin_roles_client.create_role(**self.role())['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('show_role', expected_status=exceptions.Forbidden,
+ role_id=role['id'])
+ # user gets a 404 for nonexistent domain role
+ self.do_request('show_role', expected_status=exceptions.NotFound,
+ role_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_domain_roles(self):
+ # user cannot list domain roles in own domain
+ role = self.admin_roles_client.create_role(
+ **self.role(domain_id=self.own_domain))['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('list_roles', expected_status=exceptions.Forbidden,
+ domain_id=self.persona.credentials.domain_id)
+ # user cannot get domain role in other domain
+ role = self.admin_roles_client.create_role(
+ **self.role(domain_id=self.domain_id))['role']
+ self.addCleanup(self.admin_roles_client.delete_role, role['id'])
+ self.do_request('list_roles', expected_status=exceptions.Forbidden,
+ domain_id=self.domain_id)
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_role_assignment.py b/keystone_tempest_plugin/tests/rbac/v3/test_role_assignment.py
new file mode 100644
index 0000000..7b27294
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_role_assignment.py
@@ -0,0 +1,1130 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacAssignmentTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacAssignmentTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.role_assignments_client
+ cls.admin_client = cls.os_system_admin
+
+ @classmethod
+ def resource_setup(cls):
+ super(IdentityV3RbacAssignmentTest, cls).resource_setup()
+ cls._setup_assignments()
+
+ @classmethod
+ def _setup_assignments(cls):
+ cls.own_domain = cls.persona.credentials.domain_id
+ cls.role_id = cls.admin_client.roles_v3_client.create_role(
+ name=data_utils.rand_name('role'))['role']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.roles_v3_client.delete_role, cls.role_id)
+ cls.user_in_domain = cls.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=cls.own_domain)['user']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.users_v3_client.delete_user,
+ cls.user_in_domain)
+ cls.group_in_domain = cls.admin_client.groups_client.create_group(
+ name=data_utils.rand_name('group'),
+ domain_id=cls.own_domain)['group']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.groups_client.delete_group,
+ cls.group_in_domain)
+ cls.project_in_domain = (
+ cls.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'),
+ domain_id=cls.own_domain)['project']['id'])
+ cls.addClassResourceCleanup(
+ cls.admin_client.projects_client.delete_project,
+ cls.project_in_domain)
+ cls.other_domain = cls.admin_client.domains_client.create_domain(
+ name=data_utils.rand_name('domain'))['domain']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.delete_domain,
+ cls.other_domain)
+ cls.addClassResourceCleanup(
+ cls.admin_client.domains_client.update_domain,
+ cls.other_domain,
+ enabled=False)
+ cls.user_other_domain = cls.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name('user'),
+ domain_id=cls.other_domain)['user']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.users_v3_client.delete_user,
+ cls.user_other_domain)
+ cls.group_other_domain = cls.admin_client.groups_client.create_group(
+ name=data_utils.rand_name('group'),
+ domain_id=cls.other_domain)['group']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.groups_client.delete_group,
+ cls.group_other_domain)
+ cls.project_other_domain = (
+ cls.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'),
+ domain_id=cls.other_domain)['project']['id'])
+ cls.addClassResourceCleanup(
+ cls.admin_client.projects_client.delete_project,
+ cls.project_other_domain)
+
+ roles_client = cls.admin_client.roles_v3_client
+ roles_client.create_user_role_on_project(
+ cls.project_in_domain,
+ cls.user_in_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_project(
+ cls.project_in_domain,
+ cls.user_other_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_project(
+ cls.project_other_domain,
+ cls.user_in_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_project(
+ cls.project_other_domain,
+ cls.user_other_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_domain(
+ cls.own_domain,
+ cls.user_in_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_domain(
+ cls.own_domain,
+ cls.user_other_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_domain(
+ cls.other_domain,
+ cls.user_in_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_domain(
+ cls.other_domain,
+ cls.user_other_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_system(
+ cls.user_in_domain,
+ cls.role_id)
+ roles_client.create_user_role_on_system(
+ cls.user_other_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_project(
+ cls.project_in_domain,
+ cls.group_in_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_project(
+ cls.project_in_domain,
+ cls.group_other_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_project(
+ cls.project_other_domain,
+ cls.group_in_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_project(
+ cls.project_other_domain,
+ cls.group_other_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_domain(
+ cls.own_domain,
+ cls.group_in_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_domain(
+ cls.own_domain,
+ cls.group_other_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_domain(
+ cls.other_domain,
+ cls.group_in_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_domain(
+ cls.other_domain,
+ cls.group_other_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_system(
+ cls.group_in_domain,
+ cls.role_id)
+ roles_client.create_group_role_on_system(
+ cls.group_other_domain,
+ cls.role_id)
+
+ cls.assignments = [
+ {
+ 'user_id': cls.user_in_domain,
+ 'project_id': cls.project_in_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'user_id': cls.user_other_domain,
+ 'project_id': cls.project_in_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'user_id': cls.user_in_domain,
+ 'project_id': cls.project_other_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'user_id': cls.user_other_domain,
+ 'project_id': cls.project_other_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'user_id': cls.user_in_domain,
+ 'domain_id': cls.own_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'user_id': cls.user_other_domain,
+ 'domain_id': cls.own_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'user_id': cls.user_in_domain,
+ 'domain_id': cls.other_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'user_id': cls.user_other_domain,
+ 'domain_id': cls.other_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'user_id': cls.user_in_domain,
+ 'system': 'all',
+ 'role_id': cls.role_id
+ },
+ {
+ 'user_id': cls.user_other_domain,
+ 'system': 'all',
+ 'role_id': cls.role_id
+ },
+ {
+ 'group_id': cls.group_in_domain,
+ 'project_id': cls.project_in_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'group_id': cls.group_other_domain,
+ 'project_id': cls.project_in_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'group_id': cls.group_in_domain,
+ 'project_id': cls.project_other_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'group_id': cls.group_other_domain,
+ 'project_id': cls.project_other_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'group_id': cls.group_in_domain,
+ 'domain_id': cls.own_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'group_id': cls.group_other_domain,
+ 'domain_id': cls.own_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'group_id': cls.group_in_domain,
+ 'domain_id': cls.other_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'group_id': cls.group_other_domain,
+ 'domain_id': cls.other_domain,
+ 'role_id': cls.role_id
+ },
+ {
+ 'group_id': cls.group_in_domain,
+ 'system': 'all',
+ 'role_id': cls.role_id
+ },
+ {
+ 'group_id': cls.group_other_domain,
+ 'system': 'all',
+ 'role_id': cls.role_id
+ },
+ ]
+
+ def _extract_role_assignments_from_response_body(self, r):
+ # Condense the role assignment details into a set of key things we can
+ # use in assertions.
+ assignments = []
+ for assignment in r['role_assignments']:
+ a = {}
+ if 'project' in assignment['scope']:
+ a['project_id'] = assignment['scope']['project']['id']
+ elif 'domain' in assignment['scope']:
+ a['domain_id'] = assignment['scope']['domain']['id']
+ elif 'system' in assignment['scope']:
+ a['system'] = 'all'
+
+ if 'user' in assignment:
+ a['user_id'] = assignment['user']['id']
+ elif 'group' in assignment:
+ a['group_id'] = assignment['group']['id']
+
+ a['role_id'] = assignment['role']['id']
+
+ assignments.append(a)
+ return assignments
+
+ @abc.abstractmethod
+ def test_identity_list_role_assignments(self):
+ """Test identity:list_role_assignments policy.
+
+ This test must check:
+ * whether the persona can list all user and group assignments across
+ the deployment
+ * whether the persona can list all user and group assignments in
+ a domain
+ * whether the persona can list user and group assignments with names
+ * whether the persona can filter user and group assignments by domain
+ * whether the persona can filter user and group assignments by
+ project in their own domain
+ * whether the persona can filter user and group assignments by
+ project in another domain
+ * whether the persona can filter user and group assignments by system
+ * whether the persona can filter user assignments by user in their
+ own domain
+ * whether the persona can filter user assignments by user in another
+ domain
+ * whether the persona can filter group assignments by group in their
+ own domain
+ * whether the persona can filter group assignments by group in
+ another domain
+ * whether the persona can filter role assignments by global role
+ * whether the persona can filter assignments by project and role
+ * whether the persona can filter assignments by domain and role
+ * whether the persona can filter assignments by system and role
+ * whether the persona can filter assignments by user and role
+ * whether the persona can filter assignments by group and role
+ * whether the persona can filter assignments by project and user
+ * whether the persona can filter assignments by project and group
+ * whether the persona can filter assignments by domain and user
+ * whether the persona can filter assignments by domain and group
+
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_role_assignments_for_tree(self):
+ """Test identity:list_role_assignments_for_tree policy.
+
+ This test must check:
+ * whether the persona can list role assignments for a subtree of a
+ project in their own domain
+ * whether the persona can list role assignments for a subtree of a
+ project in another domain
+ * whether the persona can list role assignments for a subtree of a
+ project on which they have a role assignment (if applicable)
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacAssignmentTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_list_role_assignments(self):
+ # Listing all assignments with no filters should return all assignments
+ resp = self.do_request('list_role_assignments')
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in self.assignments:
+ self.assertIn(assignment, actual)
+
+ # Listing all assignments with names
+ query = {'include_names': True}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in self.assignments:
+ self.assertIn(assignment, actual)
+
+ # Filter assignments by own domain should succeed
+ expected = [a for a in self.assignments
+ if a.get('domain_id') == self.own_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'scope.domain.id': self.own_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by other domain should succeed
+ expected = [a for a in self.assignments
+ if a.get('domain_id') == self.other_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'scope.domain.id': self.other_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by project in own domain should succeed
+ expected = [a for a in self.assignments
+ if a.get('project_id') == self.project_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'scope.project.id': self.project_in_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by project in other domain should succeed
+ expected = [a for a in self.assignments
+ if a.get('project_id') == self.project_other_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'scope.project.id': self.project_other_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by system should succeed
+ expected = [a for a in self.assignments if a.get('system') == 'all']
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'scope.system': 'all'}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by user in own domain should succeed
+ expected = [a for a in self.assignments
+ if a.get('user_id') == self.user_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'user.id': self.user_in_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by user in other domain should succeed
+ expected = [a for a in self.assignments
+ if a.get('user_id') == self.user_other_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'user.id': self.user_other_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by group in own domain should succeed
+ expected = [a for a in self.assignments
+ if a.get('group_id') == self.group_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'group.id': self.group_in_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by group in other domain should succeed
+ expected = [a for a in self.assignments
+ if a.get('group_id') == self.group_other_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'group.id': self.group_other_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by global role should succeed
+ expected = self.assignments
+ query = {'role.id': self.role_id}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ # Reverse the check: only ephemeral tempest roles should be in the list
+ for assignment in actual:
+ self.assertIn(assignment, expected)
+
+ # Filter assignments by project and role should succeed
+ expected = [a for a in self.assignments
+ if a.get('project_id') == self.project_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'scope.project.id': self.project_in_domain,
+ 'role.id': self.role_id}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+ # Reverse the check: only ephemeral tempest roles should be in the list
+ for assignment in actual:
+ self.assertIn(assignment, expected)
+
+ # Filter assignments by domain and role should succeed
+ expected = [a for a in self.assignments
+ if a.get('domain_id') == self.other_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'scope.domain.id': self.other_domain, 'role.id': self.role_id}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+ # Reverse the check: only ephemeral tempest roles should be in the list
+ for assignment in actual:
+ self.assertIn(assignment, expected)
+
+ # Filter assignments by system and role should succeed
+ expected = [a for a in self.assignments if a.get('system') == 'all']
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'scope.system': 'all', 'role.id': self.role_id}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+ # Reverse the check: only ephemeral tempest roles should be in the list
+ for assignment in actual:
+ self.assertIn(assignment, expected)
+
+ # Filter assignments by user and role should succeed
+ expected = [a for a in self.assignments
+ if a.get('user_id') == self.user_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'user.id': self.user_in_domain, 'role.id': self.role_id}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+ # Reverse the check: only ephemeral tempest roles should be in the list
+ for assignment in actual:
+ self.assertIn(assignment, expected)
+
+ # Filter assignments by group and role should succeed
+ expected = [a for a in self.assignments
+ if a.get('group_id') == self.group_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'group.id': self.group_in_domain, 'role.id': self.role_id}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+ # Reverse the check: only ephemeral tempest roles should be in the list
+ for assignment in actual:
+ self.assertIn(assignment, expected)
+
+ # Filter assignments by project and user should succeed
+ expected = [a for a in self.assignments
+ if a.get('project_id') == self.project_in_domain
+ and a.get('user_id') == self.user_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'user.id': self.user_in_domain,
+ 'scope.project.id': self.project_in_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by project and group should succeed
+ expected = [a for a in self.assignments
+ if a.get('project_id') == self.project_in_domain
+ and a.get('group_id') == self.group_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'group.id': self.group_in_domain,
+ 'scope.project.id': self.project_in_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by domain and user should succeed
+ expected = [a for a in self.assignments
+ if a.get('domain_id') == self.own_domain
+ and a.get('user_id') == self.user_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'user.id': self.user_in_domain,
+ 'scope.domain.id': self.own_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by domain and group should succeed
+ expected = [a for a in self.assignments
+ if a.get('domain_id') == self.own_domain
+ and a.get('group_id') == self.group_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'group.id': self.group_in_domain,
+ 'scope.domain.id': self.own_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ def test_identity_list_role_assignments_for_tree(self):
+ # Should see subtree assignments for project in own domain
+ subproject_id = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'),
+ domain_id=self.own_domain,
+ parent_id=self.project_in_domain)['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ subproject_id)
+ self.admin_client.roles_v3_client.create_user_role_on_project(
+ subproject_id, self.user_in_domain, self.role_id)
+ query = {'scope.project.id': self.project_in_domain,
+ 'include_subtree': True}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ expected_assignment = {'user_id': self.user_in_domain,
+ 'project_id': subproject_id,
+ 'role_id': self.role_id}
+ self.assertIn(expected_assignment, actual)
+
+ # Should see subtree assignments for project in other domain
+ subproject_id = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'),
+ domain_id=self.other_domain,
+ parent_id=self.project_other_domain)['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ subproject_id)
+ self.admin_client.roles_v3_client.create_user_role_on_project(
+ subproject_id, self.user_in_domain, self.role_id)
+ query = {'scope.project.id': self.project_other_domain,
+ 'include_subtree': True}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ expected_assignment = {'user_id': self.user_in_domain,
+ 'project_id': subproject_id,
+ 'role_id': self.role_id}
+ self.assertIn(expected_assignment, actual)
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(IdentityV3RbacAssignmentTest, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_list_role_assignments(self):
+ # Listing all assignments with no filters should only return
+ # assignments in own domain
+ expected = [a for a in self.assignments
+ if a.get('project_id') == self.project_in_domain
+ or a.get('domain_id') == self.own_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ resp = self.do_request('list_role_assignments')
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Listing all assignments with names and no filters should only return
+ # assignments in own domain
+ query = {'include_names': True}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by own domain should succeed
+ expected = [a for a in self.assignments
+ if a.get('domain_id') == self.own_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'scope.domain.id': self.own_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by other domain should be empty
+ query = {'scope.domain.id': self.other_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ self.assertEmpty(actual)
+
+ # Filter assignments by project in own domain should succeed
+ expected = [a for a in self.assignments
+ if a.get('project_id') == self.project_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'scope.project.id': self.project_in_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by project in other domain should be empty
+ query = {'scope.project.id': self.project_other_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ self.assertEmpty(actual)
+
+ # Filter assignments by system should be empty
+ query = {'scope.system': 'all'}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ self.assertEmpty(actual)
+
+ # Filter assignments by user in own domain should get assignments for
+ # that user only for projects in own domain or for own domain itself
+ expected = [a for a in self.assignments
+ if a.get('user_id') == self.user_in_domain
+ and (a.get('project_id') == self.project_in_domain
+ or a.get('domain_id') == self.own_domain)]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'user.id': self.user_in_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by user in other domain should still work but only
+ # return assignments for projects in own domain or for own domain
+ # itself
+ expected = [a for a in self.assignments
+ if a.get('user_id') == self.user_other_domain
+ and (a.get('project_id') == self.project_in_domain
+ or a.get('domain_id') == self.own_domain)]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'user.id': self.user_other_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by group in own domain should succeed
+ expected = [a for a in self.assignments
+ if a.get('group_id') == self.group_in_domain
+ and (a.get('project_id') == self.project_in_domain
+ or a.get('domain_id') == self.own_domain)]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'group.id': self.group_in_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by group in other domain should still work but
+ # only return assignments for projects in own domain or for own domain
+ # itself
+ expected = [a for a in self.assignments
+ if a.get('group_id') == self.group_other_domain
+ and (a.get('project_id') == self.project_in_domain
+ or a.get('domain_id') == self.own_domain)]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'group.id': self.group_other_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by global role should only return role
+ # assignments for own domain
+ expected = [a for a in self.assignments
+ if a.get('project_id') == self.project_in_domain
+ or a.get('domain_id') == self.own_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'role.id': self.role_id}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by project and role should succeed
+ expected = [a for a in self.assignments
+ if a.get('project_id') == self.project_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'scope.project.id': self.project_in_domain,
+ 'role.id': self.role_id}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+ # Reverse the check: only ephemeral tempest roles should be in the list
+ for assignment in actual:
+ self.assertIn(assignment, expected)
+
+ # Filter assignments by domain and role should succeed
+ expected = [a for a in self.assignments
+ if a.get('domain_id') == self.other_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'scope.domain.id': self.other_domain, 'role.id': self.role_id}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+ # Reverse the check: only ephemeral tempest roles should be in the list
+ for assignment in actual:
+ self.assertIn(assignment, expected)
+
+ # Filter assignments by system and role should be empty
+ query = {'scope.system': 'all', 'role.id': self.role_id}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ self.assertEmpty(actual)
+
+ # Filter assignments by user and role should should get assignments for
+ # that user only for projects in own domain or for own domain itself
+ expected = [a for a in self.assignments
+ if a.get('user_id') == self.user_in_domain
+ and (a.get('project_id') == self.project_in_domain
+ or a.get('domain_id') == self.own_domain)]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'user.id': self.user_in_domain, 'role.id': self.role_id}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+ # Reverse the check: only ephemeral tempest roles should be in the list
+ for assignment in actual:
+ self.assertIn(assignment, expected)
+
+ # Filter assignments by group and role should get assignments for
+ # that group only for projects in own domain or for own domain itself
+ expected = [a for a in self.assignments
+ if a.get('group_id') == self.group_in_domain
+ and (a.get('project_id') == self.project_in_domain
+ or a.get('domain_id') == self.own_domain)]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'group.id': self.group_in_domain, 'role.id': self.role_id}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+ # Reverse the check: only ephemeral tempest roles should be in the list
+ for assignment in actual:
+ self.assertIn(assignment, expected)
+
+ # Filter assignments by project and user should succeed
+ expected = [a for a in self.assignments
+ if a.get('project_id') == self.project_in_domain
+ and a.get('user_id') == self.user_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'user.id': self.user_in_domain,
+ 'scope.project.id': self.project_in_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by project and group should succeed
+ expected = [a for a in self.assignments
+ if a.get('project_id') == self.project_in_domain
+ and a.get('group_id') == self.group_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'group.id': self.group_in_domain,
+ 'scope.project.id': self.project_in_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by domain and user should succeed
+ expected = [a for a in self.assignments
+ if a.get('domain_id') == self.own_domain
+ and a.get('user_id') == self.user_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'user.id': self.user_in_domain,
+ 'scope.domain.id': self.own_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ # Filter assignments by domain and group should succeed
+ expected = [a for a in self.assignments
+ if a.get('domain_id') == self.own_domain
+ and a.get('group_id') == self.group_in_domain]
+ not_expected = [a for a in self.assignments if a not in expected]
+ query = {'group.id': self.group_in_domain,
+ 'scope.domain.id': self.own_domain}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ for assignment in expected:
+ self.assertIn(assignment, actual)
+ for assignment in not_expected:
+ self.assertNotIn(assignment, actual)
+
+ def test_identity_list_role_assignments_for_tree(self):
+ # Should see subtree assignments for project in own domain
+ subproject_id = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'),
+ domain_id=self.own_domain,
+ parent_id=self.project_in_domain)['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ subproject_id)
+ self.admin_client.roles_v3_client.create_user_role_on_project(
+ subproject_id, self.user_in_domain, self.role_id)
+ query = {'scope.project.id': self.project_in_domain,
+ 'include_subtree': True}
+ resp = self.do_request('list_role_assignments', **query)
+ actual = self._extract_role_assignments_from_response_body(resp)
+ expected_assignment = {'user_id': self.user_in_domain,
+ 'project_id': subproject_id,
+ 'role_id': self.role_id}
+ self.assertIn(expected_assignment, actual)
+
+ # Should not see subtree assignments for project in other domain
+ query = {'scope.project.id': self.project_other_domain,
+ 'include_subtree': True}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(IdentityV3RbacAssignmentTest, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+ def test_identity_list_role_assignments(self):
+ # Listing all assignments with no filters should fail
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden)
+
+ # Listing all assignments with names and no filters should fail
+ query = {'include_names': True}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by own domain should fail
+ query = {'scope.domain.id': self.own_domain}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by other domain should fail
+ query = {'scope.domain.id': self.other_domain}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by project in own domain should fail
+ query = {'scope.project.id': self.project_in_domain}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by project in other domain should fail
+ query = {'scope.project.id': self.project_other_domain}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by system should fail
+ query = {'scope.system': 'all'}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by user in own domain should fail
+ query = {'user.id': self.user_in_domain}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by user in other domain should fail
+ query = {'user.id': self.user_other_domain}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by group in own domain should fail
+ query = {'group.id': self.group_in_domain}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by group in other domain should fail
+ query = {'group.id': self.group_other_domain}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by global role should fail
+ query = {'role.id': self.role_id}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by project and role should fail
+ query = {'scope.project.id': self.project_in_domain,
+ 'role.id': self.role_id}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by domain and role should fail
+ query = {'scope.domain.id': self.other_domain, 'role.id': self.role_id}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by system and role should fail
+ query = {'scope.system': 'all', 'role.id': self.role_id}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by user and role should should fail
+ query = {'user.id': self.user_in_domain, 'role.id': self.role_id}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by group and role should fail
+ query = {'group.id': self.group_in_domain, 'role.id': self.role_id}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by project and user should fail
+ query = {'user.id': self.user_in_domain,
+ 'scope.project.id': self.project_in_domain}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by project and group should fail
+ query = {'group.id': self.group_in_domain,
+ 'scope.project.id': self.project_in_domain}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by domain and user should fail
+ query = {'user.id': self.user_in_domain,
+ 'scope.domain.id': self.own_domain}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Filter assignments by domain and group should fail
+ query = {'group.id': self.group_in_domain,
+ 'scope.domain.id': self.own_domain}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ def test_identity_list_role_assignments_for_tree(self):
+ # Should not see subtree assignments for project in own domain
+ query = {'scope.project.id': self.project_in_domain,
+ 'include_subtree': True}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Should not see subtree assignments for project in other domain
+ query = {'scope.project.id': self.project_other_domain,
+ 'include_subtree': True}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Should see subtree for own project
+ own_project = self.persona.credentials.project_id
+ subproject_id = self.admin_client.projects_client.create_project(
+ name=data_utils.rand_name('project'),
+ domain_id=self.own_domain,
+ parent_id=own_project)['project']['id']
+ self.addCleanup(self.admin_client.projects_client.delete_project,
+ subproject_id)
+ self.admin_client.roles_v3_client.create_user_role_on_project(
+ subproject_id, self.user_other_domain, self.role_id)
+ query = {'scope.project.id': own_project,
+ 'include_subtree': True}
+ resp = self.do_request('list_role_assignments', **query)
+ expected_assignment = {'user_id': self.user_other_domain,
+ 'project_id': subproject_id,
+ 'role_id': self.role_id}
+ actual = self._extract_role_assignments_from_response_body(resp)
+ self.assertIn(expected_assignment, actual)
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+ def test_identity_list_role_assignments_for_tree(self):
+ # Should not see subtree assignments for project in own domain
+ query = {'scope.project.id': self.project_in_domain,
+ 'include_subtree': True}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Should not see subtree assignments for project in other domain
+ query = {'scope.project.id': self.project_other_domain,
+ 'include_subtree': True}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+ # Should not see subtree for own project
+ own_project = self.persona.credentials.project_id
+ query = {'scope.project.id': own_project,
+ 'include_subtree': True}
+ self.do_request('list_role_assignments',
+ expected_status=exceptions.Forbidden, **query)
+
+
+class ProjectReaderTests(ProjectMemberTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_service.py b/keystone_tempest_plugin/tests/rbac/v3/test_service.py
new file mode 100644
index 0000000..a6a9083
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_service.py
@@ -0,0 +1,233 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacServiceTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacServiceTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.identity_services_v3_client
+ admin_client = cls.os_system_admin
+ cls.admin_services_client = admin_client.identity_services_v3_client
+
+ def service(self):
+ return {
+ 'name': data_utils.rand_name('service_name'),
+ 'type': data_utils.rand_name('service_type'),
+ }
+
+ @abc.abstractmethod
+ def test_identity_create_service(self):
+ """Test identity:create_service policy.
+
+ This test must check:
+ * whether the persona can create a service
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_service(self):
+ """Test identity:get_service policy.
+
+ This test must check:
+ * whether the persona can get a service
+ * whether the persona can get a service that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_services(self):
+ """Test identity:list_services policy.
+
+ This test must check:
+ * whether the persona can list all services
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_service(self):
+ """Test identity:update_service policy.
+
+ This test must check:
+ * whether the persona can update a service
+ * whether the persona can update a service that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_service(self):
+ """Test identity:delete_service policy.
+
+ This test must check
+ * whether the persona can delete a service
+ * whether the persona can delete a service that does not exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacServiceTests, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_service(self):
+ service_id = self.do_request(
+ 'create_service', expected_status=201,
+ **self.service())['service']['id']
+ self.addCleanup(
+ self.admin_services_client.delete_service,
+ service_id=service_id)
+
+ def test_identity_get_service(self):
+ service_id = self.admin_services_client.create_service(
+ **self.service())['service']['id']
+ self.addCleanup(
+ self.admin_services_client.delete_service,
+ service_id=service_id)
+ self.do_request('show_service', service_id=service_id)
+ # user gets a 404 for nonexistent service
+ self.do_request('show_service', expected_status=exceptions.NotFound,
+ service_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_services(self):
+ service_id = self.admin_services_client.create_service(
+ **self.service())['service']['id']
+ self.addCleanup(
+ self.admin_services_client.delete_service,
+ service_id=service_id)
+ resp = self.do_request('list_services')
+ self.assertIn(service_id, [e['id'] for e in resp['services']])
+
+ def test_identity_update_service(self):
+ service_id = self.admin_services_client.create_service(
+ **self.service())['service']['id']
+ self.addCleanup(
+ self.admin_services_client.delete_service,
+ service_id=service_id)
+ self.do_request('update_service',
+ service_id=service_id,
+ type=data_utils.rand_name('service_type'))
+ # user gets a 404 for nonexistent service
+ self.do_request('update_service', expected_status=exceptions.NotFound,
+ service_id=data_utils.rand_uuid_hex(),
+ type=data_utils.rand_name('service_type'))
+
+ def test_identity_delete_service(self):
+ service_id = self.admin_services_client.create_service(
+ **self.service())['service']['id']
+ self.do_request('delete_service', expected_status=204,
+ service_id=service_id)
+ # user gets a 404 for nonexistent service
+ self.do_request('delete_service', expected_status=exceptions.NotFound,
+ service_id=data_utils.rand_uuid_hex())
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_service(self):
+ self.do_request(
+ 'create_service', expected_status=exceptions.Forbidden,
+ **self.service())
+
+ def test_identity_update_service(self):
+ service_id = self.admin_services_client.create_service(
+ **self.service())['service']['id']
+ self.addCleanup(
+ self.admin_services_client.delete_service,
+ service_id=service_id)
+ self.do_request('update_service',
+ expected_status=exceptions.Forbidden,
+ service_id=service_id,
+ type=data_utils.rand_name('service_type'))
+ # user gets a 403 for nonexistent service
+ self.do_request('update_service', expected_status=exceptions.Forbidden,
+ service_id=data_utils.rand_uuid_hex(),
+ type=data_utils.rand_name('service_type'))
+
+ def test_identity_delete_service(self):
+ service_id = self.admin_services_client.create_service(
+ **self.service())['service']['id']
+ self.do_request('delete_service',
+ expected_status=exceptions.Forbidden,
+ service_id=service_id)
+ # user gets a 403 for nonexistent service
+ self.do_request('delete_service', expected_status=exceptions.Forbidden,
+ service_id=data_utils.rand_uuid_hex())
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_service(self):
+ service_id = self.admin_services_client.create_service(
+ **self.service())['service']['id']
+ self.addCleanup(
+ self.admin_services_client.delete_service,
+ service_id=service_id)
+ self.do_request('show_service', expected_status=exceptions.Forbidden,
+ service_id=service_id)
+ # user gets a 403 for nonexistent service
+ self.do_request('show_service', expected_status=exceptions.Forbidden,
+ service_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_services(self):
+ service_id = self.admin_services_client.create_service(
+ **self.service())['service']['id']
+ self.addCleanup(
+ self.admin_services_client.delete_service,
+ service_id=service_id)
+ self.do_request('list_services', expected_status=exceptions.Forbidden)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_service_provider.py b/keystone_tempest_plugin/tests/rbac/v3/test_service_provider.py
new file mode 100644
index 0000000..6cf54b9
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_service_provider.py
@@ -0,0 +1,250 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin import clients
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacServiceProviderTests(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacServiceProviderTests, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ persona_mgr = clients.Manager(cls.persona.credentials)
+ cls.client = persona_mgr.service_providers_client
+ admin_client = cls.os_system_admin
+ admin_mgr = clients.Manager(admin_client.credentials)
+ cls.admin_sp_client = admin_mgr.service_providers_client
+
+ @abc.abstractmethod
+ def test_identity_create_service_provider(self):
+ """Test identity:create_service_provider policy.
+
+ This test must check:
+ * whether the persona can create a service provider
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_service_provider(self):
+ """Test identity:get_service_provider policy.
+
+ This test must check:
+ * whether the persona can get a service provider
+ * whether the persona can get a service provider that does not
+ exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_service_providers(self):
+ """Test identity:list_service_providers policy.
+
+ This test must check:
+ * whether the persona can list all identity providers
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_service_provider(self):
+ """Test identity:update_service_provider policy.
+
+ This test must check:
+ * whether the persona can update a service provider
+ * whether the persona can update a service provider that does not
+ exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_service_provider(self):
+ """Test identity:delete_service_provider policy.
+
+ This test must check
+ * whether the persona can delete a service provider
+ * whether the persona can delete a service provider that does not
+ exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacServiceProviderTests,
+ base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_service_provider(self):
+ sp_id = self.do_request(
+ 'create_service_provider', expected_status=201,
+ sp_id=data_utils.rand_name(),
+ auth_url=data_utils.rand_url(),
+ sp_url=data_utils.rand_url()
+ )['service_provider']['id']
+ self.addCleanup(self.admin_sp_client.delete_service_provider, sp_id)
+
+ def test_identity_get_service_provider(self):
+ sp_id = self.admin_sp_client.create_service_provider(
+ sp_id=data_utils.rand_name(),
+ auth_url=data_utils.rand_url(),
+ sp_url=data_utils.rand_url())['service_provider']['id']
+ self.addCleanup(self.admin_sp_client.delete_service_provider, sp_id)
+ self.do_request('show_service_provider', sp_id=sp_id)
+ # user gets a 404 for nonexistent sp
+ self.do_request('show_service_provider',
+ expected_status=exceptions.NotFound,
+ sp_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_service_providers(self):
+ sp_id = self.admin_sp_client.create_service_provider(
+ sp_id=data_utils.rand_name(),
+ auth_url=data_utils.rand_url(),
+ sp_url=data_utils.rand_url())['service_provider']['id']
+ self.addCleanup(self.admin_sp_client.delete_service_provider, sp_id)
+ resp = self.do_request('list_service_providers')
+ self.assertIn(sp_id, [i['id'] for i in resp['service_providers']])
+
+ def test_identity_update_service_provider(self):
+ sp_id = self.admin_sp_client.create_service_provider(
+ sp_id=data_utils.rand_name(),
+ auth_url=data_utils.rand_url(),
+ sp_url=data_utils.rand_url())['service_provider']['id']
+ self.addCleanup(self.admin_sp_client.delete_service_provider, sp_id)
+ self.do_request('update_service_provider',
+ sp_id=sp_id,
+ description=data_utils.arbitrary_string())
+ # user gets a 404 for nonexistent sp
+ self.do_request('update_service_provider',
+ expected_status=exceptions.NotFound,
+ sp_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_service_provider(self):
+ sp_id = self.admin_sp_client.create_service_provider(
+ sp_id=data_utils.rand_name(),
+ auth_url=data_utils.rand_url(),
+ sp_url=data_utils.rand_url())['service_provider']['id']
+ self.do_request('delete_service_provider', expected_status=204,
+ sp_id=sp_id)
+ # user gets a 404 for nonexistent sp
+ self.do_request('delete_service_provider',
+ expected_status=exceptions.NotFound,
+ sp_id=sp_id)
+
+
+class SystemMemberTests(SystemAdminTests, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_service_provider(self):
+ self.do_request('create_service_provider',
+ expected_status=exceptions.Forbidden,
+ sp_id=data_utils.rand_name(),
+ auth_url=data_utils.rand_url(),
+ sp_url=data_utils.rand_url())
+
+ def test_identity_update_service_provider(self):
+ sp_id = self.admin_sp_client.create_service_provider(
+ sp_id=data_utils.rand_name(),
+ auth_url=data_utils.rand_url(),
+ sp_url=data_utils.rand_url())['service_provider']['id']
+ self.addCleanup(self.admin_sp_client.delete_service_provider, sp_id)
+ self.do_request('update_service_provider',
+ expected_status=exceptions.Forbidden,
+ sp_id=sp_id,
+ description=data_utils.arbitrary_string())
+ # user gets a 403 for nonexistent sp
+ self.do_request('update_service_provider',
+ expected_status=exceptions.Forbidden,
+ sp_id=data_utils.rand_uuid_hex(),
+ description=data_utils.arbitrary_string())
+
+ def test_identity_delete_service_provider(self):
+ sp_id = self.admin_sp_client.create_service_provider(
+ sp_id=data_utils.rand_name(),
+ auth_url=data_utils.rand_url(),
+ sp_url=data_utils.rand_url())['service_provider']['id']
+ self.addCleanup(self.admin_sp_client.delete_service_provider, sp_id)
+ self.do_request('delete_service_provider',
+ expected_status=exceptions.Forbidden,
+ sp_id=sp_id)
+ # user gets a 403 for nonexistent sp
+ self.do_request('delete_service_provider',
+ expected_status=exceptions.Forbidden,
+ sp_id=sp_id)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_service_provider(self):
+ sp_id = self.admin_sp_client.create_service_provider(
+ sp_id=data_utils.rand_name(),
+ auth_url=data_utils.rand_url(),
+ sp_url=data_utils.rand_url())['service_provider']['id']
+ self.addCleanup(self.admin_sp_client.delete_service_provider, sp_id)
+ self.do_request('show_service_provider',
+ expected_status=exceptions.Forbidden,
+ sp_id=sp_id)
+ # user gets a 403 for nonexistent sp
+ self.do_request('show_service_provider',
+ expected_status=exceptions.Forbidden,
+ sp_id=data_utils.rand_uuid_hex())
+
+ def test_identity_list_service_providers(self):
+ sp_id = self.admin_sp_client.create_service_provider(
+ sp_id=data_utils.rand_name(),
+ auth_url=data_utils.rand_url(),
+ sp_url=data_utils.rand_url())['service_provider']['id']
+ self.addCleanup(self.admin_sp_client.delete_service_provider, sp_id)
+ self.do_request('list_service_providers',
+ expected_status=exceptions.Forbidden)
+
+
+class DomainMemberTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainReaderTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_token.py b/keystone_tempest_plugin/tests/rbac/v3/test_token.py
new file mode 100644
index 0000000..e5d10ed
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_token.py
@@ -0,0 +1,309 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest import clients
+from tempest.lib import auth
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacTokenTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacTokenTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.identity_v3_client
+
+ @classmethod
+ def resource_setup(cls):
+ admin_client = cls.os_system_admin
+ cls.user = {
+ 'name': data_utils.rand_name('user'),
+ 'password': data_utils.rand_password(),
+ }
+ cls.user_id = admin_client.users_v3_client.create_user(
+ **cls.user)['user']['id']
+ cls.addClassResourceCleanup(
+ admin_client.users_v3_client.delete_user, user_id=cls.user_id)
+ cls.project_id = admin_client.projects_client.create_project(
+ name=data_utils.rand_name()
+ )['project']['id']
+ cls.addClassResourceCleanup(
+ admin_client.projects_client.delete_project,
+ project_id=cls.project_id)
+ cls.domain_id = admin_client.domains_client.create_domain(
+ name=data_utils.rand_name()
+ )['domain']['id']
+ cls.addClassResourceCleanup(
+ admin_client.domains_client.delete_domain,
+ domain_id=cls.domain_id)
+ cls.addClassResourceCleanup(
+ admin_client.domains_client.update_domain,
+ domain_id=cls.domain_id, enabled=False)
+ role_id = admin_client.roles_v3_client.create_role(
+ name=data_utils.rand_name())['role']['id']
+ cls.addClassResourceCleanup(
+ admin_client.roles_v3_client.delete_role,
+ role_id=role_id)
+ admin_client.roles_v3_client.create_user_role_on_project(
+ project_id=cls.project_id,
+ user_id=cls.user_id,
+ role_id=role_id
+ )
+ admin_client.roles_v3_client.create_user_role_on_domain(
+ domain_id=cls.domain_id,
+ user_id=cls.user_id,
+ role_id=role_id
+ )
+ admin_client.roles_v3_client.create_user_role_on_system(
+ user_id=cls.user_id,
+ role_id=role_id
+ )
+
+ def setUp(self):
+ super(IdentityV3RbacTokenTest, self).setUp()
+ own_creds = auth.KeystoneV3Credentials(**self.own_keystone_creds)
+ own_creds = clients.get_auth_provider(own_creds).fill_credentials()
+ self.own_token = clients.Manager(
+ credentials=own_creds).identity_v3_client.token
+ project_creds = auth.KeystoneV3Credentials(
+ user_id=self.user_id,
+ password=self.user['password'],
+ project_id=self.project_id)
+ project_creds = clients.get_auth_provider(
+ project_creds).fill_credentials()
+ self.project_token = clients.Manager(
+ credentials=project_creds).identity_v3_client.token
+ domain_creds = auth.KeystoneV3Credentials(
+ user_id=self.user_id,
+ password=self.user['password'],
+ domain_id=self.domain_id)
+ domain_creds = clients.get_auth_provider(
+ domain_creds).fill_credentials()
+ self.domain_token = clients.Manager(
+ credentials=domain_creds).identity_v3_client.token
+ system_creds = auth.KeystoneV3Credentials(
+ user_id=self.user_id,
+ password=self.user['password'],
+ system='all')
+ system_creds = clients.get_auth_provider(
+ system_creds).fill_credentials()
+ self.system_token = clients.Manager(
+ credentials=system_creds).identity_v3_client.token
+
+ @abc.abstractmethod
+ def test_identity_check_token(self):
+ """Test identity:check_token policy.
+
+ This test must check:
+ * whether the persona can check their own token in their current
+ scope
+ * whether the persona can check a system-scoped token for a different
+ user
+ * whether the persona can check a domain-scoped token for a different
+ user
+ * whether the persona can check a project-scoped token for a
+ different user
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_validate_token(self):
+ """Test identity:validate_token policy.
+
+ This test must validate:
+ * whether the persona can validate their own token in their current
+ scope
+ * whether the persona can validate a system-scoped token for a
+ different user
+ * whether the persona can validate a domain-scoped token for a
+ different user
+ * whether the persona can validate a project-scoped token for a
+ different user
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_revoke_token(self):
+ """Test identity:revoke_token policy.
+
+ This test must revoke:
+ * whether the persona can revoke their own token in their current
+ scope
+ * whether the persona can revoke a system-scoped token for a
+ different user
+ * whether the persona can revoke a domain-scoped token for a
+ different user
+ * whether the persona can revoke a project-scoped token for a
+ different user
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacTokenTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def setUp(self):
+ self.own_keystone_creds = {
+ 'user_id': self.persona.credentials.user_id,
+ 'password': self.persona.credentials.password,
+ 'system': 'all'
+ }
+ super(SystemAdminTests, self).setUp()
+
+ def test_identity_check_token(self):
+ # user can check own token
+ self.do_request('check_token_existence', resp_token=self.own_token)
+ # user can check other system user's token
+ self.do_request('check_token_existence', resp_token=self.system_token)
+ # user can check domain user's token
+ self.do_request('check_token_existence', resp_token=self.domain_token)
+ # user can check project user's token
+ self.do_request('check_token_existence', resp_token=self.project_token)
+
+ def test_identity_validate_token(self):
+ # user can validate own token
+ self.do_request('show_token', resp_token=self.own_token)
+ # user can validate other system user's token
+ self.do_request('show_token', resp_token=self.system_token)
+ # user can validate domain user's token
+ self.do_request('show_token', resp_token=self.domain_token)
+ # user can validate project user's token
+ self.do_request('show_token', resp_token=self.project_token)
+
+ def test_identity_revoke_token(self):
+ # user can revoke own token
+ self.do_request('delete_token', expected_status=204,
+ resp_token=self.own_token)
+ # user can revoke other system user's token
+ self.do_request('delete_token', expected_status=204,
+ resp_token=self.system_token)
+ # user can revoke domain user's token
+ self.do_request('delete_token', expected_status=204,
+ resp_token=self.domain_token)
+ # user can revoke project user's token
+ self.do_request('delete_token', expected_status=204,
+ resp_token=self.project_token)
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_revoke_token(self):
+ # user can revoke own token
+ self.do_request('delete_token', expected_status=204,
+ resp_token=self.own_token)
+ # user cannot revoke other system user's token
+ self.do_request('delete_token', expected_status=exceptions.Forbidden,
+ resp_token=self.system_token)
+ # user cannot revoke domain user's token
+ self.do_request('delete_token', expected_status=exceptions.Forbidden,
+ resp_token=self.domain_token)
+ # user cannot revoke project user's token
+ self.do_request('delete_token', expected_status=exceptions.Forbidden,
+ resp_token=self.project_token)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def setUp(self):
+ self.own_keystone_creds = {
+ 'user_id': self.persona.credentials.user_id,
+ 'password': self.persona.credentials.password,
+ 'domain_id': self.persona.credentials.domain_id
+ }
+ # call base setUp directly to ensure we don't use system creds
+ super(SystemAdminTests, self).setUp()
+
+ def test_identity_check_token(self):
+ # user can check own token
+ self.do_request('check_token_existence', resp_token=self.own_token)
+ # user cannot check other system user's token
+ self.do_request('check_token_existence',
+ expected_status=exceptions.Forbidden,
+ resp_token=self.system_token)
+ # user cannot check domain user's token
+ self.do_request('check_token_existence',
+ expected_status=exceptions.Forbidden,
+ resp_token=self.domain_token)
+ # user cannot check project user's token
+ self.do_request('check_token_existence',
+ expected_status=exceptions.Forbidden,
+ resp_token=self.project_token)
+
+ def test_identity_validate_token(self):
+ # user can validate own token
+ self.do_request('show_token', resp_token=self.own_token)
+ # user cannot validate other system user's token
+ self.do_request('show_token',
+ expected_status=exceptions.Forbidden,
+ resp_token=self.system_token)
+ # user cannot validate domain user's token
+ self.do_request('show_token',
+ expected_status=exceptions.Forbidden,
+ resp_token=self.domain_token)
+ # user cannot validate project user's token
+ self.do_request('show_token',
+ expected_status=exceptions.Forbidden,
+ resp_token=self.project_token)
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainAdminTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(DomainAdminTests, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+ def setUp(self):
+ self.own_keystone_creds = {
+ 'user_id': self.persona.credentials.user_id,
+ 'password': self.persona.credentials.password,
+ 'project_id': self.persona.credentials.project_id
+ }
+ # call base setUp directly to ensure we don't use system creds
+ super(SystemAdminTests, self).setUp()
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_trust.py b/keystone_tempest_plugin/tests/rbac/v3/test_trust.py
new file mode 100644
index 0000000..c30f9eb
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_trust.py
@@ -0,0 +1,559 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest import clients
+from tempest.lib import auth
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacTrustTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacTrustTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.trusts_client
+ cls.admin_client = cls.os_system_admin
+ cls.admin_trusts_client = cls.admin_client.trusts_client
+
+ @classmethod
+ def resource_setup(cls):
+ trustor_user = {
+ 'name': data_utils.rand_name('user'),
+ 'password': data_utils.rand_password(),
+ }
+ cls.trustor = cls.admin_client.users_v3_client.create_user(
+ **trustor_user)['user']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.users_v3_client.delete_user,
+ user_id=cls.trustor)
+ cls.trustee = cls.admin_client.users_v3_client.create_user(
+ name=data_utils.rand_name())['user']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.users_v3_client.delete_user,
+ user_id=cls.trustee)
+ cls.project = cls.admin_client.projects_client.create_project(
+ name=data_utils.rand_name()
+ )['project']['id']
+ cls.addClassResourceCleanup(
+ cls.admin_client.projects_client.delete_project,
+ project_id=cls.project)
+ cls.roles = [
+ {'id': cls.admin_client.roles_v3_client.create_role(
+ name=data_utils.rand_name())['role']['id']}
+ ]
+ cls.addClassResourceCleanup(
+ cls.admin_client.roles_v3_client.delete_role,
+ role_id=cls.roles[0]['id'])
+ cls.admin_client.roles_v3_client.create_user_role_on_project(
+ project_id=cls.project,
+ user_id=cls.trustor,
+ role_id=cls.roles[0]['id']
+ )
+ creds = auth.KeystoneV3Credentials(
+ user_id=cls.trustor,
+ password=trustor_user['password'],
+ project_id=cls.project)
+ auth_provider = clients.get_auth_provider(creds)
+ creds = auth_provider.fill_credentials()
+ user_client = clients.Manager(credentials=creds)
+ cls.user_trust_client = user_client.trusts_client
+
+ cls.admin_role_id = cls.admin_client.roles_v3_client.list_roles(
+ name='admin')['roles'][0]['id']
+ cls.member_role_id = cls.admin_client.roles_v3_client.list_roles(
+ name='member')['roles'][0]['id']
+ cls.reader_role_id = cls.admin_client.roles_v3_client.list_roles(
+ name='reader')['roles'][0]['id']
+
+ def trust(self, trustor=None, trustee=None, project_id=None, roles=None):
+ trust = {}
+ trust['trustor_user_id'] = trustor or self.trustor
+ trust['trustee_user_id'] = trustee or self.trustee
+ trust['project_id'] = project_id or self.project
+ trust['roles'] = roles or self.roles
+ trust['impersonation'] = False
+ return trust
+
+ @abc.abstractmethod
+ def test_identity_create_trust(self):
+ """Test identity:create_trust policy.
+
+ This test must check:
+ * whether the persona can create a trust for themself
+ * whether the persona can create a trust for another user
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_trust(self):
+ """Test identity:get_trust policy.
+
+ This test must check:
+ * whether the persona can get a trust for which they are the trustor
+ * whether the persona can get a trust for which they are the trustee
+ * whether the persona can get a trust with which they are
+ unaffiliated
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_trusts(self):
+ """Test identity:list_trusts policy.
+
+ This test must check:
+ * whether the persona can list all trusts
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_trusts_for_trustor(self):
+ """Test identity:list_trusts_for_trustor policy.
+
+ This test must check:
+ * whether the persona can list trusts by trustor for which they are
+ the trustor
+ * whether the persona can list trusts by trustor for which another
+ user is trustor
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_trusts_for_trustee(self):
+ """Test identity:list_trusts_for_trustee policy.
+
+ This test must check:
+ * whether the persona can list trusts by trustee for which they are
+ the trustee
+ * whether the persona can list trusts by trustee for which another
+ user is trustee
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_roles_for_trust(self):
+ """Test identity:list_roles_for_trust policy.
+
+ This test must check:
+ * whether the persona can list the roles of a trust for which they
+ are the trustee
+ * whether the persona can list the roles of a trust for which they
+ are the trustor
+ * whether the persona can list the roles of a trust with which they
+ are unaffiliated
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_role_for_trust(self):
+ """Test identity:get_role_for_trust policy.
+
+ This test must check:
+ * whether the persona can get a role of a trust for which they are
+ the trustee
+ * whether the persona can get a role of a trust for which they are
+ the trustor
+ * whether the persona can get a role of a trust with which they are
+ unaffiliated
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_trust(self):
+ """Test identity:delete_trust policy.
+
+ This test must check
+ * whether the persona can delete a trust for which they are the
+ trustor
+ * whether the persona can delete a trust for which they are the
+ trustee
+ * whether the persona can delete a trust which which they are
+ unaffiliated
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacTrustTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_trust(self):
+ # user cannot create trust for themself
+ self.do_request('create_trust',
+ expected_status=exceptions.Forbidden,
+ **self.trust(trustor=self.persona.credentials.user_id))
+ # user cannot create trust for another user
+ self.do_request('create_trust',
+ expected_status=exceptions.Forbidden,
+ **self.trust())
+
+ def test_identity_get_trust(self):
+ # user cannot have their own trust
+ # user can get trust for other user
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ self.do_request('show_trust', trust_id=trust_id)
+
+ def test_identity_list_trusts(self):
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ resp = self.do_request('list_trusts')
+ self.assertIn(trust_id, [t['id'] for t in resp['trusts']])
+
+ def test_identity_list_trusts_for_trustor(self):
+ # user cannot have their own trust
+ # user can list trusts for other user
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ self.do_request('list_trusts', trustor_user_id=self.trustor)
+
+ def test_identity_list_trusts_for_trustee(self):
+ # user cannot have their own trust
+ # user can list trusts for other user
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ self.do_request('list_trusts', trustee_user_id=self.trustee)
+
+ def test_identity_list_roles_for_trust(self):
+ # user cannot have their own trust
+ # user can list roles of trust for other user
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ resp = self.do_request('list_trust_roles', trust_id=trust_id)
+ self.assertIn(self.roles[0]['id'], [r['id'] for r in resp['roles']])
+
+ def test_identity_get_role_for_trust(self):
+ # user cannot have their own trust
+ # user can get role of trust for other user
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ self.do_request('show_trust_role',
+ trust_id=trust_id, role_id=self.roles[0]['id'])
+
+ def test_identity_delete_trust(self):
+ # user cannot have their own trust
+ # user can delete a user's trust
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.do_request('delete_trust', expected_status=204, trust_id=trust_id)
+
+
+class SystemMemberTests(SystemAdminTests):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_delete_trust(self):
+ # system user cannot have their own trust
+ # user cannot delete another user's trust
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ self.do_request('delete_trust', expected_status=exceptions.Forbidden,
+ trust_id=trust_id)
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(SystemReaderTests, base.BaseIdentityTest):
+
+ # Domain admins cannot create their own trusts (trusts can only be
+ # scoped to projects) and domain admins have no special privileges over the
+ # trusts own by users in their domains.
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def test_identity_get_trust(self):
+ # user cannot have their own trust
+ # user can get trust for other user
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ self.do_request('show_trust', expected_status=exceptions.Forbidden,
+ trust_id=trust_id)
+
+ def test_identity_list_trusts(self):
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ self.do_request('list_trusts',
+ expected_status=exceptions.Forbidden)
+
+ def test_identity_list_trusts_for_trustor(self):
+ # user cannot have their own trust
+ # user can list trusts for other user
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ self.do_request('list_trusts', expected_status=exceptions.Forbidden,
+ trustor_user_id=self.trustor)
+
+ def test_identity_list_trusts_for_trustee(self):
+ # user cannot have their own trust
+ # user can list trusts for other user
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ self.do_request('list_trusts', expected_status=exceptions.Forbidden,
+ trustee_user_id=self.trustee)
+
+ def test_identity_list_roles_for_trust(self):
+ # user cannot have their own trust
+ # user can list roles of trust for other user
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ self.do_request('list_trust_roles',
+ expected_status=exceptions.Forbidden,
+ trust_id=trust_id)
+
+ def test_identity_get_role_for_trust(self):
+ # user cannot have their own trust
+ # user can get role of trust for other user
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ self.do_request('show_trust_role',
+ expected_status=exceptions.Forbidden,
+ trust_id=trust_id, role_id=self.roles[0]['id'])
+
+
+class DomainMemberTests(DomainAdminTests):
+
+ credentials = ['domain_member', 'system_admin']
+
+
+class DomainReaderTests(DomainAdminTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(IdentityV3RbacTrustTest, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+ def setUp(self):
+ super(ProjectAdminTests, self).setUp()
+ self.role_id = self.admin_role_id
+
+ def test_identity_create_trust(self):
+ # user can create a trust for their own project
+ trustor_user_id = self.persona.credentials.user_id
+ project_id = self.persona.credentials.project_id
+ resp = self.do_request(
+ 'create_trust',
+ expected_status=201,
+ **self.trust(
+ trustor=trustor_user_id,
+ project_id=project_id,
+ roles=[{'id': self.role_id}])
+ )['trust']
+ self.addCleanup(self.client.delete_trust, resp['id'])
+
+ # user cannot create trust with another user as trustor
+ self.do_request(
+ 'create_trust',
+ expected_status=exceptions.Forbidden,
+ **self.trust())
+
+ def test_identity_get_trust(self):
+ # user can get a trust for which they are trustor
+ trustor_user_id = self.persona.credentials.user_id
+ project_id = self.persona.credentials.project_id
+ trust_id = self.client.create_trust(
+ **self.trust(trustor=trustor_user_id,
+ project_id=project_id,
+ roles=[{'id': self.role_id}]))['trust']['id']
+ self.addCleanup(self.client.delete_trust, trust_id=trust_id)
+ self.do_request('show_trust', trust_id=trust_id)
+
+ # user can get a trust for which they are trustee
+ trustee_user_id = self.persona.credentials.user_id
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust(trustee=trustee_user_id))['trust']['id']
+ self.addCleanup(self.user_trust_client.delete_trust, trust_id=trust_id)
+ self.do_request('show_trust', trust_id=trust_id)
+
+ # user cannot get a trust with which they are unaffiliated
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.user_trust_client.delete_trust, trust_id=trust_id)
+ self.do_request('show_trust', expected_status=exceptions.Forbidden,
+ trust_id=trust_id)
+
+ def test_identity_list_trusts(self):
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.admin_trusts_client.delete_trust,
+ trust_id=trust_id)
+ self.do_request('list_trusts',
+ expected_status=exceptions.Forbidden)
+
+ def test_identity_list_trusts_for_trustor(self):
+ # user can list their own trusts
+ trustor_user_id = self.persona.credentials.user_id
+ project_id = self.persona.credentials.project_id
+ trust_id = self.client.create_trust(
+ **self.trust(trustor=trustor_user_id,
+ project_id=project_id,
+ roles=[{'id': self.role_id}]))['trust']['id']
+ self.addCleanup(self.client.delete_trust, trust_id=trust_id)
+ self.do_request('list_trusts', trustor_user_id=trustor_user_id)
+
+ # user cannot list another user's trusts
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.user_trust_client.delete_trust, trust_id=trust_id)
+ self.do_request('list_trusts', expected_status=exceptions.Forbidden,
+ trustor_user_id=self.trustor)
+
+ def test_identity_list_trusts_for_trustee(self):
+ # user can list their own trusts
+ trustee_user_id = self.persona.credentials.user_id
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust(trustee=trustee_user_id))['trust']['id']
+ self.addCleanup(self.user_trust_client.delete_trust, trust_id=trust_id)
+ self.do_request('list_trusts', trustee_user_id=trustee_user_id)
+
+ # user cannot list another user's trusts
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.user_trust_client.delete_trust, trust_id=trust_id)
+ self.do_request('list_trusts', expected_status=exceptions.Forbidden,
+ trustee_user_id=self.trustee)
+
+ def test_identity_list_roles_for_trust(self):
+ # user can list roles for trust for which they are trustor
+ trustor_user_id = self.persona.credentials.user_id
+ project_id = self.persona.credentials.project_id
+ trust_id = self.client.create_trust(
+ **self.trust(trustor=trustor_user_id,
+ project_id=project_id,
+ roles=[{'id': self.role_id}]))['trust']['id']
+ self.addCleanup(self.client.delete_trust, trust_id=trust_id)
+ self.do_request('list_trust_roles', trust_id=trust_id)
+
+ # user can list roles for trust for which they are trustee
+ trustee_user_id = self.persona.credentials.user_id
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust(trustee=trustee_user_id))['trust']['id']
+ self.addCleanup(self.user_trust_client.delete_trust, trust_id=trust_id)
+ self.do_request('list_trust_roles', trust_id=trust_id)
+
+ # user cannot list roles for trust with which they are unaffiliated
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.user_trust_client.delete_trust, trust_id=trust_id)
+ self.do_request('list_trust_roles',
+ expected_status=exceptions.Forbidden,
+ trust_id=trust_id)
+
+ def test_identity_get_role_for_trust(self):
+ # user can get roles for trust for which they are trustor
+ trustor_user_id = self.persona.credentials.user_id
+ project_id = self.persona.credentials.project_id
+ trust_id = self.client.create_trust(
+ **self.trust(trustor=trustor_user_id,
+ project_id=project_id,
+ roles=[{'id': self.role_id}]))['trust']['id']
+ self.addCleanup(self.client.delete_trust, trust_id=trust_id)
+ self.do_request('show_trust_role',
+ trust_id=trust_id, role_id=self.role_id)
+
+ # user can list roles for trust for which they are trustee
+ trustee_user_id = self.persona.credentials.user_id
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust(trustee=trustee_user_id))['trust']['id']
+ self.addCleanup(self.user_trust_client.delete_trust, trust_id=trust_id)
+ self.do_request('show_trust_role',
+ trust_id=trust_id, role_id=self.roles[0]['id'])
+
+ # user cannot list roles for trust with which they are unaffiliated
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.user_trust_client.delete_trust, trust_id=trust_id)
+ self.do_request('show_trust_role',
+ expected_status=exceptions.Forbidden,
+ trust_id=trust_id, role_id=self.role_id)
+
+ def test_identity_delete_trust(self):
+ # user can delete trust for which they are the trustor
+ trustor_user_id = self.persona.credentials.user_id
+ project_id = self.persona.credentials.project_id
+ trust_id = self.client.create_trust(
+ **self.trust(trustor=trustor_user_id,
+ project_id=project_id,
+ roles=[{'id': self.role_id}]))['trust']['id']
+ self.do_request('delete_trust', expected_status=204, trust_id=trust_id)
+
+ # user cannot delete trust for which they are the trustee
+ trustee_user_id = self.persona.credentials.user_id
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust(trustee=trustee_user_id))['trust']['id']
+ self.addCleanup(self.user_trust_client.delete_trust, trust_id=trust_id)
+ self.do_request('delete_trust', expected_status=exceptions.Forbidden,
+ trust_id=trust_id)
+
+ # user cannot delete trust with which they are unaffiliated
+ trust_id = self.user_trust_client.create_trust(
+ **self.trust())['trust']['id']
+ self.addCleanup(self.user_trust_client.delete_trust, trust_id=trust_id)
+ self.do_request('delete_trust', expected_status=exceptions.Forbidden,
+ trust_id=trust_id)
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+ def setUp(self):
+ super(ProjectMemberTests, self).setUp()
+ self.role_id = self.member_role_id
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
+
+ def setUp(self):
+ super(ProjectReaderTests, self).setUp()
+ self.role_id = self.reader_role_id
diff --git a/keystone_tempest_plugin/tests/rbac/v3/test_user.py b/keystone_tempest_plugin/tests/rbac/v3/test_user.py
new file mode 100644
index 0000000..7dcfdc7
--- /dev/null
+++ b/keystone_tempest_plugin/tests/rbac/v3/test_user.py
@@ -0,0 +1,540 @@
+# Copyright 2020 SUSE LLC
+#
+# 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.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from keystone_tempest_plugin.tests.rbac.v3 import base as rbac_base
+
+
+class IdentityV3RbacUserTest(rbac_base.IdentityV3RbacBaseTests,
+ metaclass=abc.ABCMeta):
+
+ @classmethod
+ def setup_clients(cls):
+ super(IdentityV3RbacUserTest, cls).setup_clients()
+ cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+ cls.client = cls.persona.users_v3_client
+ admin_client = cls.os_system_admin
+ cls.admin_users_client = admin_client.users_v3_client
+ cls.admin_domains_client = admin_client.domains_client
+
+ def user(self):
+ user = {}
+ name = data_utils.rand_name('user')
+ user['name'] = name
+ user['description'] = name + 'description'
+ user['email'] = name + '@testmail.tm'
+ user['password'] = data_utils.rand_password()
+ user['enabled'] = False
+ return user
+
+ @abc.abstractmethod
+ def test_identity_create_user(self):
+ """Test identity:create_user policy.
+
+ This test must check:
+ * whether the persona can create an arbitrary user
+ * whether the persona can create a user in another domain
+ (if applicable)
+ * whether the persona can create a user in their own domain
+ (if applicable)
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_get_user(self):
+ """Test identity:get_user policy.
+
+ This test must check:
+ * whether the persona can get an arbitary user
+ * whether the persona can get their own user
+ * whether the persona can get a user in another domain
+ (if applicable)
+ * whether the persona can get a user in their own domain
+ (if applicable)
+ * whether the persona can get a user that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_list_users(self):
+ """Test identity:list_users policy.
+
+ This test must check:
+ * whether the persona can list all users
+ * whether the result list is appropriately filtered to domain
+ (if applicable)
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_update_user(self):
+ """Test identity:update_users policy.
+
+ This test must check:
+ * whether the persona can update an arbitrary user
+ * whether the persona can update a user in another domain
+ (if applicable)
+ * whether the persona can update a user in their own domain
+ (if applicable)
+ * whether the persona can update a user that does not exist
+ """
+ pass
+
+ @abc.abstractmethod
+ def test_identity_delete_user(self):
+ """Test identity:delete_user policy.
+
+ This test must check
+ * whether the persona can delete an arbitrary user
+ * whether the persona can delete a user in another domain
+ (if applicable)
+ * whether the persona can delete a user in their own domain
+ (if applicable)
+ * whether the persona can delete a user that does not exist
+ """
+ pass
+
+
+class SystemAdminTests(IdentityV3RbacUserTest, base.BaseIdentityTest):
+
+ credentials = ['system_admin']
+
+ def test_identity_create_user(self):
+ resp = self.do_request('create_user',
+ expected_status=201,
+ **self.user())
+ self.addCleanup(self.admin_users_client.delete_user,
+ resp['user']['id'])
+
+ def test_identity_get_user(self):
+ user = self.admin_users_client.create_user(**self.user())['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ # user can get arbitrary user
+ resp = self.do_request('show_user', user_id=user['id'])
+ self.assertEqual(resp['user']['id'], user['id'])
+ # user can get own user
+ user_id = self.persona.credentials.user_id
+ resp = self.do_request('show_user', user_id=user_id)
+ self.assertEqual(resp['user']['id'], user_id)
+ # user gets a 404 for nonexistent user
+ self.do_request('show_user', expected_status=exceptions.NotFound,
+ user_id='fakeuser')
+
+ def test_identity_list_users(self):
+ domain = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']
+ user_create = self.user()
+ # create user in default domain
+ user1 = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user1['id'])
+ # create user in arbitrary domain
+ user_create['domain_id'] = domain['id']
+ user2 = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user2['id'])
+ resp = self.do_request('list_users')
+ user_ids = set(u['id'] for u in resp['users'])
+ # both users should be in the list
+ self.assertIn(user1['id'], user_ids)
+ self.assertIn(user2['id'], user_ids)
+
+ def test_identity_update_user(self):
+ user = self.admin_users_client.create_user(**self.user())['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ user_update = {
+ 'user_id': user['id'],
+ 'description': data_utils.arbitrary_string()
+ }
+ self.do_request('update_user', **user_update)
+ # user gets a 404 for nonexistent user
+ user_update = {
+ 'user_id': 'fakeuser',
+ 'description': data_utils.arbitrary_string()
+ }
+ self.do_request('update_user', expected_status=exceptions.NotFound,
+ **user_update)
+
+ def test_identity_delete_user(self):
+ user = self.admin_users_client.create_user(**self.user())['user']
+ self.do_request('delete_user', expected_status=204, user_id=user['id'])
+ # user gets a 404 for nonexistent user
+ self.do_request('delete_user', expected_status=exceptions.NotFound,
+ user_id='fakeuser')
+
+
+class SystemMemberTests(IdentityV3RbacUserTest, base.BaseIdentityTest):
+
+ credentials = ['system_member', 'system_admin']
+
+ def test_identity_create_user(self):
+ self.do_request('create_user', expected_status=exceptions.Forbidden,
+ **self.user())
+
+ def test_identity_get_user(self):
+ user = self.admin_users_client.create_user(**self.user())['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ # user can get arbitrary user
+ resp = self.do_request('show_user', user_id=user['id'])
+ self.assertEqual(resp['user']['id'], user['id'])
+ # user can get own user
+ user_id = self.persona.credentials.user_id
+ resp = self.do_request('show_user', user_id=user_id)
+ self.assertEqual(resp['user']['id'], user_id)
+ # user gets a 404 for nonexistent user
+ self.do_request('show_user', expected_status=exceptions.NotFound,
+ user_id='fakeuser')
+
+ def test_identity_list_users(self):
+ domain = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']
+ user_create = self.user()
+ # create user in default domain
+ user1 = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user1['id'])
+ # create user in arbitrary domain
+ user_create['domain_id'] = domain['id']
+ user2 = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user2['id'])
+ resp = self.do_request('list_users')
+ user_ids = set(u['id'] for u in resp['users'])
+ # both users should be in the list
+ self.assertIn(user1['id'], user_ids)
+ self.assertIn(user2['id'], user_ids)
+
+ def test_identity_update_user(self):
+ user = self.admin_users_client.create_user(**self.user())['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ user_update = {
+ 'user_id': user['id'],
+ 'description': data_utils.arbitrary_string()
+ }
+ self.do_request('update_user', expected_status=exceptions.Forbidden,
+ **user_update)
+ # user gets a 403 for nonexistent user
+ user_update = {
+ 'user_id': 'fakeuser',
+ 'description': data_utils.arbitrary_string()
+ }
+ self.do_request('update_user', expected_status=exceptions.Forbidden,
+ **user_update)
+
+ def test_identity_delete_user(self):
+ user = self.admin_users_client.create_user(**self.user())['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ self.do_request('delete_user', expected_status=exceptions.Forbidden,
+ user_id=user['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('delete_user', expected_status=exceptions.Forbidden,
+ user_id='fakeuser')
+
+
+class SystemReaderTests(SystemMemberTests):
+
+ credentials = ['system_reader', 'system_admin']
+
+
+class DomainAdminTests(IdentityV3RbacUserTest, base.BaseIdentityTest):
+
+ credentials = ['domain_admin', 'system_admin']
+
+ def setUp(self):
+ super(DomainAdminTests, self).setUp()
+ self.other_domain = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']
+ self.addCleanup(self.admin_domains_client.delete_domain,
+ self.other_domain['id'])
+ self.addCleanup(self.admin_domains_client.update_domain,
+ domain_id=self.other_domain['id'], enabled=False)
+
+ def test_identity_create_user(self):
+ user_create = self.user()
+ # create user in other domain
+ user_create['domain_id'] = self.other_domain['id']
+ self.do_request('create_user', expected_status=exceptions.Forbidden,
+ **user_create)
+ # create user in own domain
+ user_create['domain_id'] = self.persona.credentials.domain_id
+ resp = self.do_request('create_user',
+ expected_status=201,
+ **user_create)
+ self.addCleanup(self.admin_users_client.delete_user,
+ resp['user']['id'])
+
+ def test_identity_get_user(self):
+ user_create = self.user()
+ user_create['domain_id'] = self.other_domain['id']
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ # user cannot get user in other domain
+ self.do_request('show_user', expected_status=exceptions.Forbidden,
+ user_id=user['id'])
+ user_create['domain_id'] = self.persona.credentials.domain_id
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ # user can get user in own domain
+ resp = self.do_request('show_user', user_id=user['id'])
+ self.assertEqual(resp['user']['id'], user['id'])
+ # user can get own user
+ user_id = self.persona.credentials.user_id
+ resp = self.do_request('show_user', user_id=user_id)
+ self.assertEqual(resp['user']['id'], user_id)
+ # user gets a 403 for nonexistent user
+ self.do_request('show_user', expected_status=exceptions.Forbidden,
+ user_id='fakeuser')
+
+ def test_identity_list_users(self):
+ user_create = self.user()
+ # create user in other domain
+ user_create['domain_id'] = self.other_domain['id']
+ user1 = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user1['id'])
+ # create user in own domain
+ user_create['domain_id'] = self.persona.credentials.domain_id
+ user2 = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user2['id'])
+ resp = self.do_request('list_users')
+ user_ids = set(u['id'] for u in resp['users'])
+ self.assertNotIn(user1['id'], user_ids)
+ self.assertIn(user2['id'], user_ids)
+
+ def test_identity_update_user(self):
+ user_create = self.user()
+ # create user in other domain
+ user_create['domain_id'] = self.other_domain['id']
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ user_update = {
+ 'user_id': user['id'],
+ 'description': data_utils.arbitrary_string()
+ }
+ self.do_request('update_user', expected_status=exceptions.Forbidden,
+ **user_update)
+ # create user in own domain
+ user_create['domain_id'] = self.persona.credentials.domain_id
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ user_update = {
+ 'user_id': user['id'],
+ 'description': data_utils.arbitrary_string()
+ }
+ self.do_request('update_user', **user_update)
+ # user gets a 403 for nonexistent user
+ user_update = {
+ 'user_id': 'fakeuser',
+ 'description': data_utils.arbitrary_string()
+ }
+ self.do_request('update_user', expected_status=exceptions.Forbidden,
+ **user_update)
+
+ def test_identity_delete_user(self):
+ user_create = self.user()
+ # create user in other domain
+ user_create['domain_id'] = self.other_domain['id']
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ self.do_request('delete_user', expected_status=exceptions.Forbidden,
+ user_id=user['id'])
+ # create user in own domain
+ user_create['domain_id'] = self.persona.credentials.domain_id
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.do_request('delete_user', expected_status=204, user_id=user['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('delete_user', expected_status=exceptions.Forbidden,
+ user_id='fakeuser')
+
+
+class DomainMemberTests(IdentityV3RbacUserTest, base.BaseIdentityTest):
+
+ credentials = ['domain_member', 'system_admin']
+
+ def setUp(self):
+ super(DomainMemberTests, self).setUp()
+ self.other_domain = self.admin_domains_client.create_domain(
+ name=data_utils.rand_name())['domain']
+ self.addCleanup(self.admin_domains_client.delete_domain,
+ self.other_domain['id'])
+ self.addCleanup(self.admin_domains_client.update_domain,
+ domain_id=self.other_domain['id'], enabled=False)
+
+ def test_identity_create_user(self):
+ user_create = self.user()
+ # create user without domain specified
+ self.do_request('create_user', expected_status=exceptions.Forbidden,
+ **user_create)
+ # create user in other domain
+ user_create['domain_id'] = self.other_domain['id']
+ self.do_request('create_user', expected_status=exceptions.Forbidden,
+ **user_create)
+ # create user in own domain
+ user_create['domain_id'] = self.persona.credentials.domain_id
+ self.do_request('create_user', expected_status=exceptions.Forbidden,
+ **user_create)
+
+ def test_identity_get_user(self):
+ user_create = self.user()
+ user_create['domain_id'] = self.other_domain['id']
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ # user cannot get user in other domain
+ self.do_request('show_user', expected_status=exceptions.Forbidden,
+ user_id=user['id'])
+ user_create['domain_id'] = self.persona.credentials.domain_id
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ # user can get user in own domain
+ resp = self.do_request('show_user', user_id=user['id'])
+ self.assertEqual(resp['user']['id'], user['id'])
+ # user can get own user
+ user_id = self.persona.credentials.user_id
+ resp = self.do_request('show_user', user_id=user_id)
+ self.assertEqual(resp['user']['id'], user_id)
+ # user gets a 403 for nonexistent user
+ self.do_request('show_user', expected_status=exceptions.Forbidden,
+ user_id='fakeuser')
+
+ def test_identity_list_users(self):
+ user_create = self.user()
+ # create user in other domain
+ user_create['domain_id'] = self.other_domain['id']
+ user1 = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user1['id'])
+ # create user in own domain
+ user_create['domain_id'] = self.persona.credentials.domain_id
+ user2 = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user2['id'])
+ resp = self.do_request('list_users')
+ user_ids = set(u['id'] for u in resp['users'])
+ self.assertNotIn(user1['id'], user_ids)
+ self.assertIn(user2['id'], user_ids)
+
+ def test_identity_update_user(self):
+ user_create = self.user()
+ # create user in other domain
+ user_create['domain_id'] = self.other_domain['id']
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ user_update = {
+ 'user_id': user['id'],
+ 'description': data_utils.arbitrary_string()
+ }
+ self.do_request('update_user', expected_status=exceptions.Forbidden,
+ **user_update)
+ # create user in own domain
+ user_create['domain_id'] = self.persona.credentials.domain_id
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ user_update = {
+ 'user_id': user['id'],
+ 'description': data_utils.arbitrary_string()
+ }
+ self.do_request('update_user', expected_status=exceptions.Forbidden,
+ **user_update)
+ # user gets a 403 for nonexistent user
+ user_update = {
+ 'user_id': 'fakeuser',
+ 'description': data_utils.arbitrary_string()
+ }
+ self.do_request('update_user', expected_status=exceptions.Forbidden,
+ **user_update)
+
+ def test_identity_delete_user(self):
+ user_create = self.user()
+ # create user in other domain
+ user_create['domain_id'] = self.other_domain['id']
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ self.do_request('delete_user', expected_status=exceptions.Forbidden,
+ user_id=user['id'])
+ # create user in own domain
+ user_create['domain_id'] = self.persona.credentials.domain_id
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.do_request('delete_user', expected_status=exceptions.Forbidden,
+ user_id=user['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('delete_user', expected_status=exceptions.Forbidden,
+ user_id='fakeuser')
+
+
+class DomainReaderTests(DomainMemberTests):
+
+ credentials = ['domain_reader', 'system_admin']
+
+
+class ProjectAdminTests(IdentityV3RbacUserTest, base.BaseIdentityTest):
+
+ credentials = ['project_admin', 'system_admin']
+
+ def test_identity_create_user(self):
+ self.do_request('create_user', expected_status=exceptions.Forbidden,
+ **self.user())
+
+ def test_identity_get_user(self):
+ user = self.admin_users_client.create_user(**self.user())['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ # user cannot get arbitrary user
+ self.do_request('show_user', expected_status=exceptions.Forbidden,
+ user_id=user['id'])
+ # user can get own user
+ user_id = self.persona.credentials.user_id
+ resp = self.do_request('show_user', user_id=user_id)
+ self.assertEqual(resp['user']['id'], user_id)
+ # user gets a 403 for nonexistent user
+ self.do_request('show_user', expected_status=exceptions.Forbidden,
+ user_id='fakeuser')
+
+ def test_identity_list_users(self):
+ user = self.admin_users_client.create_user(**self.user())['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ self.do_request('list_users', expected_status=exceptions.Forbidden)
+
+ def test_identity_update_user(self):
+ user_create = self.user()
+ user = self.admin_users_client.create_user(**user_create)['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ user_update = {
+ 'user_id': user['id'],
+ 'description': data_utils.arbitrary_string()
+ }
+ self.do_request('update_user', expected_status=exceptions.Forbidden,
+ **user_update)
+ # user gets a 403 for nonexistent user
+ user_update = {
+ 'user_id': 'fakeuser',
+ 'description': data_utils.arbitrary_string()
+ }
+ self.do_request('update_user', expected_status=exceptions.Forbidden,
+ **user_update)
+
+ def test_identity_delete_user(self):
+ user = self.admin_users_client.create_user(**self.user())['user']
+ self.addCleanup(self.admin_users_client.delete_user, user['id'])
+ self.do_request('delete_user', expected_status=exceptions.Forbidden,
+ user_id=user['id'])
+ # user gets a 403 for nonexistent user
+ self.do_request('delete_user', expected_status=exceptions.Forbidden,
+ user_id='fakeuser')
+
+
+class ProjectMemberTests(ProjectAdminTests):
+
+ credentials = ['project_member', 'system_admin']
+
+
+class ProjectReaderTests(ProjectAdminTests):
+
+ credentials = ['project_reader', 'system_admin']
diff --git a/tox.ini b/tox.ini
index 8b4a058..570c029 100644
--- a/tox.ini
+++ b/tox.ini
@@ -42,6 +42,6 @@
# E123, E125 skipped as they are invalid PEP-8.
show-source = True
-ignore = E123,E125
+ignore = E123,E125,W503
builtins = _
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build