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
(cherry picked from commit a226a3d8be)
This commit is contained in:
Lance Bragstad 2018-02-13 16:52:57 +00:00
parent 1365916701
commit 752d299d58
1 changed files with 57 additions and 0 deletions

View File

@ -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)