Allow project users to retrieve domains
This commit adds thorough testing to make sure users who have a role on a project can use project-scoped tokens to call GET /v3/domain/{domain_id} for the domain own their project. These users are not allowed to access domains that they don't have any authorization via project role assignments. This ensures the domains API is tested with these cases and makes the domains API more self-serviceable for users that are not administrators. Change-Id: Ifc100a7a235140fbd07cbafe80983d3c2f17a7dc Closes-Bug: 1794864 Related-Bug: 968696
This commit is contained in:
parent
2c47e935fa
commit
2c8f81af62
@ -43,17 +43,19 @@ deprecated_delete_domain = policy.DeprecatedRule(
|
||||
name=base.IDENTITY % 'delete_domain',
|
||||
check_str=base.RULE_ADMIN_REQUIRED
|
||||
)
|
||||
SYSTEM_USER_OR_DOMAIN_USER_OR_PROJECT_USER = (
|
||||
'(role:reader and system_scope:all) or '
|
||||
'token.domain.id:%(target.domain.id)s or '
|
||||
'token.project.domain.id:%(target.domain.id)s'
|
||||
)
|
||||
|
||||
|
||||
domain_policies = [
|
||||
policy.DocumentedRuleDefault(
|
||||
name=base.IDENTITY % 'get_domain',
|
||||
# NOTE(lbragstad): This policy allows system, domain, and
|
||||
# project-scoped tokens.
|
||||
check_str=(
|
||||
'(role:reader and system_scope:all) or '
|
||||
'token.domain.id:%(target.domain.id)s or '
|
||||
'token.project.domain.id:%(target.domain.id)s'
|
||||
),
|
||||
check_str=SYSTEM_USER_OR_DOMAIN_USER_OR_PROJECT_USER,
|
||||
scope_types=['system', 'domain', 'project'],
|
||||
description='Show domain details.',
|
||||
operations=[{'path': '/v3/domains/{domain_id}',
|
||||
|
@ -12,14 +12,17 @@
|
||||
|
||||
import uuid
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
from six.moves import http_client
|
||||
|
||||
from keystone.common.policies import domain as dp
|
||||
from keystone.common import provider_api
|
||||
import keystone.conf
|
||||
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
|
||||
@ -384,3 +387,156 @@ class DomainUserTests(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 ProjectReaderTests(base_classes.TestCaseWithBootstrap,
|
||||
common_auth.AuthTestMixin,
|
||||
_DomainAndProjectUserDomainTests):
|
||||
|
||||
def setUp(self):
|
||||
super(ProjectReaderTests, 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']
|
||||
|
||||
project_reader = unit.new_user_ref(domain_id=self.domain_id)
|
||||
project_reader_id = PROVIDERS.identity_api.create_user(
|
||||
project_reader
|
||||
)['id']
|
||||
project = unit.new_project_ref(domain_id=self.domain_id)
|
||||
project_id = PROVIDERS.resource_api.create_project(
|
||||
project['id'], project
|
||||
)['id']
|
||||
|
||||
PROVIDERS.assignment_api.create_grant(
|
||||
self.bootstrapper.reader_role_id, user_id=project_reader_id,
|
||||
project_id=project_id
|
||||
)
|
||||
|
||||
auth = self.build_authentication_request(
|
||||
user_id=project_reader_id,
|
||||
password=project_reader['password'],
|
||||
project_id=project_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 ProjectMemberTests(base_classes.TestCaseWithBootstrap,
|
||||
common_auth.AuthTestMixin,
|
||||
_DomainAndProjectUserDomainTests):
|
||||
|
||||
def setUp(self):
|
||||
super(ProjectMemberTests, 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']
|
||||
|
||||
project_member = unit.new_user_ref(domain_id=self.domain_id)
|
||||
project_member_id = PROVIDERS.identity_api.create_user(
|
||||
project_member
|
||||
)['id']
|
||||
project = unit.new_project_ref(domain_id=self.domain_id)
|
||||
project_id = PROVIDERS.resource_api.create_project(
|
||||
project['id'], project
|
||||
)['id']
|
||||
|
||||
PROVIDERS.assignment_api.create_grant(
|
||||
self.bootstrapper.member_role_id, user_id=project_member_id,
|
||||
project_id=project_id
|
||||
)
|
||||
|
||||
auth = self.build_authentication_request(
|
||||
user_id=project_member_id,
|
||||
password=project_member['password'],
|
||||
project_id=project_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 ProjectAdminTests(base_classes.TestCaseWithBootstrap,
|
||||
common_auth.AuthTestMixin,
|
||||
_DomainAndProjectUserDomainTests):
|
||||
|
||||
def setUp(self):
|
||||
super(ProjectAdminTests, 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']
|
||||
|
||||
project_admin = unit.new_user_ref(domain_id=self.domain_id)
|
||||
project_admin_id = PROVIDERS.identity_api.create_user(
|
||||
project_admin
|
||||
)['id']
|
||||
project = unit.new_project_ref(domain_id=self.domain_id)
|
||||
project_id = PROVIDERS.resource_api.create_project(
|
||||
project['id'], project
|
||||
)['id']
|
||||
|
||||
PROVIDERS.assignment_api.create_grant(
|
||||
self.bootstrapper.admin_role_id, user_id=project_admin_id,
|
||||
project_id=project_id
|
||||
)
|
||||
|
||||
auth = self.build_authentication_request(
|
||||
user_id=project_admin_id,
|
||||
password=project_admin['password'],
|
||||
project_id=project_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.domains 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:get_domain': (
|
||||
dp.SYSTEM_USER_OR_DOMAIN_USER_OR_PROJECT_USER
|
||||
)
|
||||
}
|
||||
f.write(jsonutils.dumps(overridden_policies))
|
||||
|
41
releasenotes/notes/bug-1794864-3116bf165a146be6.yaml
Normal file
41
releasenotes/notes/bug-1794864-3116bf165a146be6.yaml
Normal file
@ -0,0 +1,41 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
[`bug 1794864 <https://bugs.launchpad.net/keystone/+bug/1794864>`_]
|
||||
[`bug 1794376 <https://bugs.launchpad.net/keystone/+bug/1794376>`_]
|
||||
The default policies that protect the domains API have been deprecated in
|
||||
favor of ones that are more secure and self-serviceable. If you're
|
||||
maintaining custom policies, please make sure you resolve your domain
|
||||
policies to work with the new default by adding the proper role
|
||||
assignments, or continue maintaining custom overrides. The new defaults
|
||||
allow for better protection of the domains API when giving the `admin` role
|
||||
to users on domains and projects.
|
||||
deprecations:
|
||||
- |
|
||||
[`bug 1794864 <https://bugs.launchpad.net/keystone/+bug/1794864>`_]
|
||||
[`bug 1794376 <https://bugs.launchpad.net/keystone/+bug/1794376>`_]
|
||||
The default policies that protect the domains API have been deprecated in
|
||||
favor of ones that are more secure and self-serviceable. If you're
|
||||
maintaining custom policies, please make sure you resolve your domain
|
||||
policies to work with the new default by adding the proper role
|
||||
assignments, or continue maintaining custom overrides. The new defaults
|
||||
allow for better protection of the domains API when giving the `admin` role
|
||||
to users on domains and projects.
|
||||
security:
|
||||
- |
|
||||
[`bug 1794864 <https://bugs.launchpad.net/keystone/+bug/1794864>`_]
|
||||
[`bug 1794376 <https://bugs.launchpad.net/keystone/+bug/1794376>`_]
|
||||
The default policies that protect the domains API have been deprecated in
|
||||
favor of ones that are more secure and self-serviceable.
|
||||
fixes:
|
||||
- |
|
||||
[`bug 1794864 <https://bugs.launchpad.net/keystone/+bug/1794864>`_]
|
||||
[`bug 1794376 <https://bugs.launchpad.net/keystone/+bug/1794376>`_]
|
||||
The default policies that protect the domains API have been deprecated in
|
||||
favor of ones that are more secure and self-serviceable. Users with roles
|
||||
on domains and projects are now able to call the
|
||||
``GET /v3/domains/{domain_id}`` API if they use a token scoped to that
|
||||
domain or a token scoped to a project within that domain. System users are
|
||||
allowed to access the domain APIs in the same way legacy `admin` users were
|
||||
able to. This allows for better protection of the domain API when giving
|
||||
the `admin` role to users on domains and projects.
|
Loading…
Reference in New Issue
Block a user