From de083009eb51d1af086387bbac0dca8d3c4474c0 Mon Sep 17 00:00:00 2001 From: Lance Bragstad Date: Wed, 20 Mar 2019 21:58:51 +0000 Subject: [PATCH] Test project users against system assignment API This commit ensures that project users are not able to operate on system role assignments in anyway since they lack the proper authorization to do so. Change-Id: I8b5add170ba0d9eec42f2d088f4b89aa801136df Related-Bug: 1805368 Related-Bug: 1750669 Related-Bug: 1806762 (cherry picked from commit fac844c4ae058c148889b636ab6cbb637df7e554) --- .../protection/v3/test_system_assignments.py | 157 ++++++++++++++++++ .../notes/bug-1750669-dfce859550126f03.yaml | 40 +++++ 2 files changed, 197 insertions(+) create mode 100644 releasenotes/notes/bug-1750669-dfce859550126f03.yaml diff --git a/keystone/tests/unit/protection/v3/test_system_assignments.py b/keystone/tests/unit/protection/v3/test_system_assignments.py index c5b61187de..60c75a088f 100644 --- a/keystone/tests/unit/protection/v3/test_system_assignments.py +++ b/keystone/tests/unit/protection/v3/test_system_assignments.py @@ -12,14 +12,17 @@ import uuid +from oslo_serialization import jsonutils from six.moves import http_client +from keystone.common.policies import base 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 @@ -325,3 +328,157 @@ 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, + _DomainAndProjectUserSystemAssignmentTests): + + 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, + _DomainAndProjectUserSystemAssignmentTests): + + 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, + _DomainAndProjectUserSystemAssignmentTests): + + 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.grants 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:check_system_grant_for_user': base.SYSTEM_READER, + 'identity:list_system_grants_for_user': base.SYSTEM_READER, + 'identity:create_system_grant_for_user': base.SYSTEM_ADMIN, + 'identity:revoke_system_grant_for_user': base.SYSTEM_ADMIN + } + f.write(jsonutils.dumps(overridden_policies)) diff --git a/releasenotes/notes/bug-1750669-dfce859550126f03.yaml b/releasenotes/notes/bug-1750669-dfce859550126f03.yaml new file mode 100644 index 0000000000..a5aed56ce1 --- /dev/null +++ b/releasenotes/notes/bug-1750669-dfce859550126f03.yaml @@ -0,0 +1,40 @@ +--- +features: + - | + [`bug 1805368 `_] + [`bug 1750669 `_] + The system assignment API now supports the ``admin``, ``member``, + and ``reader`` default roles across system-scope, domain-scope, + and project-scope. +upgrade: + - | + [`bug 1805368 `_] + [`bug 1750669 `_] + The system assignment API uses new default policies that make it more + accessible to end users and administrators in a secure way. Please + consider these new defaults if your deployment overrides system + assignment policies. +deprecations: + - | + [`bug 1805368 `_] + [`bug 1750669 `_] + The system assignment policies have been deprecated. The + ``identity:list_system_grants_for_user`` and + ``identity:check_system_grant_for_user`` policies now use + ``role:reader and system_scope:all`` instead of + ``rule:admin_required``. The + ``identity:create_system_grant_for_user`` and + ``identity:revoke_system_grant_for_user`` policies now use + ``role:admin and system_scope:all`` instead of + ``rule:admin_required``. These new defaults automatically include + support for a read-only role and allow for more granular access to + the system assignment API, making it easier for administrators to + delegate authorization, safely. Please consider these new defaults + if your deployment overrides the system assignment APIs. +security: + - | + [`bug 1805368 `_] + [`bug 1750669 `_] + The system assignment API now uses system-scope, domain-scope, + project-scope, and default roles to provide better accessibility + to users in a secure way.