diff --git a/.zuul.yaml b/.zuul.yaml index 11a43a8..84b2fdd 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 @@ -11,10 +47,12 @@ - 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-ubuntu-focal-k2k + - keystone-protection-functional - job: name: keystone-dsvm-py3-functional-ussuri 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 @@ identity_feature_option = [ 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 @@ class KeystoneTempestPlugin(plugins.TempestPlugin): 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/tests/rbac/__init__.py b/keystone_tempest_plugin/tests/rbac/__init__.py new file mode 100644 index 0000000..e69de29 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 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..13fe16a --- /dev/null +++ b/keystone_tempest_plugin/tests/rbac/v3/test_application_credential.py @@ -0,0 +1,551 @@ +# 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 + 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=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 + 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=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 @@ commands = oslo_debug_helper {posargs} # 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