Fix domain federation tokens for inherited roles.
Currently domain-scoped federation-generated tokens incorrectly include group roles that are inherited to projects within that domain. This error is also exposed via the /auth/domains and /OS-FEDERATION/domains API calls. This patch fixes this. Change-Id: I2b5c1e3d695dd7b27bf3b15361fccb5c13bdd554 Closes-bug: 1385533 Closes-bug: 1385643
This commit is contained in:
parent
4bb8d28b40
commit
1f54bebe65
|
@ -14,6 +14,7 @@
|
|||
|
||||
import six
|
||||
import sqlalchemy
|
||||
from sqlalchemy.sql.expression import false
|
||||
|
||||
from keystone import assignment as keystone_assignment
|
||||
from keystone import clean
|
||||
|
@ -325,6 +326,7 @@ class Assignment(keystone_assignment.Driver):
|
|||
sql_constraints = sqlalchemy.and_(
|
||||
RoleAssignment.type == assignment_type,
|
||||
RoleAssignment.target_id == target_id,
|
||||
RoleAssignment.inherited == false(),
|
||||
Role.id == RoleAssignment.role_id,
|
||||
RoleAssignment.actor_id.in_(group_ids))
|
||||
|
||||
|
@ -364,6 +366,7 @@ class Assignment(keystone_assignment.Driver):
|
|||
|
||||
group_sql_conditions = sqlalchemy.and_(
|
||||
RoleAssignment.type == assignment_type,
|
||||
RoleAssignment.inherited == false(),
|
||||
entity.id == RoleAssignment.target_id,
|
||||
RoleAssignment.actor_id.in_(group_ids))
|
||||
|
||||
|
|
|
@ -3041,6 +3041,103 @@ class IdentityTests(object):
|
|||
self.assertThat(member_assignments,
|
||||
matchers.Equals(orig_member_assignments))
|
||||
|
||||
def test_get_roles_for_groups_on_domain(self):
|
||||
"""Test retrieving group domain roles.
|
||||
|
||||
Test Plan:
|
||||
|
||||
- Create a domain, three groups and three roles
|
||||
- Assign one an inherited and the others a non-inherited group role
|
||||
to the domain
|
||||
- Ensure that only the non-inherited roles are returned on the domain
|
||||
|
||||
"""
|
||||
domain1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
|
||||
self.assignment_api.create_domain(domain1['id'], domain1)
|
||||
group_list = []
|
||||
group_id_list = []
|
||||
role_list = []
|
||||
for _ in range(3):
|
||||
group = {'name': uuid.uuid4().hex, 'domain_id': domain1['id']}
|
||||
group = self.identity_api.create_group(group)
|
||||
group_list.append(group)
|
||||
group_id_list.append(group['id'])
|
||||
|
||||
role = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
|
||||
self.assignment_api.create_role(role['id'], role)
|
||||
role_list.append(role)
|
||||
|
||||
# Assign the roles - one is inherited
|
||||
self.assignment_api.create_grant(group_id=group_list[0]['id'],
|
||||
domain_id=domain1['id'],
|
||||
role_id=role_list[0]['id'])
|
||||
self.assignment_api.create_grant(group_id=group_list[1]['id'],
|
||||
domain_id=domain1['id'],
|
||||
role_id=role_list[1]['id'])
|
||||
self.assignment_api.create_grant(group_id=group_list[2]['id'],
|
||||
domain_id=domain1['id'],
|
||||
role_id=role_list[2]['id'],
|
||||
inherited_to_projects=True)
|
||||
|
||||
# Now get the effective roles for the groups on the domain project. We
|
||||
# shouldn't get back the inherited role.
|
||||
|
||||
role_refs = self.assignment_api.get_roles_for_groups(
|
||||
group_id_list, domain_id=domain1['id'])
|
||||
|
||||
self.assertThat(role_refs, matchers.HasLength(2))
|
||||
self.assertIn(role_list[0], role_refs)
|
||||
self.assertIn(role_list[1], role_refs)
|
||||
|
||||
def test_list_domains_for_groups(self):
|
||||
"""Test retrieving domains for a list of groups.
|
||||
|
||||
Test Plan:
|
||||
|
||||
- Create three domains, three groups and one role
|
||||
- Assign a non-inherited group role to two domains, and an inherited
|
||||
group role to the third
|
||||
- Ensure only the domains with non-inherited roles are returned
|
||||
|
||||
"""
|
||||
domain_list = []
|
||||
group_list = []
|
||||
group_id_list = []
|
||||
for _ in range(3):
|
||||
domain = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
|
||||
self.assignment_api.create_domain(domain['id'], domain)
|
||||
domain_list.append(domain)
|
||||
|
||||
group = {'name': uuid.uuid4().hex, 'domain_id': domain['id']}
|
||||
group = self.identity_api.create_group(group)
|
||||
group_list.append(group)
|
||||
group_id_list.append(group['id'])
|
||||
|
||||
role1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
|
||||
self.assignment_api.create_role(role1['id'], role1)
|
||||
|
||||
# Assign the roles - one is inherited
|
||||
self.assignment_api.create_grant(group_id=group_list[0]['id'],
|
||||
domain_id=domain_list[0]['id'],
|
||||
role_id=role1['id'])
|
||||
self.assignment_api.create_grant(group_id=group_list[1]['id'],
|
||||
domain_id=domain_list[1]['id'],
|
||||
role_id=role1['id'])
|
||||
self.assignment_api.create_grant(group_id=group_list[2]['id'],
|
||||
domain_id=domain_list[2]['id'],
|
||||
role_id=role1['id'],
|
||||
inherited_to_projects=True)
|
||||
|
||||
# Now list the domains that have roles for any of the 3 groups
|
||||
# We shouldn't get back domain[2] since that had an inherited role.
|
||||
|
||||
domain_refs = (
|
||||
self.assignment_api.list_domains_for_groups(group_id_list))
|
||||
|
||||
self.assertThat(domain_refs, matchers.HasLength(2))
|
||||
self.assertIn(domain_list[0], domain_refs)
|
||||
self.assertIn(domain_list[1], domain_refs)
|
||||
|
||||
|
||||
class TokenTests(object):
|
||||
def _create_token_id(self):
|
||||
|
|
|
@ -409,6 +409,12 @@ class BaseLDAPIdentity(test_backend.IdentityTests):
|
|||
def test_get_roles_for_user_and_domain(self):
|
||||
self.skipTest('N/A: LDAP does not support multiple domains')
|
||||
|
||||
def test_get_roles_for_groups_on_domain(self):
|
||||
self.skipTest('Blocked by bug: 1390125')
|
||||
|
||||
def test_list_domains_for_groups(self):
|
||||
self.skipTest('N/A: LDAP does not support multiple domains')
|
||||
|
||||
def test_list_role_assignments_unfiltered(self):
|
||||
new_domain = self._get_domain_fixture()
|
||||
new_user = {'name': uuid.uuid4().hex, 'password': uuid.uuid4().hex,
|
||||
|
|
|
@ -1078,14 +1078,10 @@ class FederatedTokenTests(FederationTests):
|
|||
self._check_scoped_token_attributes(token_resp)
|
||||
|
||||
def test_scope_to_domain_with_only_inherited_roles_fails(self):
|
||||
# TODO(henry-nash): The following *should* fail (since the only roles
|
||||
# a customer has on domainD are inherited to projects within it.
|
||||
# See bug #1385533
|
||||
r = self.v3_authenticate_token(self.TOKEN_SCOPE_DOMAIN_D_FROM_CUSTOMER)
|
||||
token_resp = r.result['token']
|
||||
domain_id = token_resp['domain']['id']
|
||||
self.assertEqual(domain_id, self.domainD['id'])
|
||||
self._check_scoped_token_attributes(token_resp)
|
||||
"""Try to scope to a domain that has no direct roles."""
|
||||
self.v3_authenticate_token(
|
||||
self.TOKEN_SCOPE_DOMAIN_D_FROM_CUSTOMER,
|
||||
expected_status=401)
|
||||
|
||||
def test_list_projects(self):
|
||||
urls = ('/OS-FEDERATION/projects', '/auth/projects')
|
||||
|
@ -1116,18 +1112,16 @@ class FederatedTokenTests(FederationTests):
|
|||
self.tokens['EMPLOYEE_ASSERTION'],
|
||||
self.tokens['ADMIN_ASSERTION'])
|
||||
|
||||
# TODO(henry-nash): The following *should* not include domainD
|
||||
# for customer/admin since they only have a role that is inherited
|
||||
# to projects within it. See bug #1385643
|
||||
# NOTE(henry-nash): domain D does not appear in the expected results
|
||||
# since it only had inherited roles (which only apply to projects
|
||||
# within the domain)
|
||||
|
||||
domain_refs = (set([self.domainA['id'],
|
||||
self.domainD['id']]),
|
||||
domain_refs = (set([self.domainA['id']]),
|
||||
set([self.domainA['id'],
|
||||
self.domainB['id']]),
|
||||
set([self.domainA['id'],
|
||||
self.domainB['id'],
|
||||
self.domainC['id'],
|
||||
self.domainD['id']]))
|
||||
self.domainC['id']]))
|
||||
|
||||
for token, domains_ref in zip(tokens, domain_refs):
|
||||
for url in urls:
|
||||
|
|
Loading…
Reference in New Issue