From f0ef5741c1ffb4173ce5d845a4ec30e075984b3e Mon Sep 17 00:00:00 2001 From: Lance Bragstad Date: Fri, 22 Mar 2019 22:07:44 +0000 Subject: [PATCH] Implement domain reader support for grants This commit adds testing and policy changes for domain users to be able to manage grants within their domain. Co-Authored-By: Vishakha Agarwal Co-Authored-By: Colleen Murphy Change-Id: I453203a4d92c391612cb7efc5dd4287ef30f7392 Partial-Bug: 1805368 Partial-Bug: 1750669 --- keystone/common/policies/grant.py | 39 +- .../tests/unit/protection/v3/test_grants.py | 1605 +++++++++++++++++ 2 files changed, 1638 insertions(+), 6 deletions(-) diff --git a/keystone/common/policies/grant.py b/keystone/common/policies/grant.py index 5c383b0ca3..25a54af22e 100644 --- a/keystone/common/policies/grant.py +++ b/keystone/common/policies/grant.py @@ -15,6 +15,35 @@ from oslo_policy import policy from keystone.common.policies import base +# Two of the three portions of this check string are specific to domain +# readers. The first catches domain readers who are checking or listing grants +# for users. The second does the same for groups. We have to overload the check +# string to handle both cases because `identity:check_grant` is used to protect +# both user and group grant APIs. If the `identity:check_grant` policy is every +# broken apart, we can write specific check strings that are tailored to either +# users or groups (e.g., `identity:check_group_grant` or +# `identity:check_user_grant`) and prevent overloading like this. +DOMAIN_MATCHES_USER_DOMAIN = 'domain_id:%(target.user.domain_id)s' +DOMAIN_MATCHES_GROUP_DOMAIN = 'domain_id:%(target.group.domain_id)s' +DOMAIN_MATCHES_PROJECT_DOMAIN = 'domain_id:%(target.project.domain_id)s' +DOMAIN_MATCHES_TARGET_DOMAIN = 'domain_id:%(target.domain.id)s' +DOMAIN_MATCHES_ROLE = 'domain_id:%(target.role.domain_id)s or None:%(target.role.domain_id)s' +GRANTS_DOMAIN_READER = ( + '(role:reader and ' + DOMAIN_MATCHES_USER_DOMAIN + ' and ' + DOMAIN_MATCHES_PROJECT_DOMAIN + ') or ' + '(role:reader and ' + DOMAIN_MATCHES_USER_DOMAIN + ' and ' + DOMAIN_MATCHES_TARGET_DOMAIN + ') or ' + '(role:reader and ' + DOMAIN_MATCHES_GROUP_DOMAIN + ' and ' + DOMAIN_MATCHES_PROJECT_DOMAIN + ') or ' + '(role:reader and ' + DOMAIN_MATCHES_GROUP_DOMAIN + ' and ' + DOMAIN_MATCHES_TARGET_DOMAIN + ')' +) +SYSTEM_READER_OR_DOMAIN_READER = ( + '(' + base.SYSTEM_READER + ') or ' + '(' + GRANTS_DOMAIN_READER + ') and ' + '(' + DOMAIN_MATCHES_ROLE + ')' +) + +SYSTEM_READER_OR_DOMAIN_READER_LIST = ( + '(' + base.SYSTEM_READER + ') or ' + GRANTS_DOMAIN_READER +) + deprecated_check_system_grant_for_user = policy.DeprecatedRule( name=base.IDENTITY % 'check_system_grant_for_user', check_str=base.RULE_ADMIN_REQUIRED @@ -111,14 +140,14 @@ list_grants_operations = ( grant_policies = [ policy.DocumentedRuleDefault( name=base.IDENTITY % 'check_grant', - check_str=base.SYSTEM_READER, + check_str=SYSTEM_READER_OR_DOMAIN_READER, # FIXME(lbragstad): A system administrator should be able to grant role # assignments from any actor to any target in the deployment. Domain # administrators should only be able to grant access to the domain they # administer or projects within that domain. Once keystone is smart # enough to enforce those checks in code, we can add 'project' to the # list of scope_types below. - scope_types=['system'], + scope_types=['system', 'domain'], description=('Check a role grant between a target and an actor. A ' 'target can be either a domain or a project. An actor ' 'can be either a user or a group. These terms also apply ' @@ -131,10 +160,8 @@ grant_policies = [ deprecated_since=versionutils.deprecated.STEIN), policy.DocumentedRuleDefault( name=base.IDENTITY % 'list_grants', - check_str=base.SYSTEM_READER, - # FIXME(lbragstad): See the above comment about scope_types before - # adding 'project' to scope_types below. - scope_types=['system'], + check_str=SYSTEM_READER_OR_DOMAIN_READER_LIST, + scope_types=['system', 'domain'], description=('List roles granted to an actor on a target. A target ' 'can be either a domain or a project. An actor can be ' 'either a user or a group. For the OS-INHERIT APIs, it ' diff --git a/keystone/tests/unit/protection/v3/test_grants.py b/keystone/tests/unit/protection/v3/test_grants.py index 1628cd6ada..65a757a5ba 100644 --- a/keystone/tests/unit/protection/v3/test_grants.py +++ b/keystone/tests/unit/protection/v3/test_grants.py @@ -12,8 +12,10 @@ import uuid +from oslo_serialization import jsonutils from six.moves import http_client +from keystone.common.policies import grant as gp from keystone.common import provider_api import keystone.conf from keystone.tests.common import auth as common_auth @@ -394,6 +396,1522 @@ class _SystemMemberAndReaderGrantTests(object): ) +class _DomainUserTests(object): + + def test_user_can_list_grants_for_user_on_project(self): + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=self.domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref(domain_id=self.domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + r = c.get( + '/v3/projects/%s/users/%s/roles' % (project['id'], user['id']), + headers=self.headers + ) + self.assertEqual(1, len(r.json['roles'])) + + def test_user_can_list_grants_for_user_on_domain(self): + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=self.domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + domain_id=self.domain_id + ) + + with self.test_client() as c: + r = c.get( + '/v3/domains/%s/users/%s/roles' % (self.domain_id, user['id']), + headers=self.headers + ) + self.assertEqual(1, len(r.json['roles'])) + + def test_user_can_list_grants_for_group_on_project(self): + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=self.domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref(domain_id=self.domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + r = c.get( + '/v3/projects/%s/groups/%s/roles' % ( + project['id'], group['id']), + headers=self.headers + ) + self.assertEqual(1, len(r.json['roles'])) + + def test_user_can_list_grants_for_group_on_domain(self): + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=self.domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + domain_id=self.domain_id + ) + + with self.test_client() as c: + r = c.get( + '/v3/domains/%s/groups/%s/roles' % ( + self.domain_id, group['id'] + ), headers=self.headers + ) + self.assertEqual(1, len(r.json['roles'])) + + def test_user_can_check_grant_for_user_on_project(self): + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=self.domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=self.domain_id + ) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.get( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.NO_CONTENT + ) + + def test_user_can_check_grant_for_user_on_domain(self): + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=self.domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + domain_id=self.domain_id + ) + + with self.test_client() as c: + c.get( + '/v3/domains/%s/users/%s/roles/%s' % ( + self.domain_id, user['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.NO_CONTENT + ) + + def test_user_can_check_grant_for_group_on_project(self): + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=self.domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref(domain_id=self.domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.get( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], + group['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.NO_CONTENT + ) + + def test_user_can_check_grant_for_group_on_domain(self): + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=self.domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + domain_id=self.domain_id + ) + + with self.test_client() as c: + c.get( + '/v3/domains/%s/groups/%s/roles/%s' % ( + self.domain_id, group['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.NO_CONTENT + ) + + def test_user_cannot_list_grants_for_user_other_domain_on_project_own_domain(self): + user_domain_id = CONF.identity.default_domain_id + project_domain_id = self.domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref(domain_id=project_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.get( + '/v3/projects/%s/users/%s/roles' % (project['id'], user['id']), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_list_grants_for_user_own_domain_on_project_other_domain(self): + user_domain_id = self.domain_id + project_domain_id = CONF.identity.default_domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, + unit.new_project_ref(domain_id=project_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.get( + '/v3/projects/%s/users/%s/roles' % (project['id'], user['id']), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_list_grants_for_user_own_domain_on_other_domain(self): + user_domain_id = self.domain_id + domain_id = CONF.identity.default_domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.get( + '/v3/domains/%s/users/%s/roles' % (domain_id, user['id']), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_list_grants_for_user_other_domain_on_own_domain(self): + user_domain_id = CONF.identity.default_domain_id + domain_id = self.domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.get( + '/v3/domains/%s/users/%s/roles' % (domain_id, user['id']), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_list_grants_for_group_other_domain_on_project_own_domain(self): + group_domain_id = CONF.identity.default_domain_id + project_domain_id = self.domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref(domain_id=project_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.get( + '/v3/projects/%s/groups/%s/roles' % ( + project['id'], group['id']), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_list_grants_for_group_own_domain_on_project_other_domain(self): + group_domain_id = self.domain_id + project_domain_id = CONF.identity.default_domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, + unit.new_project_ref(domain_id=project_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.get( + '/v3/projects/%s/groups/%s/roles' % ( + project['id'], group['id']), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_list_grants_for_group_own_domain_on_other_domain(self): + group_domain_id = self.domain_id + domain_id = CONF.identity.default_domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.get( + '/v3/domains/%s/groups/%s/roles' % ( + domain_id, group['id']), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_list_grants_for_group_other_domain_on_own_domain(self): + group_domain_id = CONF.identity.default_domain_id + domain_id = self.domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.get( + '/v3/domains/%s/groups/%s/roles' % ( + domain_id, group['id']), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_check_grant_for_user_other_domain_on_project_own_domain(self): + user_domain_id = CONF.identity.default_domain_id + project_domain_id = self.domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref(domain_id=project_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.get( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], + self.bootstrapper.reader_role_id), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_check_grant_for_user_own_domain_on_project_other_domain(self): + user_domain_id = self.domain_id + project_domain_id = CONF.identity.default_domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, + unit.new_project_ref(domain_id=project_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.get( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], + self.bootstrapper.reader_role_id), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_check_grant_for_user_own_domain_on_project_own_domain_with_role_other_domain(self): + user_domain_id = self.domain_id + project_domain_id = self.domain_id + role_domain_id = CONF.identity.default_domain_id + + role = PROVIDERS.role_api.create_role( + uuid.uuid4().hex, unit.new_role_ref(domain_id=role_domain_id)) + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, + unit.new_project_ref(domain_id=project_domain_id) + ) + + # NOTE(cmurphy) the grant for a domain-specific role cannot be created + # for a project in a different domain, so we don't try to create it, + # but we still need to test that checking the role results in a 403 and + # not a 404 + + with self.test_client() as c: + c.get( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], + role['id']), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_check_grant_for_user_own_domain_on_other_domain(self): + user_domain_id = self.domain_id + domain_id = CONF.identity.default_domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.get( + '/v3/domains/%s/users/%s/roles/%s' % ( + domain_id, user['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_check_grant_for_user_other_domain_on_own_domain(self): + user_domain_id = CONF.identity.default_domain_id + domain_id = self.domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.get( + '/v3/domains/%s/users/%s/roles/%s' % ( + domain_id, user['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_check_grant_for_user_own_domain_on_own_domain_with_role_other_domain(self): + user_domain_id = self.domain_id + domain_id = self.domain_id + role_domain_id = CONF.identity.default_domain_id + + role = PROVIDERS.role_api.create_role( + uuid.uuid4().hex, + unit.new_role_ref(domain_id=role_domain_id)) + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + # NOTE(cmurphy) the grant for a domain-specific role cannot be created + # for a project in a different domain, so we don't try to create it, + # but we still need to test that checking the role results in a 403 and + # not a 404 + + with self.test_client() as c: + c.get( + '/v3/domains/%s/users/%s/roles/%s' % ( + domain_id, user['id'], + role['id'] + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_check_grant_for_group_other_domain_on_project_own_domain(self): + group_domain_id = CONF.identity.default_domain_id + project_domain_id = self.domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref(domain_id=project_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.get( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], group['id'], + self.bootstrapper.reader_role_id), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_check_grant_for_group_own_domain_on_project_other_domain(self): + group_domain_id = self.domain_id + project_domain_id = CONF.identity.default_domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref(domain_id=project_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.get( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], group['id'], + self.bootstrapper.reader_role_id), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_check_grant_for_group_own_domain_on_project_own_domain_with_role_other_domain(self): + group_domain_id = self.domain_id + project_domain_id = CONF.identity.default_domain_id + role_domain_id = CONF.identity.default_domain_id + + role = PROVIDERS.role_api.create_role( + uuid.uuid4().hex, + unit.new_role_ref(domain_id=role_domain_id)) + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref(domain_id=project_domain_id) + ) + + # NOTE(cmurphy) the grant for a domain-specific role cannot be created + # for a project in a different domain, so we don't try to create it, + # but we still need to test that checking the role results in a 403 and + # not a 404 + + with self.test_client() as c: + c.get( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], group['id'], + role['id']), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_check_grant_for_group_own_domain_on_other_domain(self): + group_domain_id = self.domain_id + domain_id = CONF.identity.default_domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.get( + '/v3/domains/%s/groups/%s/roles/%s' % ( + domain_id, group['id'], + self.bootstrapper.reader_role_id), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_check_grant_for_group_other_domain_on_own_domain(self): + group_domain_id = CONF.identity.default_domain_id + domain_id = self.domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.get( + '/v3/domains/%s/groups/%s/roles/%s' % ( + domain_id, group['id'], + self.bootstrapper.reader_role_id), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_check_grant_for_group_own_domain_on_own_domain_with_role_other_domain(self): + group_domain_id = self.domain_id + domain_id = self.domain_id + role_domain_id = CONF.identity.default_domain_id + + role = PROVIDERS.role_api.create_role(uuid.uuid4().hex, unit.new_role_ref(domain_id=role_domain_id)) + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + # NOTE(cmurphy) the grant for a domain-specific role cannot be created + # for a project in a different domain, so we don't try to create it, + # but we still need to test that checking the role results in a 403 and + # not a 404 + + with self.test_client() as c: + c.get( + '/v3/domains/%s/groups/%s/roles/%s' % ( + domain_id, group['id'], + role['id']), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_user_other_domain_on_project_own_domain(self): + user_domain_id = CONF.identity.default_domain_id + project_domain_id = self.domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=project_domain_id + ) + ) + + with self.test_client() as c: + c.put( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_user_own_domain_on_project_other_domain(self): + user_domain_id = self.domain_id + project_domain_id = CONF.identity.default_domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=project_domain_id + ) + ) + + with self.test_client() as c: + c.put( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_cannot_create_grant_for_user_own_domain_on_project_own_domain_with_role_other_domain(self): + user_domain_id = self.domain_id + project_domain_id = self.domain_id + role_domain_id = CONF.identity.default_domain_id + + role = PROVIDERS.role_api.create_role( + uuid.uuid4().hex, unit.new_role_ref(domain_id=role_domain_id)) + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=project_domain_id + ) + ) + with self.test_client() as c: + c.put( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], role['id'] + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_user_other_domain_on_own_domain(self): + user_domain_id = CONF.identity.default_domain_id + domain_id = self.domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + with self.test_client() as c: + c.put( + '/v3/domains/%s/users/%s/roles/%s' % ( + domain_id, user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_user_own_domain_on_other_domain(self): + user_domain_id = self.domain_id + domain_id = CONF.identity.default_domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + with self.test_client() as c: + c.put( + '/v3/domains/%s/users/%s/roles/%s' % ( + domain_id, user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_cannot_create_grant_for_user_own_domain_on_own_domain_with_role_other_domain(self): + user_domain_id = self.domain_id + domain_id = self.domain_id + role_domain_id = CONF.identity.default_domain_id + + role = PROVIDERS.role_api.create_role( + uuid.uuid4().hex, unit.new_role_ref(domain_id=role_domain_id)) + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + with self.test_client() as c: + c.put( + '/v3/domains/%s/users/%s/roles/%s' % ( + domain_id, user['id'], role['id'] + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_group_other_domain_on_project_own_domain(self): + group_domain_id = CONF.identity.default_domain_id + project_domain_id = self.domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=project_domain_id + ) + ) + + with self.test_client() as c: + c.put( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], + group['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_group_own_domain_on_project_other_domain(self): + group_domain_id = self.domain_id + project_domain_id = CONF.identity.default_domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=project_domain_id + ) + ) + + with self.test_client() as c: + c.put( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], + group['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_cannot_create_grant_for_group_own_domain_on_project_own_domain_with_role_other_domain(self): + group_domain_id = self.domain_id + project_domain_id = self.domain_id + role_domain_id = CONF.identity.default_domain_id + + role = PROVIDERS.role_api.create_role( + uuid.uuid4().hex, unit.new_role_ref(domain_id=role_domain_id)) + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=project_domain_id + ) + ) + + with self.test_client() as c: + c.put( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], + group['id'], + role['id'] + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_group_other_domain_on_own_domain(self): + group_domain_id = CONF.identity.default_domain_id + domain_id = self.domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + with self.test_client() as c: + c.put( + '/v3/domains/%s/groups/%s/roles/%s' % ( + domain_id, group['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_group_own_domain_on_other_domain(self): + group_domain_id = self.domain_id + domain_id = CONF.identity.default_domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + with self.test_client() as c: + c.put( + '/v3/domains/%s/groups/%s/roles/%s' % ( + domain_id, group['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_group_own_domain_on_own_domain_with_role_other_domain(self): + group_domain_id = self.domain_id + domain_id = self.domain_id + role_domain_id = CONF.identity.default_domain_id + + role = PROVIDERS.role_api.create_role( + uuid.uuid4().hex, unit.new_role_ref(domain_id=role_domain_id)) + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + with self.test_client() as c: + c.put( + '/v3/domains/%s/groups/%s/roles/%s' % ( + domain_id, group['id'], role['id'] + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_user_other_domain_on_project_own_domain(self): + user_domain_id = CONF.identity.default_domain_id + project_domain_id = self.domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=project_domain_id + ) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.delete( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_user_own_domain_on_project_other_domain(self): + user_domain_id = self.domain_id + project_domain_id = CONF.identity.default_domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=project_domain_id + ) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.delete( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_user_other_domain_on_own_domain(self): + user_domain_id = CONF.identity.default_domain_id + domain_id = self.domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.delete( + '/v3/domains/%s/users/%s/roles/%s' % ( + domain_id, user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_user_own_domain_on_other_domain(self): + user_domain_id = self.domain_id + domain_id = CONF.identity.default_domain_id + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.delete( + '/v3/domains/%s/users/%s/roles/%s' % ( + domain_id, user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_user_own_domain_on_own_domain_with_role_other_domain(self): + user_domain_id = self.domain_id + domain_id = self.domain_id + role_domain_id = CONF.identity.default_domain_id + + role = PROVIDERS.role_api.create_role( + uuid.uuid4().hex, unit.new_role_ref(domain_id=role_domain_id)) + + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=user_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + role['id'], user_id=user['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.delete( + '/v3/domains/%s/users/%s/roles/%s' % ( + domain_id, user['id'], role['id'] + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_group_other_domain_on_project_own_domain(self): + group_domain_id = CONF.identity.default_domain_id + project_domain_id = self.domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=project_domain_id + ) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.delete( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], + group['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_group_own_domain_on_project_other_domain(self): + group_domain_id = self.domain_id + project_domain_id = CONF.identity.default_domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=project_domain_id + ) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.delete( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], + group['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_group_other_domain_on_own_domain(self): + group_domain_id = CONF.identity.default_domain_id + domain_id = self.domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.delete( + '/v3/domains/%s/groups/%s/roles/%s' % ( + domain_id, group['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_group_own_domain_on_other_domain(self): + group_domain_id = self.domain_id + domain_id = CONF.identity.default_domain_id + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.delete( + '/v3/domains/%s/groups/%s/roles/%s' % ( + domain_id, group['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_group_own_domain_on_own_domain_with_role_other_domain(self): + group_domain_id = self.domain_id + domain_id = self.domain_id + role_domain_id = CONF.identity.default_domain_id + + role = PROVIDERS.role_api.create_role( + uuid.uuid4().hex, + unit.new_role_ref(domain_id=role_domain_id)) + + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=group_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + role['id'], group_id=group['id'], + domain_id=domain_id + ) + + with self.test_client() as c: + c.delete( + '/v3/domains/%s/groups/%s/roles/%s' % ( + domain_id, group['id'], role['id'] + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + +class _DomainMemberAndReaderTests(object): + + def test_user_cannot_create_grant_for_user_on_project(self): + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=self.domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=CONF.identity.default_domain_id + ) + ) + + with self.test_client() as c: + c.put( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_user_on_domain(self): + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=self.domain_id) + ) + + domain = PROVIDERS.resource_api.create_domain( + uuid.uuid4().hex, unit.new_domain_ref() + ) + + with self.test_client() as c: + c.put( + '/v3/domains/%s/users/%s/roles/%s' % ( + domain['id'], user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_group_on_project(self): + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=self.domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref(domain_id=self.domain_id) + ) + + with self.test_client() as c: + c.put( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], + group['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_group_on_domain(self): + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=self.domain_id) + ) + + domain = PROVIDERS.resource_api.create_domain( + uuid.uuid4().hex, unit.new_domain_ref() + ) + + with self.test_client() as c: + c.put( + '/v3/domains/%s/groups/%s/roles/%s' % ( + domain['id'], group['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_user_on_project_other_domain(self): + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=CONF.identity.default_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=self.domain_id + ) + ) + + with self.test_client() as c: + c.put( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_user_on_other_domain(self): + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=CONF.identity.default_domain_id) + ) + + with self.test_client() as c: + c.put( + '/v3/domains/%s/users/%s/roles/%s' % ( + self.domain_id, user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_group_on_project_other_domain(self): + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=CONF.identity.default_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=self.domain_id + ) + ) + + with self.test_client() as c: + c.put( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], + group['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_create_grant_for_group_on_other_domain(self): + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=CONF.identity.default_domain_id) + ) + + with self.test_client() as c: + c.put( + '/v3/domains/%s/groups/%s/roles/%s' % ( + self.domain_id, group['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_user_on_project(self): + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=self.domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref(domain_id=self.domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.delete( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_user_on_domain(self): + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=self.domain_id) + ) + + domain = PROVIDERS.resource_api.create_domain( + uuid.uuid4().hex, unit.new_domain_ref() + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + domain_id=domain['id'] + ) + + with self.test_client() as c: + c.delete( + '/v3/domains/%s/users/%s/roles/%s' % ( + domain['id'], user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_group_on_project(self): + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=self.domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=CONF.identity.default_domain_id + ) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.delete( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], + group['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_group_on_domain(self): + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=self.domain_id) + ) + + domain = PROVIDERS.resource_api.create_domain( + uuid.uuid4().hex, unit.new_domain_ref() + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + domain_id=domain['id'] + ) + + with self.test_client() as c: + c.delete( + '/v3/domains/%s/groups/%s/roles/%s' % ( + domain['id'], group['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_user_on_project_other_domain(self): + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=CONF.identity.default_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=self.domain_id + ) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.delete( + '/v3/projects/%s/users/%s/roles/%s' % ( + project['id'], user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_user_on_other_domain(self): + user = PROVIDERS.identity_api.create_user( + unit.new_user_ref(domain_id=CONF.identity.default_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=user['id'], + domain_id=self.domain_id + ) + + with self.test_client() as c: + c.delete( + '/v3/domains/%s/users/%s/roles/%s' % ( + self.domain_id, user['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_group_on_project_other_domain(self): + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=CONF.identity.default_domain_id) + ) + + project = PROVIDERS.resource_api.create_project( + uuid.uuid4().hex, unit.new_project_ref( + domain_id=self.domain_id + ) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + project_id=project['id'] + ) + + with self.test_client() as c: + c.delete( + '/v3/projects/%s/groups/%s/roles/%s' % ( + project['id'], + group['id'], + self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + def test_user_cannot_revoke_grant_from_group_on_other_domain(self): + group = PROVIDERS.identity_api.create_group( + unit.new_group_ref(domain_id=CONF.identity.default_domain_id) + ) + + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, group_id=group['id'], + domain_id=self.domain_id + ) + + with self.test_client() as c: + c.delete( + '/v3/domains/%s/groups/%s/roles/%s' % ( + self.domain_id, group['id'], self.bootstrapper.reader_role_id + ), + headers=self.headers, + expected_status_code=http_client.FORBIDDEN + ) + + class SystemReaderTests(base_classes.TestCaseWithBootstrap, common_auth.AuthTestMixin, _SystemUserGrantTests, @@ -486,6 +2004,24 @@ class SystemAdminTests(base_classes.TestCaseWithBootstrap, self.token_id = r.headers['X-Subject-Token'] self.headers = {'X-Auth-Token': self.token_id} + def _override_policy(self): + # TODO(lbragstad): Remove this once the deprecated policies in + # keystone.common.policies.grant have been removed. This is only + # here to make sure we test the new policies instead of the deprecated + # ones. Oslo.policy will OR deprecated policies with new policies to + # maintain compatibility and give operators a chance to update + # permissions or update policies without breaking users. This will + # cause these specific tests to fail since we're trying to correct this + # broken behavior with better scope checking. + with open(self.policy_file_name, 'w') as f: + overridden_policies = { + 'identity:list_grants': gp.SYSTEM_READER_OR_DOMAIN_READER_LIST, + 'identity:check_grant': gp.SYSTEM_READER_OR_DOMAIN_READER, + 'identity:create_grant': gp.SYSTEM_ADMIN_OR_DOMAIN_ADMIN, + 'identity:revoke_grant': gp.SYSTEM_ADMIN_OR_DOMAIN_ADMIN + } + f.write(jsonutils.dumps(overridden_policies)) + def test_user_can_create_grant_for_user_on_project(self): user = PROVIDERS.identity_api.create_user( unit.new_user_ref(domain_id=CONF.identity.default_domain_id) @@ -653,3 +2189,72 @@ class SystemAdminTests(base_classes.TestCaseWithBootstrap, ), headers=self.headers ) + + +class DomainReaderTests(base_classes.TestCaseWithBootstrap, + common_auth.AuthTestMixin, + _DomainUserTests, + _DomainMemberAndReaderTests): + + def setUp(self): + super(DomainReaderTests, self).setUp() + self.loadapp() + self.useFixture(ksfixtures.Policy(self.config_fixture)) + self.config_fixture.config(group='oslo_policy', enforce_scope=True) + + domain = PROVIDERS.resource_api.create_domain( + uuid.uuid4().hex, unit.new_domain_ref() + ) + self.domain_id = domain['id'] + domain_user = unit.new_user_ref(domain_id=self.domain_id) + self.user_id = PROVIDERS.identity_api.create_user(domain_user)['id'] + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=self.user_id, + domain_id=self.domain_id + ) + + auth = self.build_authentication_request( + user_id=self.user_id, password=domain_user['password'], + domain_id=self.domain_id + ) + + # Grab a token using the persona we're testing and prepare headers + # for requests we'll be making in the tests. + with self.test_client() as c: + r = c.post('/v3/auth/tokens', json=auth) + self.token_id = r.headers['X-Subject-Token'] + self.headers = {'X-Auth-Token': self.token_id} + + +class DomainMemberTests(base_classes.TestCaseWithBootstrap, + common_auth.AuthTestMixin, + _DomainUserTests, + _DomainMemberAndReaderTests): + + def setUp(self): + super(DomainMemberTests, self).setUp() + self.loadapp() + self.useFixture(ksfixtures.Policy(self.config_fixture)) + self.config_fixture.config(group='oslo_policy', enforce_scope=True) + domain = PROVIDERS.resource_api.create_domain( + uuid.uuid4().hex, unit.new_domain_ref() + ) + self.domain_id = domain['id'] + domain_user = unit.new_user_ref(domain_id=self.domain_id) + self.user_id = PROVIDERS.identity_api.create_user(domain_user)['id'] + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.member_role_id, user_id=self.user_id, + domain_id=self.domain_id + ) + + auth = self.build_authentication_request( + user_id=self.user_id, password=domain_user['password'], + domain_id=self.domain_id + ) + + # Grab a token using the persona we're testing and prepare headers + # for requests we'll be making in the tests. + with self.test_client() as c: + r = c.post('/v3/auth/tokens', json=auth) + self.token_id = r.headers['X-Subject-Token'] + self.headers = {'X-Auth-Token': self.token_id}