Fix user email in federated shadow users

When the federated rule contains 'email' in user and we should set
email for the federated user. Also, if the federated user changes the
email info, it should be chenged too.

Change-Id: Ib17172c34bd65d5236cbfc192b3a3f2b221411ef
Closes-Bug: #1746599
This commit is contained in:
yangweiwei 2018-03-22 19:26:08 +08:00
parent e05e2b5a60
commit 475ea454ee
8 changed files with 31 additions and 7 deletions

View File

@ -237,9 +237,11 @@ def handle_unscoped_token(request, auth_payload, resource_api, federation_api,
unique_id, display_name = (
get_user_unique_id_and_display_name(request, mapped_properties)
)
email = mapped_properties['user'].get('email')
user = identity_api.shadow_federated_user(identity_provider,
protocol, unique_id,
display_name)
display_name,
email)
if 'projects' in mapped_properties:
idp_domain_id = federation_api.get_idp(

View File

@ -1412,13 +1412,14 @@ class Manager(manager.Manager):
@MEMOIZE
def shadow_federated_user(self, idp_id, protocol_id, unique_id,
display_name):
display_name, email=None):
"""Map a federated user to a user.
:param idp_id: identity provider id
:param protocol_id: protocol id
:param unique_id: unique id for the user within the IdP
:param display_name: user's display name
:param email: user's email
:returns: dictionary of the mapped User entity
"""
@ -1428,6 +1429,10 @@ class Manager(manager.Manager):
idp_id, protocol_id, unique_id, display_name)
user_dict = PROVIDERS.shadow_users_api.get_federated_user(
idp_id, protocol_id, unique_id)
if email:
user_ref = {"email": email}
self.update_user(user_dict['id'], user_ref)
user_dict.update({"email": email})
except exception.UserNotFound:
idp = PROVIDERS.federation_api.get_idp(idp_id)
federated_dict = {
@ -1438,7 +1443,7 @@ class Manager(manager.Manager):
}
user_dict = (
PROVIDERS.shadow_users_api.create_federated_user(
idp['domain_id'], federated_dict
idp['domain_id'], federated_dict, email=email
)
)
PROVIDERS.shadow_users_api.set_last_active_at(user_dict['id'])

View File

@ -24,11 +24,12 @@ class ShadowUsersDriverBase(object):
"""Interface description for an Shadow Users driver."""
@abc.abstractmethod
def create_federated_user(self, domain_id, federated_dict):
def create_federated_user(self, domain_id, federated_dict, email=None):
"""Create a new user with the federated identity.
:param domain_id: The domain ID of the IdP used for the federated user
:param dict federated_dict: Reference to the federated user
:param email: Federated user's email
:returns dict: Containing the user reference
"""

View File

@ -29,12 +29,14 @@ CONF = cfg.CONF
class ShadowUsers(base.ShadowUsersDriverBase):
@sql.handle_conflicts(conflict_type='federated_user')
def create_federated_user(self, domain_id, federated_dict):
def create_federated_user(self, domain_id, federated_dict, email=None):
user = {
'id': uuid.uuid4().hex,
'domain_id': domain_id,
'enabled': True
}
if email:
user['email'] = email
with sql.session_for_write() as session:
federated_ref = model.FederatedUser.from_dict(federated_dict)
user_ref = model.User.from_dict(user)

View File

@ -83,6 +83,11 @@ class ShadowUsersBackendTests(object):
self.domain_id, self.federated_user)
self.assertEqual(user['domain_id'], self.domain_id)
def test_create_federated_user_email(self):
user = PROVIDERS.shadow_users_api.create_federated_user(
self.domain_id, self.federated_user, self.email)
self.assertEqual(user['email'], self.email)
def test_get_federated_user(self):
user_dict_create = PROVIDERS.shadow_users_api.create_federated_user(
self.domain_id, self.federated_user)

View File

@ -23,9 +23,10 @@ class ShadowUsersCoreTests(object):
self.federated_user['idp_id'],
self.federated_user['protocol_id'],
self.federated_user['unique_id'],
self.federated_user['display_name'])
self.federated_user['display_name'],
self.email)
self.assertIsNotNone(user['id'])
self.assertEqual(6, len(user.keys()))
self.assertEqual(7, len(user.keys()))
self.assertIsNotNone(user['name'])
self.assertIsNone(user['password_expires_at'])
self.assertIsNotNone(user['domain_id'])
@ -33,6 +34,7 @@ class ShadowUsersCoreTests(object):
# equal True. assertTrue should not be used, because it converts
# the passed value to bool().
self.assertEqual(True, user['enabled'])
self.assertIsNotNone(user['email'])
def test_shadow_existing_federated_user(self):

View File

@ -47,6 +47,7 @@ class ShadowUsersTests(unit.TestCase,
'unique_id': uuid.uuid4().hex,
'display_name': uuid.uuid4().hex
}
self.email = uuid.uuid4().hex
PROVIDERS.federation_api.create_idp(self.idp['id'], self.idp)
PROVIDERS.federation_api.create_mapping(
self.mapping['id'], self.mapping

View File

@ -0,0 +1,6 @@
---
fixes:
- |
[`bug 1746599 <https://bugs.launchpad.net/keystone/+bug/1746599>`_]
Fixes user email being set for federated shadow users, when the rule
contains email in user.