Invalidate the shadow user cache when deleting a user

When deleting a user, the cache for the related shadow user should
be invalidated as well. Otherwise the federation authentication
will not work well and will raise 404 UserNotFound error.

This patch fixes the bug and adds a new function for shadow backend
to get the shadow user information.

Change-Id: I3882f0dc6e8f8f618bb89ebd699736bc4b352261
Closes-bug: #1760205
This commit is contained in:
wangxiyuan 2018-04-17 19:21:43 +08:00
parent 587cf2e1ba
commit 3b701cdf70
5 changed files with 65 additions and 0 deletions

View File

@ -1147,11 +1147,22 @@ class Manager(manager.Manager):
self._get_domain_driver_and_entity_id(user_id))
# Get user details to invalidate the cache.
user_old = self.get_user(user_id)
hints = driver_hints.Hints()
hints.add_filter('user_id', user_id)
fed_users = PROVIDERS.shadow_users_api.list_federated_users_info(hints)
driver.delete_user(entity_id)
PROVIDERS.assignment_api.delete_user_assignments(user_id)
self.get_user.invalidate(self, user_id)
self.get_user_by_name.invalidate(self, user_old['name'],
user_old['domain_id'])
for fed_user in fed_users:
self.shadow_federated_user.invalidate(
self, fed_user['idp_id'], fed_user['protocol_id'],
fed_user['unique_id'], fed_user['display_name'],
user_old.get('extra', {}).get('email'))
PROVIDERS.credential_api.delete_credentials_for_user(user_id)
PROVIDERS.id_mapping_api.delete_id_mapping(user_id)
notifications.Audit.deleted(self._USER, user_id, initiator)

View File

@ -88,3 +88,16 @@ class ShadowUsersDriverBase(object):
"""
raise exception.NotImplemented()
@abc.abstractmethod
def list_federated_users_info(self, hints=None):
"""Get the shadow users info with the specified filters.
:param hints: contains the list of filters yet to be satisfied.
Any filters satisfied here will be removed so that
the caller will know if any filters remain.
:returns list: A list of objects that containing the shadow users
reference.
"""
raise exception.NotImplemented()

View File

@ -170,3 +170,10 @@ class ShadowUsers(base.ShadowUsersDriverBase):
if not user_ref:
raise exception.UserNotFound(user_id=user_id)
return user_ref
def list_federated_users_info(self, hints=None):
with sql.session_for_read() as session:
query = session.query(model.FederatedUser)
fed_user_refs = sql.filter_limit_query(model.FederatedUser, query,
hints)
return [x.to_dict() for x in fed_user_refs]

View File

@ -1901,6 +1901,26 @@ class FederatedTokenTests(test_v3.RestfulTestCase, FederatedSetupMixin):
self.assertIsNotNone(r.headers.get('X-Subject-Token'))
self.assertValidMappedUser(r.json['token'])
def test_issue_the_same_unscoped_token_with_user_deleted(self):
r = self._issue_unscoped_token()
token = r.json['token']
user1 = token['user']
user_id1 = user1.pop('id')
# delete the referenced user, and authenticate again. Keystone should
# create another new shadow user.
PROVIDERS.identity_api.delete_user(user_id1)
r = self._issue_unscoped_token()
token = r.json['token']
user2 = token['user']
user_id2 = user2.pop('id')
# Only the user_id is different. Other properties include
# identity_provider, protocol, groups and domain are the same.
self.assertIsNot(user_id2, user_id1)
self.assertEqual(user1, user2)
def test_issue_unscoped_token_disabled_idp(self):
"""Check if authentication works with disabled identity providers.

View File

@ -0,0 +1,14 @@
---
fixes:
- |
[`bug 1760205 <https://bugs.launchpad.net/keystone/+bug/1760205>`_]
When deleting a shadow user, the related cache info is not invalidated so
that Keystone will raise 404 UserNotFound error when authenticating with
the previous federation info. This bug has been fixed now.
other:
- |
A new interface called `list_federated_users_info` is added to shadow
backend. It's used to get the shadow user information internally. If you
are maintaining any out-tree shadow backends, please implement this
function for them as well.