diff options
author | Colleen Murphy <colleen.murphy@suse.de> | 2019-12-04 10:51:05 -0800 |
---|---|---|
committer | Colleen Murphy <colleen.murphy@suse.de> | 2019-12-06 14:25:23 -0800 |
commit | 17947516b0095c51da5cff94771247f2e7c44ee6 (patch) | |
tree | 94621880f4b98c891b87c11014795418db74bcf1 | |
parent | 7a81c84e2fbd79522f695827dd80e7120b38def7 (diff) | |
download | keystone-17947516b0095c51da5cff94771247f2e7c44ee6.tar.gz |
Fix credential list for project members
Without this patch, project members and readers can list any credentials
with the /v3/credentials API when enforce_scope is false. enforce_scope
is only applicable to project admins due to the admin-ness problem[1],
and this policy is not meant to allow project admins any access to users'
credentials (only system admins should be able to access them). However,
when enforce_scope is false, we need to preserve the old behavior of
project admins being able to list all credentials. This change mitigates
the problem by running the identity:get_credential policy check to
filter out credentials the user does not have access to. This will
impact performance.
Closes-bug: #1855080
[1] https://bugs.launchpad.net/keystone/+bug/968696
Change-Id: I5dd85a6b8368373a27aef2942a64499d020662ef
(cherry picked from commit 17c337dbdbfb9d548ad531c2ad0483c9bce5b98f)
(cherry picked from commit bd3f63787151183f4daa43578aa491856fefae5b)
-rw-r--r-- | keystone/api/credentials.py | 23 | ||||
-rw-r--r-- | keystone/tests/unit/protection/v3/test_credentials.py | 112 | ||||
-rw-r--r-- | releasenotes/notes/bug-1855080-08b28181b7cb2470.yaml | 23 |
3 files changed, 151 insertions, 7 deletions
diff --git a/keystone/api/credentials.py b/keystone/api/credentials.py index 9487f1914..08a492c1d 100644 --- a/keystone/api/credentials.py +++ b/keystone/api/credentials.py @@ -101,13 +101,22 @@ class CredentialResource(ks_flask.ResourceBase): # If the request was filtered, make sure to return only the # credentials specific to that user. This makes it so that users with # roles on projects can't see credentials that aren't theirs. - if (not self.oslo_context.system_scope and - CONF.oslo_policy.enforce_scope): - filtered_refs = [] - for ref in refs: - if ref['user_id'] == target['credential']['user_id']: - filtered_refs.append(ref) - refs = filtered_refs + filtered_refs = [] + for ref in refs: + # Check each credential again to make sure the user has access to + # it, either by owning it, being a project admin with + # enforce_scope=false, being a system user, or having some other + # custom policy that allows access. + try: + cred = PROVIDERS.credential_api.get_credential(ref['id']) + ENFORCER.enforce_call( + action='identity:get_credential', + target_attr={'credential': cred} + ) + filtered_refs.append(ref) + except exception.Forbidden: + pass + refs = filtered_refs refs = [self._blob_to_json(r) for r in refs] return self.wrap_collection(refs, hints=hints) diff --git a/keystone/tests/unit/protection/v3/test_credentials.py b/keystone/tests/unit/protection/v3/test_credentials.py index b681e7ee5..695e76526 100644 --- a/keystone/tests/unit/protection/v3/test_credentials.py +++ b/keystone/tests/unit/protection/v3/test_credentials.py @@ -1138,3 +1138,115 @@ class ProjectAdminTests(base_classes.TestCaseWithBootstrap, 'identity:delete_credential': cp.SYSTEM_ADMIN_OR_CRED_OWNER } f.write(jsonutils.dumps(overridden_policies)) + + +class ProjectReaderTestsEnforceScopeFalse(base_classes.TestCaseWithBootstrap, + common_auth.AuthTestMixin, + _UserCredentialTests, + _ProjectUsersTests): + + def setUp(self): + super(ProjectReaderTestsEnforceScopeFalse, self).setUp() + self.loadapp() + self.useFixture(ksfixtures.Policy(self.config_fixture)) + self.config_fixture.config(group='oslo_policy', enforce_scope=False) + + project_reader = unit.new_user_ref( + domain_id=CONF.identity.default_domain_id + ) + self.user_id = PROVIDERS.identity_api.create_user( + project_reader + )['id'] + project = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id + ) + self.project_id = PROVIDERS.resource_api.create_project( + project['id'], project + )['id'] + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.reader_role_id, user_id=self.user_id, + project_id=self.project_id + ) + + auth = self.build_authentication_request( + user_id=self.user_id, + password=project_reader['password'], + project_id=self.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 ProjectMemberTestsEnforceScopeFalse(base_classes.TestCaseWithBootstrap, + common_auth.AuthTestMixin, + _UserCredentialTests, + _ProjectUsersTests): + + def setUp(self): + super(ProjectMemberTestsEnforceScopeFalse, self).setUp() + self.loadapp() + self.useFixture(ksfixtures.Policy(self.config_fixture)) + self.config_fixture.config(group='oslo_policy', enforce_scope=False) + + project_member = unit.new_user_ref( + domain_id=CONF.identity.default_domain_id + ) + self.user_id = PROVIDERS.identity_api.create_user( + project_member + )['id'] + project = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id + ) + self.project_id = PROVIDERS.resource_api.create_project( + project['id'], project + )['id'] + PROVIDERS.assignment_api.create_grant( + self.bootstrapper.member_role_id, user_id=self.user_id, + project_id=self.project_id + ) + + auth = self.build_authentication_request( + user_id=self.user_id, + password=project_member['password'], + project_id=self.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 ProjectAdminTestsEnforceScopeFalse(base_classes.TestCaseWithBootstrap, + common_auth.AuthTestMixin, + _UserCredentialTests, + _SystemUserCredentialTests): + + def setUp(self): + super(ProjectAdminTestsEnforceScopeFalse, self).setUp() + self.loadapp() + self.useFixture(ksfixtures.Policy(self.config_fixture)) + self.config_fixture.config(group='oslo_policy', enforce_scope=False) + + # Reuse the system administrator account created during + # ``keystone-manage bootstrap`` + self.user_id = self.bootstrapper.admin_user_id + auth = self.build_authentication_request( + user_id=self.user_id, + password=self.bootstrapper.admin_password, + project_id=self.bootstrapper.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} diff --git a/releasenotes/notes/bug-1855080-08b28181b7cb2470.yaml b/releasenotes/notes/bug-1855080-08b28181b7cb2470.yaml new file mode 100644 index 000000000..9e47134ac --- /dev/null +++ b/releasenotes/notes/bug-1855080-08b28181b7cb2470.yaml @@ -0,0 +1,23 @@ +--- +critical: + - | + [`bug 1855080 <https://bugs.launchpad.net/keystone/+bug/1855080>`_] + An error in the policy target filtering inadvertently allowed any user to + list any credential object with the /v3/credentials API when + ``[oslo_policy]/enforce_scope`` was set to false, which is the default. + This has been addressed: users with non-admin roles on a project may not + list other users' credentials. However, users with the admin role on a + project may still list any users credentials when + ``[oslo_policy]/enforce_scope`` is false due to `bug 968696 + <https://bugs.launchpad.net/keystone/+bug/968696>`_. +security: + - | + [`bug 1855080 <https://bugs.launchpad.net/keystone/+bug/1855080>`_] + An error in the policy target filtering inadvertently allowed any user to + list any credential object with the /v3/credentials API when + ``[oslo_policy]/enforce_scope`` was set to false, which is the default. + This has been addressed: users with non-admin roles on a project may not + list other users' credentials. However, users with the admin role on a + project may still list any users credentials when + ``[oslo_policy]/enforce_scope`` is false due to `bug 968696 + <https://bugs.launchpad.net/keystone/+bug/968696>`_. |