From 7f9b2dff8c38d55de977513c8424ecf9a8483a76 Mon Sep 17 00:00:00 2001 From: Brant Knudson Date: Fri, 18 Apr 2014 14:13:01 -0500 Subject: [PATCH 3/3] LDAP fix for get_roles_for_user_and_project user=group ID When there was a role assigned to a group with the same ID as a user, the LDAP assignment backend would incorrectly return the assignment to the group when requesting roles for the user via the get_roles_for_user_and_project method. With this change, assignments to a group with the same ID are not returned for the user when calling get_roles_for_user_and_project. Change-Id: Id562ad958faff03742a014dcee0ec6b7fa5362a6 Closes-Bug: #1309228 --- keystone/assignment/backends/ldap.py | 60 +++++++++++++++++++++++++--------- keystone/tests/test_backend_ldap.py | 39 ---------------------- 2 files changed, 45 insertions(+), 54 deletions(-) diff --git a/keystone/assignment/backends/ldap.py b/keystone/assignment/backends/ldap.py index 7d41344..bc53f51 100644 --- a/keystone/assignment/backends/ldap.py +++ b/keystone/assignment/backends/ldap.py @@ -88,24 +88,54 @@ class Assignment(assignment.Driver): def _get_roles_for_just_user_and_project(user_id, tenant_id): self.get_project(tenant_id) - return [self.role._dn_to_id(a.role_dn) - for a in self.role.get_role_assignments - (self.project._id_to_dn(tenant_id)) - if self.user._dn_to_id(a.user_dn) == user_id] + + proj_dn = self.project._id_to_dn(tenant_id) + assignments = self.role.get_role_assignments(proj_dn) + + roles = [] + for assignment in assignments: + assignment_id = self.user._dn_to_id(assignment.user_dn) + + if assignment_id != user_id: + # Skip this assignment, it's not the target user id. + continue + + # "normalize" DN by uppercase, then see if the entry is in the + # tree by checking if the entry DN ends with the tree DN. + assignment_dn_norm = assignment.user_dn.upper() + user_tree_dn_norm = self.user.tree_dn.upper() + if not assignment_dn_norm.endswith(user_tree_dn_norm): + # Skip this assignment, it's not a user assignment. + continue + + role_id = self.role._dn_to_id(assignment.role_dn) + roles.append(role_id) + return roles def _get_roles_for_group_and_project(group_id, project_id): self.get_project(project_id) - group_dn = self.group._id_to_dn(group_id) - # NOTE(marcos-fermin-lobo): In Active Directory, for functions - # such as "self.role.get_role_assignments", it returns - # the key "CN" or "OU" in uppercase. - # The group_dn var has "CN" and "OU" in lowercase. - # For this reason, it is necessary to use the "upper()" - # function so both are consistent. - return [self.role._dn_to_id(a.role_dn) - for a in self.role.get_role_assignments - (self.project._id_to_dn(project_id)) - if a.user_dn.upper() == group_dn.upper()] + + project_dn = self.project._id_to_dn(project_id) + assignments = self.role.get_role_assignments(project_dn) + + roles = [] + for assignment in assignments: + assignment_id = self.group._dn_to_id(assignment.user_dn) + + if assignment_id != group_id: + # Skip this assignment, it's not the target group id. + continue + + # "normalize" DN by uppercase, then see if the entry is in the + # tree by checking if the entry DN ends with the tree DN. + assignment_dn_norm = assignment.user_dn.upper() + group_tree_dn_norm = self.group.tree_dn.upper() + if not assignment_dn_norm.endswith(group_tree_dn_norm): + # Skip this assignment, it's not a group assignment. + continue + + roles.append(self.role._dn_to_id(assignment.role_dn)) + return roles if domain_id is not None: msg = _('Domain metadata not supported by LDAP') diff --git a/keystone/tests/test_backend_ldap.py b/keystone/tests/test_backend_ldap.py index 8109a23..4e17c86 100644 --- a/keystone/tests/test_backend_ldap.py +++ b/keystone/tests/test_backend_ldap.py @@ -1251,45 +1251,6 @@ class LDAPIdentity(BaseLDAPIdentity, tests.TestCase): self.assertEqual(ldap.DEREF_SEARCHING, conn.get_option(ldap.OPT_DEREF)) - def test_get_roles_for_user_and_project_user_group_same_id(self): - """When a user has the same ID as a group, - get_roles_for_user_and_project returns the roles for the group. - - Overriding this test for LDAP because it works differently. The role - for the group is returned. This is bug 1309228. - """ - - # Setup: create user, group with same ID, role, and project; - # assign the group the role on the project. - - user_group_id = uuid.uuid4().hex - - user1 = {'id': user_group_id, 'name': uuid.uuid4().hex, - 'domain_id': CONF.identity.default_domain_id, } - self.identity_api.create_user(user_group_id, user1) - - group1 = {'id': user_group_id, 'name': uuid.uuid4().hex, - 'domain_id': CONF.identity.default_domain_id, } - self.identity_api.create_group(user_group_id, group1) - - role1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex} - self.assignment_api.create_role(role1['id'], role1) - - project1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex, - 'domain_id': CONF.identity.default_domain_id, } - self.assignment_api.create_project(project1['id'], project1) - - self.assignment_api.create_grant(role1['id'], - group_id=user_group_id, - project_id=project1['id']) - - # Check the roles, shouldn't be any since the user wasn't granted any. - roles = self.assignment_api.get_roles_for_user_and_project( - user_group_id, project1['id']) - - self.assertEqual([role1['id']], roles, - 'role for group is %s' % role1['id']) - class LDAPIdentityEnabledEmulation(LDAPIdentity): def setUp(self): -- 1.7.9.5