From a226a3d8be5ba720f149606a84df0432ec4858c7 Mon Sep 17 00:00:00 2001 From: Lance Bragstad Date: Tue, 13 Feb 2018 16:52:57 +0000 Subject: [PATCH] Expose bug in /role_assignments API with system-scope The role_assignment API supports a bunch of query parameters that gives users flexibility when querying for role assignments. This commit exposes an issue when querying keystone for a specific role using /role_assignments?role.id={role_id}. The expected result was that the returned list would only contain role assignments for that specific role ID. The actual result is a set of role assignments with that role ID and all system role assignments. This caused issues in tempest because tempest goes through and cleans up resources using `tearDownClass`, and it is common to remove specific roles used in the test class. The problem is that keystone queries the role assignment API for all role assignment with a specific role ID, which is the equivalent to `GET /v3/role_assignments?role.id={role_id}` when deleting a role. The list returned included false positives, which were system role assignments, resulting in revocation events getting persisted for users in those role assignments. This prevented the administrator in tempest from cleaning up the rest of the resources because the revocation event would make the token being used to do resource cleanup. This commit exposes the bug using tests. Change-Id: If93400be3c9d3fe8e266bb36c16accca93d77154 Partial-Bug: 1748970 --- keystone/tests/unit/test_v3_assignment.py | 57 +++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/keystone/tests/unit/test_v3_assignment.py b/keystone/tests/unit/test_v3_assignment.py index 416c310151..75b0d617e2 100644 --- a/keystone/tests/unit/test_v3_assignment.py +++ b/keystone/tests/unit/test_v3_assignment.py @@ -24,6 +24,7 @@ import keystone.conf from keystone import exception from keystone.tests import unit from keystone.tests.unit import test_v3 +from keystone.tests.unit import utils as test_utils CONF = keystone.conf.CONF @@ -3568,6 +3569,29 @@ class UserSystemRoleAssignmentTestCase(test_v3.RestfulTestCase, ) % {'project_id': self.project_id} self.get(path, expected_status=http_client.BAD_REQUEST) + @test_utils.wip("Waiting on fix for bug #1748970") + def test_query_for_role_id_does_not_return_system_user_roles(self): + system_role_id = self._create_new_role() + + # assign the user a role on the system + member_url = '/system/users/%(user_id)s/roles/%(role_id)s' % { + 'user_id': self.user['id'], + 'role_id': system_role_id + } + self.put(member_url) + + # The user has a role on the system and on a project, but self.role_id + # is only given to the user on the project. If we ask for role + # assignments matching that role for that specific user, we should only + # get one back. Instead, we get two back because the role assignment + # API isn't filtering out system role assignments when queried for a + # specific role. + path = ( + '/role_assignments?role.id=%(role_id)s&user.id=%(user_id)s' + ) % {'role_id': self.role_id, 'user_id': self.user['id']} + response = self.get(path) + self.assertValidRoleAssignmentListResponse(response, expected_length=1) + # FIXME(lbragstad): These tests contain system-level API calls, which means # they will log a warning message if they are called with a project-scoped @@ -3837,3 +3861,36 @@ class GroupSystemRoleAssignmentTestCase(test_v3.RestfulTestCase, } ) self.assertValidRoleAssignmentListResponse(response, expected_length=0) + + @test_utils.wip("Waiting on fix for bug #1748970") + def test_query_for_role_id_does_not_return_system_group_roles(self): + system_role_id = self._create_new_role() + group = self._create_group() + + # assign the group a role on the system + member_url = '/system/groups/%(group_id)s/roles/%(role_id)s' % { + 'group_id': group['id'], + 'role_id': system_role_id + } + self.put(member_url) + + # assign the group a role on the system + member_url = ( + '/projects/%(project_id)s/groups/%(group_id)s/roles/%(role_id)s' % + {'project_id': self.project_id, + 'group_id': group['id'], + 'role_id': self.role_id} + ) + self.put(member_url) + + # The group has a role on the system and on a project, but self.role_id + # is only given to the group on the project. If we ask for role + # assignments matching that role for that specific group, we should + # only get one back. Instead, we get two back because the role + # assignment API isn't filtering out system role assignments when + # queried for a specific role. + path = ( + '/role_assignments?role.id=%(role_id)s&group.id=%(group_id)s' + ) % {'role_id': self.role_id, 'group_id': group['id']} + response = self.get(path) + self.assertValidRoleAssignmentListResponse(response, expected_length=1)