From 3fb363dc8331f1970e62d139d33da3f51f607ebe Mon Sep 17 00:00:00 2001 From: Boris Bobrov Date: Mon, 17 Apr 2017 00:28:07 +0300 Subject: [PATCH] Do not fetch group assignments without groups Without the change, the method fetched all assignments for a project or domain, regardless of who has the assignment, user or group. This led to situation when federated user without groups could scope a token with other user's rules. Return empty list of assignments if no groups were passed. Closes-Bug: 1677723 Change-Id: I65f5be915bef2f979e70b043bde27064e970349d (cherry picked from commit d61fc5b707a5209104b194d84e22eede84efccb3) --- keystone/assignment/core.py | 5 +++ keystone/tests/unit/test_v3_federation.py | 58 +++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/keystone/assignment/core.py b/keystone/assignment/core.py index eccc22d..8fba77e 100644 --- a/keystone/assignment/core.py +++ b/keystone/assignment/core.py @@ -126,6 +126,11 @@ class Manager(manager.Manager): def get_roles_for_groups(self, group_ids, project_id=None, domain_id=None): """Get a list of roles for this group on domain and/or project.""" + # if no group ids were passed, there are no roles. Without this check, + # all assignments for the project or domain will be fetched, + # which is not what we want. + if not group_ids: + return [] if project_id is not None: self.resource_api.get_project(project_id) assignment_list = self.list_role_assignments( diff --git a/keystone/tests/unit/test_v3_federation.py b/keystone/tests/unit/test_v3_federation.py index 0f5148f..03509b8 100644 --- a/keystone/tests/unit/test_v3_federation.py +++ b/keystone/tests/unit/test_v3_federation.py @@ -1908,6 +1908,34 @@ class FederatedTokenTests(test_v3.RestfulTestCase, FederatedSetupMixin): token_groups = token_resp['token']['user']['OS-FEDERATION']['groups'] self.assertEqual(0, len(token_groups)) + def test_issue_scoped_token_no_groups(self): + """Verify that token without groups cannot get scoped to project. + + This test is required because of bug 1677723. + """ + # issue unscoped token with no groups + r = self._issue_unscoped_token(assertion='USER_NO_GROUPS_ASSERTION') + self.assertIsNotNone(r.headers.get('X-Subject-Token')) + token_resp = r.json_body + token_groups = token_resp['token']['user']['OS-FEDERATION']['groups'] + self.assertEqual(0, len(token_groups)) + unscoped_token = r.headers.get('X-Subject-Token') + + # let admin get roles in a project + self.proj_employees + admin = unit.new_user_ref(CONF.identity.default_domain_id) + self.identity_api.create_user(admin) + self.assignment_api.create_grant(self.role_admin['id'], + user_id=admin['id'], + project_id=self.proj_employees['id']) + + # try to scope the token. It should fail + scope = self._scope_request( + unscoped_token, 'project', self.proj_employees['id'] + ) + self.v3_create_token( + scope, expected_status=http_client.UNAUTHORIZED) + def test_issue_unscoped_token_malformed_environment(self): """Test whether non string objects are filtered out. @@ -3319,6 +3347,36 @@ class ShadowMappingTests(test_v3.RestfulTestCase, FederatedSetupMixin): self.expected_results[project_name], roles[0]['name'] ) + def test_user_gets_only_assigned_roles(self): + # in bug 1677723 user could get roles outside of what was assigned + # to them. This test verifies that this is no longer true. + # Authenticate once to create the projects + response = self._issue_unscoped_token() + self.assertValidMappedUser(response.json_body['token']) + unscoped_token = response.headers.get('X-Subject-Token') + + # Assign admin role to newly-created project to another user + staging_project = self.resource_api.get_project_by_name( + 'Staging', self.idp['domain_id'] + ) + admin = unit.new_user_ref(CONF.identity.default_domain_id) + self.identity_api.create_user(admin) + self.assignment_api.create_grant(self.role_admin['id'], + user_id=admin['id'], + project_id=staging_project['id']) + + # Authenticate again with the federated user and verify roles + response = self._issue_unscoped_token() + self.assertValidMappedUser(response.json_body['token']) + unscoped_token = response.headers.get('X-Subject-Token') + scope = self._scope_request( + unscoped_token, 'project', staging_project['id'] + ) + response = self.v3_create_token(scope) + roles = response.json_body['token']['roles'] + role_ids = [r['id'] for r in roles] + self.assertNotIn(self.role_admin['id'], role_ids) + class JsonHomeTests(test_v3.RestfulTestCase, test_v3.JsonHomeTestMixin): JSON_HOME_DATA = { -- 2.1.4