Ensure ephemeral user's user_id is url-safe
As a principle, an attribute ``user_id`` should always be url safe and we should make sure this is the case especially for the federated authentication workflow as user name and id can be provided directly from the user (either hardcoded in the mapping rule or passed as a parameter from the assertion). Change-Id: I7256a5e4d31d3c2e55fe956fb0170452bb241078 Closes-Bug: #1487115
This commit is contained in:
parent
59ea878c8c
commit
02f8576ddf
|
@ -245,6 +245,8 @@ def setup_username(context, mapped_properties):
|
|||
user['name'] = user_id
|
||||
|
||||
elif not user_id:
|
||||
user['id'] = parse.quote(user_name)
|
||||
user_id = user_name
|
||||
|
||||
user['id'] = parse.quote(user_id)
|
||||
|
||||
return user
|
||||
|
|
|
@ -789,6 +789,7 @@ MAPPING_USER_IDS = {
|
|||
{
|
||||
"user": {
|
||||
"name": "{0}",
|
||||
"id": "abc123@example.com",
|
||||
"domain": {
|
||||
"id": "federated"
|
||||
}
|
||||
|
@ -831,7 +832,7 @@ MAPPING_USER_IDS = {
|
|||
"local": [
|
||||
{
|
||||
"user": {
|
||||
"id": "abc123",
|
||||
"id": "abc123@example.com",
|
||||
"name": "{0}",
|
||||
"domain": {
|
||||
"id": "federated"
|
||||
|
@ -966,6 +967,7 @@ TESTER_ASSERTION = {
|
|||
}
|
||||
|
||||
ANOTHER_TESTER_ASSERTION = {
|
||||
'Email': 'testacct@example.com',
|
||||
'UserName': 'IamTester'
|
||||
}
|
||||
|
||||
|
|
|
@ -334,7 +334,8 @@ class FederatedSetupMixin(object):
|
|||
},
|
||||
{
|
||||
'user': {
|
||||
'name': '{0}'
|
||||
'name': '{0}',
|
||||
'id': '{1}'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -342,6 +343,9 @@ class FederatedSetupMixin(object):
|
|||
{
|
||||
'type': 'UserName'
|
||||
},
|
||||
{
|
||||
'type': 'Email',
|
||||
},
|
||||
{
|
||||
'type': 'orgPersonType',
|
||||
'any_one_of': [
|
||||
|
@ -359,7 +363,8 @@ class FederatedSetupMixin(object):
|
|||
},
|
||||
{
|
||||
'user': {
|
||||
'name': '{0}'
|
||||
'name': '{0}',
|
||||
'id': '{1}'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -367,6 +372,9 @@ class FederatedSetupMixin(object):
|
|||
{
|
||||
'type': self.ASSERTION_PREFIX + 'UserName'
|
||||
},
|
||||
{
|
||||
'type': self.ASSERTION_PREFIX + 'Email',
|
||||
},
|
||||
{
|
||||
'type': self.ASSERTION_PREFIX + 'orgPersonType',
|
||||
'any_one_of': [
|
||||
|
@ -384,7 +392,8 @@ class FederatedSetupMixin(object):
|
|||
},
|
||||
{
|
||||
'user': {
|
||||
'name': '{0}'
|
||||
'name': '{0}',
|
||||
'id': '{1}'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -392,6 +401,9 @@ class FederatedSetupMixin(object):
|
|||
{
|
||||
'type': 'UserName'
|
||||
},
|
||||
{
|
||||
'type': 'Email'
|
||||
},
|
||||
{
|
||||
'type': 'orgPersonType',
|
||||
'any_one_of': [
|
||||
|
@ -420,7 +432,8 @@ class FederatedSetupMixin(object):
|
|||
|
||||
{
|
||||
'user': {
|
||||
'name': '{0}'
|
||||
'name': '{0}',
|
||||
'id': '{1}'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -428,6 +441,9 @@ class FederatedSetupMixin(object):
|
|||
{
|
||||
'type': 'UserName'
|
||||
},
|
||||
{
|
||||
'type': 'Email'
|
||||
},
|
||||
{
|
||||
'type': 'orgPersonType',
|
||||
'any_one_of': [
|
||||
|
@ -451,7 +467,8 @@ class FederatedSetupMixin(object):
|
|||
},
|
||||
{
|
||||
'user': {
|
||||
'name': '{0}'
|
||||
'name': '{0}',
|
||||
'id': '{1}'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -459,6 +476,9 @@ class FederatedSetupMixin(object):
|
|||
{
|
||||
'type': 'UserName',
|
||||
},
|
||||
{
|
||||
'type': 'Email',
|
||||
},
|
||||
{
|
||||
'type': 'FirstName',
|
||||
'any_one_of': [
|
||||
|
@ -482,7 +502,8 @@ class FederatedSetupMixin(object):
|
|||
},
|
||||
{
|
||||
'user': {
|
||||
'name': '{0}'
|
||||
'name': '{0}',
|
||||
'id': '{1}'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -490,6 +511,9 @@ class FederatedSetupMixin(object):
|
|||
{
|
||||
'type': 'UserName',
|
||||
},
|
||||
{
|
||||
'type': 'Email',
|
||||
},
|
||||
{
|
||||
'type': 'Email',
|
||||
'any_one_of': [
|
||||
|
@ -509,7 +533,8 @@ class FederatedSetupMixin(object):
|
|||
"local": [
|
||||
{
|
||||
'user': {
|
||||
'name': '{0}'
|
||||
'name': '{0}',
|
||||
'id': '{1}'
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -525,6 +550,9 @@ class FederatedSetupMixin(object):
|
|||
{
|
||||
'type': 'UserName',
|
||||
},
|
||||
{
|
||||
'type': 'Email',
|
||||
},
|
||||
{
|
||||
"type": "orgPersonType",
|
||||
"any_one_of": [
|
||||
|
@ -538,7 +566,8 @@ class FederatedSetupMixin(object):
|
|||
"local": [
|
||||
{
|
||||
'user': {
|
||||
'name': '{0}'
|
||||
'name': '{0}',
|
||||
'id': '{1}'
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -554,6 +583,9 @@ class FederatedSetupMixin(object):
|
|||
{
|
||||
"type": "UserName",
|
||||
},
|
||||
{
|
||||
"type": "Email",
|
||||
},
|
||||
{
|
||||
"type": "orgPersonType",
|
||||
"any_one_of": [
|
||||
|
@ -566,7 +598,8 @@ class FederatedSetupMixin(object):
|
|||
"local": [
|
||||
{
|
||||
"user": {
|
||||
"name": "{0}"
|
||||
"name": "{0}",
|
||||
"id": "{1}"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -582,6 +615,9 @@ class FederatedSetupMixin(object):
|
|||
{
|
||||
"type": "UserName",
|
||||
},
|
||||
{
|
||||
"type": "Email",
|
||||
},
|
||||
{
|
||||
"type": "UserName",
|
||||
"any_one_of": [
|
||||
|
@ -1943,7 +1979,8 @@ class MappingRuleEngineTests(FederationTests):
|
|||
self.assertValidMappedUserObject(mapped_properties)
|
||||
mapped.setup_username({}, mapped_properties)
|
||||
self.assertEqual('tbo', mapped_properties['user']['name'])
|
||||
self.assertEqual('tbo', mapped_properties['user']['id'])
|
||||
self.assertEqual('abc123%40example.com',
|
||||
mapped_properties['user']['id'])
|
||||
|
||||
def test_user_identification_id(self):
|
||||
"""Test varius mapping options and how users are identified.
|
||||
|
@ -1981,17 +2018,28 @@ class MappingRuleEngineTests(FederationTests):
|
|||
- Check if user's id is properly set and and equal to value hardcoded
|
||||
in the mapping
|
||||
|
||||
This test does two iterations with different assertions used as input
|
||||
for the Mapping Engine. Different assertions will be matched with
|
||||
different rules in the ruleset, effectively issuing different user_id
|
||||
(hardcoded values). In the first iteration, the hardcoded user_id is
|
||||
not url-safe and we expect Keystone to make it url safe. In the latter
|
||||
iteration, provided user_id is already url-safe and we expect server
|
||||
not to change it.
|
||||
|
||||
"""
|
||||
mapping = mapping_fixtures.MAPPING_USER_IDS
|
||||
rp = mapping_utils.RuleProcessor(mapping['rules'])
|
||||
assertion = mapping_fixtures.CUSTOMER_ASSERTION
|
||||
mapped_properties = rp.process(assertion)
|
||||
context = {'environment': {}}
|
||||
self.assertIsNotNone(mapped_properties)
|
||||
self.assertValidMappedUserObject(mapped_properties)
|
||||
mapped.setup_username(context, mapped_properties)
|
||||
self.assertEqual('bwilliams', mapped_properties['user']['name'])
|
||||
self.assertEqual('abc123', mapped_properties['user']['id'])
|
||||
testcases = [(mapping_fixtures.CUSTOMER_ASSERTION, 'bwilliams'),
|
||||
(mapping_fixtures.EMPLOYEE_ASSERTION, 'tbo')]
|
||||
for assertion, exp_user_name in testcases:
|
||||
mapping = mapping_fixtures.MAPPING_USER_IDS
|
||||
rp = mapping_utils.RuleProcessor(mapping['rules'])
|
||||
mapped_properties = rp.process(assertion)
|
||||
context = {'environment': {}}
|
||||
self.assertIsNotNone(mapped_properties)
|
||||
self.assertValidMappedUserObject(mapped_properties)
|
||||
mapped.setup_username(context, mapped_properties)
|
||||
self.assertEqual(exp_user_name, mapped_properties['user']['name'])
|
||||
self.assertEqual('abc123%40example.com',
|
||||
mapped_properties['user']['id'])
|
||||
|
||||
|
||||
class FederatedTokenTests(FederationTests, FederatedSetupMixin):
|
||||
|
@ -2925,12 +2973,12 @@ class FernetFederatedTokenTests(FederationTests, FederatedSetupMixin):
|
|||
|
||||
def test_federated_unscoped_token(self):
|
||||
resp = self._issue_unscoped_token()
|
||||
self.assertEqual(186, len(resp.headers['X-Subject-Token']))
|
||||
self.assertEqual(204, len(resp.headers['X-Subject-Token']))
|
||||
|
||||
def test_federated_unscoped_token_with_multiple_groups(self):
|
||||
assertion = 'ANOTHER_CUSTOMER_ASSERTION'
|
||||
resp = self._issue_unscoped_token(assertion=assertion)
|
||||
self.assertEqual(204, len(resp.headers['X-Subject-Token']))
|
||||
self.assertEqual(232, len(resp.headers['X-Subject-Token']))
|
||||
|
||||
def test_validate_federated_unscoped_token(self):
|
||||
resp = self._issue_unscoped_token()
|
||||
|
|
Loading…
Reference in New Issue