Implement domain admin support for grants

This commit goes through and updates grant policies to allow domain
administrator to manager grants for their domains and projects within
thier domain.

Co-Authored-By: Colleen Murphy <colleen@gazlene.net>

Change-Id: I5f1839a3f8d23d17e449aa9f8710d70233ee8fcc
Closes-Bug: 1805368
Closes-Bug: 1750669
This commit is contained in:
Lance Bragstad 2019-06-26 20:54:22 +00:00 committed by Colleen Murphy
parent f0ef5741c1
commit bbd77d0bf9
3 changed files with 396 additions and 367 deletions

View File

@ -44,6 +44,18 @@ SYSTEM_READER_OR_DOMAIN_READER_LIST = (
'(' + base.SYSTEM_READER + ') or ' + GRANTS_DOMAIN_READER
)
GRANTS_DOMAIN_ADMIN = (
'(role:admin and ' + DOMAIN_MATCHES_USER_DOMAIN + ' and ' + DOMAIN_MATCHES_PROJECT_DOMAIN + ') or '
'(role:admin and ' + DOMAIN_MATCHES_USER_DOMAIN + ' and ' + DOMAIN_MATCHES_TARGET_DOMAIN + ') or '
'(role:admin and ' + DOMAIN_MATCHES_GROUP_DOMAIN + ' and ' + DOMAIN_MATCHES_PROJECT_DOMAIN + ') or '
'(role:admin and ' + DOMAIN_MATCHES_GROUP_DOMAIN + ' and ' + DOMAIN_MATCHES_TARGET_DOMAIN + ')'
)
SYSTEM_ADMIN_OR_DOMAIN_ADMIN = (
'(' + base.SYSTEM_ADMIN + ') or '
'(' + GRANTS_DOMAIN_ADMIN + ') and '
'(' + DOMAIN_MATCHES_ROLE + ')'
)
deprecated_check_system_grant_for_user = policy.DeprecatedRule(
name=base.IDENTITY % 'check_system_grant_for_user',
check_str=base.RULE_ADMIN_REQUIRED
@ -141,12 +153,6 @@ grant_policies = [
policy.DocumentedRuleDefault(
name=base.IDENTITY % 'check_grant',
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', 'domain'],
description=('Check a role grant between a target and an actor. A '
'target can be either a domain or a project. An actor '
@ -174,10 +180,8 @@ grant_policies = [
deprecated_since=versionutils.deprecated.STEIN),
policy.DocumentedRuleDefault(
name=base.IDENTITY % 'create_grant',
check_str=base.SYSTEM_ADMIN,
# FIXME(lbragstad): See the above comment about scope_types before
# adding 'project' to scope_types below.
scope_types=['system'],
check_str=SYSTEM_ADMIN_OR_DOMAIN_ADMIN,
scope_types=['system', 'domain'],
description=('Create 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 '
@ -190,10 +194,8 @@ grant_policies = [
deprecated_since=versionutils.deprecated.STEIN),
policy.DocumentedRuleDefault(
name=base.IDENTITY % 'revoke_grant',
check_str=base.SYSTEM_ADMIN,
# FIXME(lbragstad): See the above comment about scope_types before
# adding 'project' to scope_types below.
scope_types=['system'],
check_str=SYSTEM_ADMIN_OR_DOMAIN_ADMIN,
scope_types=['system', 'domain'],
description=('Revoke 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 '

View File

@ -22,6 +22,7 @@ from keystone.tests.common import auth as common_auth
from keystone.tests import unit
from keystone.tests.unit import base_classes
from keystone.tests.unit import ksfixtures
from keystone.tests.unit.ksfixtures import temporaryfile
CONF = keystone.conf.CONF
PROVIDERS = provider_api.ProviderAPIs
@ -1577,341 +1578,6 @@ class _DomainUserTests(object):
)
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,
@ -2004,24 +1670,6 @@ 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)
@ -2191,6 +1839,181 @@ class SystemAdminTests(base_classes.TestCaseWithBootstrap,
)
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_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
)
class DomainReaderTests(base_classes.TestCaseWithBootstrap,
common_auth.AuthTestMixin,
_DomainUserTests,
@ -2258,3 +2081,168 @@ class DomainMemberTests(base_classes.TestCaseWithBootstrap,
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 DomainAdminTests(base_classes.TestCaseWithBootstrap,
common_auth.AuthTestMixin,
_DomainUserTests):
def setUp(self):
super(DomainAdminTests, self).setUp()
self.loadapp()
self.policy_file = self.useFixture(temporaryfile.SecureTempFile())
self.policy_file_name = self.policy_file.file_name
self.useFixture(
ksfixtures.Policy(
self.config_fixture, policy_file=self.policy_file_name
)
)
self._override_policy()
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_admin = unit.new_user_ref(domain_id=self.domain_id)
self.user_id = PROVIDERS.identity_api.create_user(domain_admin)['id']
PROVIDERS.assignment_api.create_grant(
self.bootstrapper.admin_role_id, user_id=self.user_id,
domain_id=self.domain_id
)
auth = self.build_authentication_request(
user_id=self.user_id,
password=domain_admin['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}
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=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/users/%s/roles/%s' % (
project['id'], user['id'], self.bootstrapper.reader_role_id
),
headers=self.headers
)
def test_user_can_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
)
def test_user_can_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
)
def test_user_can_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=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
)
def test_user_cannot_revoke_grant_from_group_on_domain(self):
group = PROVIDERS.identity_api.create_group(
unit.new_group_ref(domain_id=CONF.identity.default_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
)

View File

@ -0,0 +1,39 @@
---
features:
- |
[`bug 1805368 <https://bugs.launchpad.net/keystone/+bug/1805368>`_]
[`bug 1750669 <https://bugs.launchpad.net/keystone/+bug/1750669>`_]
The grant API now supports the ``admin``, ``member``, and ``reader``
default roles for domain users (e.g., domain-scoped tokens).
upgrade:
- |
[`bug 1805368 <https://bugs.launchpad.net/keystone/+bug/1805368>`_]
[`bug 1750669 <https://bugs.launchpad.net/keystone/+bug/1750669>`_]
The grant APIs use new default policies that make it more accessible to
domain users in a safe and secure way. Please consider these new defaults
if your deployment overrides the grant APIs.
deprecations:
- |
[`bug 1805368 <https://bugs.launchpad.net/keystone/+bug/1805368>`_]
[`bug 1750669 <https://bugs.launchpad.net/keystone/+bug/1750669>`_]
The grant policies have been deprecated and replaced with new policies that
expose grant APIs to domain users. This allows deployments to delegate more
functionality to domain owners by default. The ``identity:check_grant`` and
``identity:list_grants`` policies now use ``(role:reader and
system_scope:all) or (role:reader and domain_id:%(target.user.domain_id)s)
or (role:reader and domain_id:%(target.group.domain_id)s)`` instead of
``role:reader and system_scope:all``. The ``identity:create_grant`` and
``identity:revoke_grant`` policies now use ``(role:admin and
system_scope:all) or (role:admin and domain_id:%(target.user.domain_id)s)
or (role:admin and domain_id:%(target.group.domain_id)s)`` instead of
``role:admin and system_scope:all``. These new defaults automatically
include support for domain reader and domain administrator roles, making it
easier for system administrator to delegate functionality down to domain
users to manage grants within their domains. Please consider these new
defaults if your deployment overrides the grant APIs.
security:
- |
[`bug 1805368 <https://bugs.launchpad.net/keystone/+bug/1805368>`_]
[`bug 1750669 <https://bugs.launchpad.net/keystone/+bug/1750669>`_]
The grant API now supports domain-scoped default roles to provide better
accessbility grants for domain users.