diff options
-rw-r--r-- | keystone/contrib/federation/utils.py | 55 | ||||
-rw-r--r-- | keystone/tests/unit/mapping_fixtures.py | 39 | ||||
-rw-r--r-- | keystone/tests/unit/test_v3_federation.py | 22 |
3 files changed, 85 insertions, 31 deletions
diff --git a/keystone/contrib/federation/utils.py b/keystone/contrib/federation/utils.py index 6fca2143d..6b0dbbdec 100644 --- a/keystone/contrib/federation/utils.py +++ b/keystone/contrib/federation/utils.py @@ -674,15 +674,18 @@ class RuleProcessor(object): for requirement in requirements: requirement_type = requirement['type'] + direct_map_values = assertion.get(requirement_type) regex = requirement.get('regex', False) + if not direct_map_values: + return None + any_one_values = requirement.get(self._EvalType.ANY_ONE_OF) if any_one_values is not None: if self._evaluate_requirement(any_one_values, - requirement_type, + direct_map_values, self._EvalType.ANY_ONE_OF, - regex, - assertion): + regex): continue else: return None @@ -690,10 +693,9 @@ class RuleProcessor(object): not_any_values = requirement.get(self._EvalType.NOT_ANY_OF) if not_any_values is not None: if self._evaluate_requirement(not_any_values, - requirement_type, + direct_map_values, self._EvalType.NOT_ANY_OF, - regex, - assertion): + regex): continue else: return None @@ -701,23 +703,21 @@ class RuleProcessor(object): # If 'any_one_of' or 'not_any_of' are not found, then values are # within 'type'. Attempt to find that 'type' within the assertion, # and filter these values if 'whitelist' or 'blacklist' is set. - direct_map_values = assertion.get(requirement_type) - if direct_map_values: - blacklisted_values = requirement.get(self._EvalType.BLACKLIST) - whitelisted_values = requirement.get(self._EvalType.WHITELIST) + blacklisted_values = requirement.get(self._EvalType.BLACKLIST) + whitelisted_values = requirement.get(self._EvalType.WHITELIST) - # If a blacklist or whitelist is used, we want to map to the - # whole list instead of just its values separately. - if blacklisted_values is not None: - direct_map_values = [v for v in direct_map_values - if v not in blacklisted_values] - elif whitelisted_values is not None: - direct_map_values = [v for v in direct_map_values - if v in whitelisted_values] + # If a blacklist or whitelist is used, we want to map to the + # whole list instead of just its values separately. + if blacklisted_values is not None: + direct_map_values = [v for v in direct_map_values + if v not in blacklisted_values] + elif whitelisted_values is not None: + direct_map_values = [v for v in direct_map_values + if v in whitelisted_values] - direct_maps.add(direct_map_values) + direct_maps.add(direct_map_values) - LOG.debug('updating a direct mapping: %s', direct_map_values) + LOG.debug('updating a direct mapping: %s', direct_map_values) return direct_maps @@ -728,8 +728,8 @@ class RuleProcessor(object): return True return False - def _evaluate_requirement(self, values, requirement_type, - eval_type, regex, assertion): + def _evaluate_requirement(self, values, assertion_values, + eval_type, regex): """Evaluate the incoming requirement and assertion. If the requirement type does not exist in the assertion data, then @@ -739,23 +739,16 @@ class RuleProcessor(object): :param values: list of allowed values, defined in the requirement :type values: list - :param requirement_type: key to look for in the assertion - :type requirement_type: string + :param assertion_values: The values from the assertion to evaluate + :type assertion_values: list/string :param eval_type: determine how to evaluate requirements :type eval_type: string :param regex: perform evaluation with regex :type regex: boolean - :param assertion: dict of attributes from the IdP - :type assertion: dict :returns: boolean, whether requirement is valid or not. """ - - assertion_values = assertion.get(requirement_type) - if not assertion_values: - return False - if regex: any_match = self._evaluate_values_by_regex(values, assertion_values) diff --git a/keystone/tests/unit/mapping_fixtures.py b/keystone/tests/unit/mapping_fixtures.py index 0892ada54..fbffb0afb 100644 --- a/keystone/tests/unit/mapping_fixtures.py +++ b/keystone/tests/unit/mapping_fixtures.py @@ -897,6 +897,45 @@ MAPPING_GROUPS_WHITELIST_AND_BLACKLIST = { ] } +MAPPING_GROUPS_WHITELIST_PASS_THROUGH = { + "rules": [ + { + "remote": [ + { + "type": "UserName" + } + ], + "local": [ + { + "user": { + "name": "{0}", + "domain": { + "id": DEVELOPER_GROUP_DOMAIN_ID + } + } + } + ] + }, + { + "remote": [ + { + "type": "orgPersonType", + "whitelist": ['Developer'] + } + ], + "local": [ + { + "groups": "{0}", + "domain": { + "id": DEVELOPER_GROUP_DOMAIN_ID + } + } + ] + } + ] +} + + EMPLOYEE_ASSERTION = { 'Email': 'tim@example.com', 'UserName': 'tbo', diff --git a/keystone/tests/unit/test_v3_federation.py b/keystone/tests/unit/test_v3_federation.py index 7bdfecb84..06ec62334 100644 --- a/keystone/tests/unit/test_v3_federation.py +++ b/keystone/tests/unit/test_v3_federation.py @@ -1963,6 +1963,28 @@ class MappingRuleEngineTests(FederationTests): self.assertEqual('bwilliams', mapped_properties['user']['name']) self.assertEqual('abc123', mapped_properties['user']['id']) + def test_whitelist_pass_through(self): + mapping = mapping_fixtures.MAPPING_GROUPS_WHITELIST_PASS_THROUGH + rp = mapping_utils.RuleProcessor(mapping['rules']) + assertion = mapping_fixtures.DEVELOPER_ASSERTION + mapped_properties = rp.process(assertion) + self.assertValidMappedUserObject(mapped_properties) + + self.assertEqual('developacct', mapped_properties['user']['name']) + self.assertEqual('Developer', + mapped_properties['group_names'][0]['name']) + + def test_type_not_in_assertion(self): + """Test that if the remote "type" is not in the assertion it fails.""" + mapping = mapping_fixtures.MAPPING_GROUPS_WHITELIST_PASS_THROUGH + rp = mapping_utils.RuleProcessor(mapping['rules']) + assertion = {uuid.uuid4().hex: uuid.uuid4().hex} + mapped_properties = rp.process(assertion) + self.assertValidMappedUserObject(mapped_properties) + + self.assertNotIn('id', mapped_properties['user']) + self.assertNotIn('name', mapped_properties['user']) + class FederatedTokenTests(FederationTests, FederatedSetupMixin): |