summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Avelar <csravelar@gmail.com>2017-03-22 17:57:56 +0000
committerKristi Nikolla <kristi@nikolla.me>2020-04-07 19:59:45 -0400
commit652f02c8b50e20be3df562099869be3a391335c4 (patch)
treeac0dda611cc284d3212b151ab19230cd6b2ee94e
parentba2e4b83e88d5c1576e9d2cd6a760367deef3a62 (diff)
downloadkeystone-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
-rw-r--r--keystone/identity/core.py4
-rw-r--r--keystone/identity/shadow_backends/base.py40
-rw-r--r--keystone/identity/shadow_backends/sql.py13
-rw-r--r--keystone/tests/unit/test_shadow_users.py29
-rw-r--r--keystone/tests/unit/test_v3_identity.py10
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)