Fix role_assignments role.id filter

Without this patch, if there are multiple role assignments on the system
and they are not all the same role, querying for role assignments with
/v3/role_assignments?role.id={role_id} may leak some role assignments
that don't match the role_id, making the returned results incorrect.
This patch fixes the issue by using a list comprehension instead of a
for loop over a list that was being modified within the loop.

Conflicts:
       keystone/tests/unit/protection/v3/test_assignment.py

Protection unit tests do not exist on this branch (stable/rocky) so
there is no need to modify the test_assignment.py protection tests.

Change-Id: Icfce3b14abb55c6fef3de1b314cee22fc8b1d08c
Closes-bug: #1858012
(cherry picked from commit c2d8830662)
(cherry picked from commit 4d413f1eba)
(cherry picked from commit af470fd639)
This commit is contained in:
Colleen Murphy 2019-12-31 16:22:34 -08:00 committed by Colleen Murphy
parent 200dda218d
commit a50a8973d7
4 changed files with 47 additions and 7 deletions

View File

@ -940,9 +940,11 @@ class Manager(manager.Manager):
a['system'] = {'all': True}
system_assignments.append(a)
for i, assignment in enumerate(system_assignments):
if role_id and role_id != assignment['role_id']:
system_assignments.pop(i)
if role_id:
system_assignments = [
sa for sa in system_assignments
if role_id == sa['role_id']
]
assignments = []
for assignment in itertools.chain(

View File

@ -1435,6 +1435,8 @@ class AssignmentTestMixin(object):
"""
if attribs.get('domain_id'):
link = '/domains/' + attribs['domain_id']
elif attribs.get('system'):
link = '/system'
else:
link = '/projects/' + attribs['project_id']
@ -1462,6 +1464,8 @@ class AssignmentTestMixin(object):
if attribs.get('domain_id'):
entity['scope'] = {'domain': {'id': attribs['domain_id']}}
elif attribs.get('system'):
entity['scope'] = {'system': {'all': True}}
else:
entity['scope'] = {'project': {'id': attribs['project_id']}}

View File

@ -931,7 +931,7 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
self.role2 = unit.new_role_ref()
PROVIDERS.role_api.create_role(self.role2['id'], self.role2)
# Now add one of each of the four types of assignment
# Now add one of each of the six types of assignment
gd_entity = self.build_role_assignment_entity(
domain_id=self.domain_id, group_id=group1['id'],
@ -955,6 +955,22 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
role_id=self.role2['id'])
self.put(up_entity['links']['assignment'])
gs_entity = self.build_role_assignment_entity(
system='all',
group_id=group1['id'],
role_id=self.role1['id'])
self.put(gs_entity['links']['assignment'])
us_entity = self.build_role_assignment_entity(
system='all',
user_id=user1['id'],
role_id=self.role2['id'])
self.put(us_entity['links']['assignment'])
us2_entity = self.build_role_assignment_entity(
system='all',
user_id=user2['id'],
role_id=self.role2['id'])
self.put(us2_entity['links']['assignment'])
# Now list by various filters to make sure we get back the right ones
collection_url = ('/role_assignments?scope.project.id=%s' %
@ -981,7 +997,7 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
r = self.get(collection_url, expected_status=http_client.OK)
self.head(collection_url, expected_status=http_client.OK)
self.assertValidRoleAssignmentListResponse(r,
expected_length=2,
expected_length=3,
resource_url=collection_url)
self.assertRoleAssignmentInListResponse(r, up_entity)
self.assertRoleAssignmentInListResponse(r, ud_entity)
@ -990,7 +1006,7 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
r = self.get(collection_url, expected_status=http_client.OK)
self.head(collection_url, expected_status=http_client.OK)
self.assertValidRoleAssignmentListResponse(r,
expected_length=2,
expected_length=3,
resource_url=collection_url)
self.assertRoleAssignmentInListResponse(r, gd_entity)
self.assertRoleAssignmentInListResponse(r, gp_entity)
@ -999,10 +1015,21 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
r = self.get(collection_url, expected_status=http_client.OK)
self.head(collection_url, expected_status=http_client.OK)
self.assertValidRoleAssignmentListResponse(r,
expected_length=2,
expected_length=3,
resource_url=collection_url)
self.assertRoleAssignmentInListResponse(r, gd_entity)
self.assertRoleAssignmentInListResponse(r, gp_entity)
self.assertRoleAssignmentInListResponse(r, gs_entity)
collection_url = '/role_assignments?role.id=%s' % self.role2['id']
r = self.get(collection_url, expected_status=http_client.OK)
self.head(collection_url, expected_status=http_client.OK)
self.assertValidRoleAssignmentListResponse(r,
expected_length=4,
resource_url=collection_url)
self.assertRoleAssignmentInListResponse(r, ud_entity)
self.assertRoleAssignmentInListResponse(r, up_entity)
self.assertRoleAssignmentInListResponse(r, us_entity)
# Let's try combining two filers together....

View File

@ -0,0 +1,7 @@
---
fixes:
- |
[`bug 1858012 <https://bugs.launchpad.net/keystone/+bug/1858012>`_]
Fixes a bug in the /v3/role_assignments filtering where the `role.id` query
parameter didn't properly filter role assignments by role in cases where
there were multiple system role assignments.