diff options
author | Richard Avelar <csravelar@gmail.com> | 2017-03-22 17:57:56 +0000 |
---|---|---|
committer | Kristi Nikolla <kristi@nikolla.me> | 2020-04-07 19:59:45 -0400 |
commit | 652f02c8b50e20be3df562099869be3a391335c4 (patch) | |
tree | ac0dda611cc284d3212b151ab19230cd6b2ee94e /keystone | |
parent | ba2e4b83e88d5c1576e9d2cd6a760367deef3a62 (diff) | |
download | keystone-652f02c8b50e20be3df562099869be3a391335c4.tar.gz |
Add federated support for get user
This patch adds functionality to get_user that allows it to pull all
associated federated objects and tack it on to be displayed to the
user.
Partial-Bug: 1816076
Change-Id: I8d69ef68153d6650652e1081e5e7b9e5e31a3ed1
Diffstat (limited to 'keystone')
-rw-r--r-- | keystone/identity/core.py | 4 | ||||
-rw-r--r-- | keystone/identity/shadow_backends/base.py | 40 | ||||
-rw-r--r-- | keystone/identity/shadow_backends/sql.py | 13 | ||||
-rw-r--r-- | keystone/tests/unit/test_shadow_users.py | 29 | ||||
-rw-r--r-- | keystone/tests/unit/test_v3_identity.py | 10 |
5 files changed, 96 insertions, 0 deletions
diff --git a/keystone/identity/core.py b/keystone/identity/core.py index 2d0c266db..22fcb5fff 100644 --- a/keystone/identity/core.py +++ b/keystone/identity/core.py @@ -958,6 +958,10 @@ class Manager(manager.Manager): domain_id, driver, entity_id = ( self._get_domain_driver_and_entity_id(user_id)) ref = driver.get_user(entity_id) + # Add user's federated objects + fed_objects = self.shadow_users_api.get_federated_objects(user_id) + if fed_objects: + ref['federated'] = fed_objects return self._set_domain_id_and_mapping( ref, domain_id, driver, mapping.EntityType.USER) diff --git a/keystone/identity/shadow_backends/base.py b/keystone/identity/shadow_backends/base.py index 4fa3bb325..3e7f32189 100644 --- a/keystone/identity/shadow_backends/base.py +++ b/keystone/identity/shadow_backends/base.py @@ -17,6 +17,36 @@ import abc from keystone import exception +def federated_objects_to_list(fed_ref): + """Create a new reformatted federated object list using the one passed in. + + When returning federated objects with a user we only need the attributes + idp_id, protocol_id, and unique_id. Therefore, we pull these elements out + of the fed_ref and create a newly formatted list with the needed + information. We simply group each federated object's protocol_ids and + unique_ids under the corresponding idp_id. + + :returns list: Containing the user's federated objects + """ + if not fed_ref: + return [] + + fed = {} + for fed_dict in fed_ref: + fed.setdefault( + fed_dict['idp_id'], + { + 'idp_id': fed_dict['idp_id'], + 'protocols': [] + } + )['protocols'].append({ + 'protocol_id': fed_dict['protocol_id'], + 'unique_id': fed_dict['unique_id'] + }) + + return list(fed.values()) + + class ShadowUsersDriverBase(object, metaclass=abc.ABCMeta): """Interface description for an Shadow Users driver.""" @@ -33,6 +63,16 @@ class ShadowUsersDriverBase(object, metaclass=abc.ABCMeta): raise exception.NotImplemented() @abc.abstractmethod + def get_federated_objects(self, user_id): + """Get all federated objects for a user. + + :param user_id: Unique identifier of the user + :returns list: Containing the user's federated objects + + """ + raise exception.NotImplemented() + + @abc.abstractmethod def get_federated_user(self, idp_id, protocol_id, unique_id): """Return the found user for the federated identity. diff --git a/keystone/identity/shadow_backends/sql.py b/keystone/identity/shadow_backends/sql.py index 5ac8b6469..d739f5756 100644 --- a/keystone/identity/shadow_backends/sql.py +++ b/keystone/identity/shadow_backends/sql.py @@ -54,6 +54,19 @@ class ShadowUsers(base.ShadowUsersDriverBase): session.add(user_ref) return identity_base.filter_user(user_ref.to_dict()) + def get_federated_objects(self, user_id): + with sql.session_for_read() as session: + query = session.query(model.FederatedUser) + query = query.filter(model.FederatedUser.user_id == user_id) + fed_ref = [] + for row in query: + m = model.FederatedUser( + idp_id=row.idp_id, + protocol_id=row.protocol_id, + unique_id=row.unique_id) + fed_ref.append(m.to_dict()) + return base.federated_objects_to_list(fed_ref) + def _update_query_with_federated_statements(self, hints, query): statements = [] for filter_ in hints.filters: diff --git a/keystone/tests/unit/test_shadow_users.py b/keystone/tests/unit/test_shadow_users.py index e67556614..79f8ba53c 100644 --- a/keystone/tests/unit/test_shadow_users.py +++ b/keystone/tests/unit/test_shadow_users.py @@ -59,3 +59,32 @@ class ShadowUsersTests(unit.TestCase, self.idp['id'], self.protocol['id'], self.protocol) self.domain_id = ( PROVIDERS.federation_api.get_idp(self.idp['id'])['domain_id']) + + +class TestUserWithFederatedUser(ShadowUsersTests): + + def setUp(self): + super(TestUserWithFederatedUser, self).setUp() + self.useFixture(database.Database()) + self.load_backends() + + def assertFederatedDictsEqual(self, fed_dict, fed_object): + self.assertEqual(fed_dict['idp_id'], fed_object['idp_id']) + self.assertEqual(fed_dict['protocol_id'], + fed_object['protocols'][0]['protocol_id']) + self.assertEqual(fed_dict['unique_id'], + fed_object['protocols'][0]['unique_id']) + + def test_get_user_when_user_has_federated_object(self): + fed_dict = unit.new_federated_user_ref(idp_id=self.idp['id'], + protocol_id=self.protocol['id']) + user = self.shadow_users_api.create_federated_user( + self.domain_id, fed_dict) + + # test that the user returns a federated object and that there is only + # one returned + user_ref = self.identity_api.get_user(user['id']) + self.assertIn('federated', user_ref) + self.assertEqual(1, len(user_ref['federated'])) + + self.assertFederatedDictsEqual(fed_dict, user_ref['federated'][0]) diff --git a/keystone/tests/unit/test_v3_identity.py b/keystone/tests/unit/test_v3_identity.py index 276363713..2a22ce7fc 100644 --- a/keystone/tests/unit/test_v3_identity.py +++ b/keystone/tests/unit/test_v3_identity.py @@ -1167,3 +1167,13 @@ class UserFederatedAttributesTests(test_v3.RestfulTestCase): def test_list_users_with_all_federated_attributes(self): attribute = ['idp_id', 'protocol_id', 'unique_id'] self._test_list_users_with_federated_parameter(attribute) + + def test_get_user_includes_required_federated_attributes(self): + user = self.identity_api.get_user(self.fed_user['id']) + self.assertIn('federated', user) + self.assertIn('idp_id', user['federated'][0]) + self.assertIn('protocols', user['federated'][0]) + self.assertIn('protocol_id', user['federated'][0]['protocols'][0]) + self.assertIn('unique_id', user['federated'][0]['protocols'][0]) + r = self.get('/users/%(user_id)s' % {'user_id': user['id']}) + self.assertValidUserResponse(r, user) |