From 00597be4cca64b9aa691d6a135698f09af455cd7 Mon Sep 17 00:00:00 2001 From: Alexey Miroshkin Date: Mon, 11 Aug 2014 15:39:17 +0400 Subject: [PATCH] Enable filtering of credentials by user ID A credentials entity has a user_id attribute. Currently the lack of a filter of user_id means that we cannot use the keystone policy file to enable users to have access to (only) their credentials. This fix solves it by adding such a filter: List credentials: `GET /credentials` Optional query parameters: - `user_id` (string) Implements: blueprint filter-credentials-by-user Closes-Bug: #1267096 Change-Id: Iff016fac37b50d55d77ec7511aae4e57af34f08f --- etc/policy.v3cloudsample.json | 2 +- keystone/credential/controllers.py | 13 +++++-------- keystone/tests/test_v3_credential.py | 12 ++++++++++++ keystone/tests/test_v3_protection.py | 21 +++++++++++++++++++++ 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/etc/policy.v3cloudsample.json b/etc/policy.v3cloudsample.json index b9f46a4bbf..8d9cfb5c31 100644 --- a/etc/policy.v3cloudsample.json +++ b/etc/policy.v3cloudsample.json @@ -67,7 +67,7 @@ "identity:add_user_to_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id", "identity:get_credential": "rule:admin_required", - "identity:list_credentials": "rule:admin_required", + "identity:list_credentials": "rule:admin_required or user_id:%(user_id)s", "identity:create_credential": "rule:admin_required", "identity:update_credential": "rule:admin_required", "identity:delete_credential": "rule:admin_required", diff --git a/keystone/credential/controllers.py b/keystone/credential/controllers.py index c6929b6be5..c15d5a1956 100644 --- a/keystone/credential/controllers.py +++ b/keystone/credential/controllers.py @@ -16,7 +16,6 @@ import hashlib from keystone.common import controller from keystone.common import dependency -from keystone.common import driver_hints from keystone import exception from keystone.i18n import _ from keystone.openstack.common import jsonutils @@ -78,15 +77,13 @@ class CredentialV3(controller.V3Controller): else: return ref - @controller.protected() - def list_credentials(self, context): - # NOTE(henry-nash): Since there are no filters for credentials, we - # shouldn't limit the output, hence we don't pass a hints list into - # the driver. - refs = self.credential_api.list_credentials() + @controller.filterprotected('user_id') + def list_credentials(self, context, filters): + hints = CredentialV3.build_driver_hints(context, filters) + refs = self.credential_api.list_credentials(hints) ret_refs = [self._blob_to_json(r) for r in refs] return CredentialV3.wrap_collection(context, ret_refs, - driver_hints.Hints()) + hints=hints) @controller.protected() def get_credential(self, context, credential_id): diff --git a/keystone/tests/test_v3_credential.py b/keystone/tests/test_v3_credential.py index 66cfa74015..2b50f584db 100644 --- a/keystone/tests/test_v3_credential.py +++ b/keystone/tests/test_v3_credential.py @@ -90,6 +90,18 @@ class CredentialTestCase(CredentialBaseTestCase): r = self.get('/credentials', content_type='xml') self.assertValidCredentialListResponse(r, ref=self.credential) + def test_list_credentials_filtered_by_user_id(self): + """Call ``GET /credentials?user_id={user_id}``.""" + credential = self.new_credential_ref( + user_id=uuid.uuid4().hex) + self.credential_api.create_credential( + credential['id'], credential) + + r = self.get('/credentials?user_id=%s' % self.user['id']) + self.assertValidCredentialListResponse(r, ref=self.credential) + for cred in r.result['credentials']: + self.assertEqual(self.user['id'], cred['user_id']) + def test_create_credential(self): """Call ``POST /credentials``.""" ref = self.new_credential_ref(user_id=self.user['id']) diff --git a/keystone/tests/test_v3_protection.py b/keystone/tests/test_v3_protection.py index b2cebbe895..42307bea56 100644 --- a/keystone/tests/test_v3_protection.py +++ b/keystone/tests/test_v3_protection.py @@ -661,3 +661,24 @@ class IdentityTestv3CloudPolicySample(test_v3.RestfulTestCase): domain_id=self.admin_domain['id']) self._test_domain_management() + + def test_list_user_credentials(self): + self.credential_user = self.new_credential_ref(self.just_a_user['id']) + self.credential_api.create_credential(self.credential_user['id'], + self.credential_user) + self.credential_admin = self.new_credential_ref( + self.cloud_admin_user['id']) + self.credential_api.create_credential(self.credential_admin['id'], + self.credential_admin) + + self.auth = self.build_authentication_request( + user_id=self.just_a_user['id'], + password=self.just_a_user['password']) + url = '/credentials?user_id=%s' % self.just_a_user['id'] + self.get(url, auth=self.auth) + url = '/credentials?user_id=%s' % self.cloud_admin_user['id'] + self.get(url, auth=self.auth, + expected_status=exception.ForbiddenAction.code) + url = '/credentials' + self.get(url, auth=self.auth, + expected_status=exception.ForbiddenAction.code)