Fix list users by name

When attempting to filter users by name, it works
for local users, but doesn't work for federated users.

This patch fixed this error.

Change-Id: I1bee51c2be81dbddd9d849731ab53728c86b2765
Closes-bug: #1738895
This commit is contained in:
wangxiyuan 2017-12-23 16:51:25 +08:00
parent f4ac7b7a5f
commit e7a4d43ece
4 changed files with 57 additions and 4 deletions

View File

@ -14,6 +14,7 @@
"""Main entry point into the Identity service."""
import copy
import functools
import itertools
import operator
@ -1025,12 +1026,23 @@ class Manager(manager.Manager):
raise exception.InvalidOperatorError(op)
return hints
def _handle_federated_attributes_in_hints(self, driver, hints):
def _handle_shadow_and_local_users(self, driver, hints):
federated_attributes = ['idp_id', 'protocol_id', 'unique_id']
for filter_ in hints.filters:
if filter_['name'] in federated_attributes:
return PROVIDERS.shadow_users_api.get_federated_users(hints)
return driver.list_users(hints)
fed_hints = copy.deepcopy(hints)
res = driver.list_users(hints)
# Note: If the filters contain 'name', we should get the user from both
# local user and shadow user backend.
for filter_ in fed_hints.filters:
if filter_['name'] == 'name':
fed_res = PROVIDERS.shadow_users_api.get_federated_users(
fed_hints)
res += fed_res
break
return res
@domains_configured
@exception_translated('user')
@ -1047,7 +1059,7 @@ class Manager(manager.Manager):
# driver selection, so remove any such filter.
self._mark_domain_id_filter_satisfied(hints)
hints = self._translate_expired_password_hints(hints)
ref_list = self._handle_federated_attributes_in_hints(driver, hints)
ref_list = self._handle_shadow_and_local_users(driver, hints)
return self._set_domain_id_and_mapping(
ref_list, domain_scope, driver, mapping.EntityType.USER)

View File

@ -67,9 +67,20 @@ class ShadowUsers(base.ShadowUsersDriverBase):
def get_federated_users(self, hints):
with sql.session_for_read() as session:
query = session.query(model.User).outerjoin(model.LocalUser)
query = session.query(model.User).outerjoin(
model.LocalUser).outerjoin(model.FederatedUser)
query = query.filter(model.User.id == model.FederatedUser.user_id)
query = self._update_query_with_federated_statements(hints, query)
name_filter = None
for filter_ in hints.filters:
if filter_['name'] == 'name':
name_filter = filter_
query = query.filter(
model.FederatedUser.display_name == name_filter[
'value'])
break
if name_filter:
hints.filters.remove(name_filter)
user_refs = sql.filter_limit_query(model.User, query, hints)
return [identity_base.filter_user(x.to_dict()) for x in user_refs]

View File

@ -529,6 +529,29 @@ class IdentityTests(object):
filters = ['unique_id', 'idp_id', 'protocol_id']
self._test_list_users_with_attribute(filters, federated_dict)
def test_list_users_with_name(self):
federated_dict = unit.new_federated_user_ref(
display_name='test@federation.org')
domain = self._get_domain_fixture()
hints = driver_hints.Hints()
hints.add_filter('name', 'test@federation.org')
users = self.identity_api.list_users(hints=hints)
self.assertEqual(0, len(users))
self.shadow_users_api.create_federated_user(domain['id'],
federated_dict)
hints = driver_hints.Hints()
hints.add_filter('name', 'test@federation.org')
users = self.identity_api.list_users(hints=hints)
self.assertEqual(1, len(users))
hints = driver_hints.Hints()
hints.add_filter('name', 'test@federation.org')
hints.add_filter('idp_id', 'ORG_IDP')
users = self.identity_api.list_users(hints=hints)
self.assertEqual(1, len(users))
def test_list_groups(self):
group1 = unit.new_group_ref(domain_id=CONF.identity.default_domain_id)
group2 = unit.new_group_ref(domain_id=CONF.identity.default_domain_id)

View File

@ -0,0 +1,7 @@
---
fixes:
- |
[`bug 1738895 <https://bugs.launchpad.net/keystone/+bug/1738895>`_]
Fixed the bug that federated users can't be listed by `name` filter. Now
when list users by `name`, Keystone will query both local user backend and
shadow user backend.