Fix evaluation logic of federation mapping rules
In the evaluation of federation mapping rules, when "regex" is true, it's only checked that if the values from assertion match the values from mapping rules, and "any_one_of" and "not_any_of" options are bypassed. So if one specifies "regex: True" and "not_any_of" at the same time, he will got an unexpected result that assertion with values in "not_any_of" can pass the evaluation. The expected behaviour, when "regex" is true, should be matching values in assertion and mapping rules using regular expression, if match with "any_one_of" or not match with "not_any_of", pass the evaluation, otherwise fail the evaluation. Change-Id: Ic6969c6dc23cff3abce775711f9ed01ffdf8dcb1 Closes-Bug: #1414961
This commit is contained in:
parent
76342b77cf
commit
ac928df1b9
|
@ -534,6 +534,13 @@ class RuleProcessor(object):
|
|||
|
||||
return direct_maps
|
||||
|
||||
def _evaluate_values_by_regex(self, values, assertion_values):
|
||||
for value in values:
|
||||
for assertion_value in assertion_values:
|
||||
if re.search(value, assertion_value):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _evaluate_requirement(self, values, requirement_type,
|
||||
eval_type, regex, assertion):
|
||||
"""Evaluate the incoming requirement and assertion.
|
||||
|
@ -563,13 +570,10 @@ class RuleProcessor(object):
|
|||
return False
|
||||
|
||||
if regex:
|
||||
for value in values:
|
||||
for assertion_value in assertion_values:
|
||||
if re.search(value, assertion_value):
|
||||
return True
|
||||
return False
|
||||
|
||||
any_match = bool(set(values).intersection(set(assertion_values)))
|
||||
any_match = self._evaluate_values_by_regex(values,
|
||||
assertion_values)
|
||||
else:
|
||||
any_match = bool(set(values).intersection(set(assertion_values)))
|
||||
if any_match and eval_type == self._EvalType.ANY_ONE_OF:
|
||||
return True
|
||||
if not any_match and eval_type == self._EvalType.NOT_ANY_OF:
|
||||
|
|
|
@ -458,6 +458,40 @@ MAPPING_TESTER_REGEX = {
|
|||
]
|
||||
}
|
||||
|
||||
MAPPING_DEVELOPER_REGEX = {
|
||||
"rules": [
|
||||
{
|
||||
"local": [
|
||||
{
|
||||
"user": {
|
||||
"name": "{0}",
|
||||
},
|
||||
"group": {
|
||||
"id": DEVELOPER_GROUP_ID
|
||||
}
|
||||
}
|
||||
],
|
||||
"remote": [
|
||||
{
|
||||
"type": "UserName"
|
||||
},
|
||||
{
|
||||
"type": "orgPersonType",
|
||||
"any_one_of": [
|
||||
"Developer"
|
||||
],
|
||||
},
|
||||
{
|
||||
"type": "Email",
|
||||
"not_any_of": [
|
||||
".*@example.org$"
|
||||
],
|
||||
"regex": True
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
MAPPING_GROUP_NAMES = {
|
||||
|
||||
|
@ -587,6 +621,14 @@ BAD_TESTER_ASSERTION = {
|
|||
'orgPersonType': 'Tester;'
|
||||
}
|
||||
|
||||
BAD_DEVELOPER_ASSERTION = {
|
||||
'Email': 'evildeveloper@example.org',
|
||||
'UserName': 'Evil',
|
||||
'FirstName': 'Develop',
|
||||
'LastName': 'Account',
|
||||
'orgPersonType': 'Developer'
|
||||
}
|
||||
|
||||
MALFORMED_TESTER_ASSERTION = {
|
||||
'Email': 'testacct@example.com',
|
||||
'UserName': 'testacct',
|
||||
|
@ -598,6 +640,14 @@ MALFORMED_TESTER_ASSERTION = {
|
|||
'tuple': tuple(xrange(5))
|
||||
}
|
||||
|
||||
DEVELOPER_ASSERTION = {
|
||||
'Email': 'developacct@example.com',
|
||||
'UserName': 'developacct',
|
||||
'FirstName': 'Develop',
|
||||
'LastName': 'Account',
|
||||
'orgPersonType': 'Developer'
|
||||
}
|
||||
|
||||
CONTRACTOR_MALFORMED_ASSERTION = {
|
||||
'UserName': 'user',
|
||||
'FirstName': object(),
|
||||
|
|
|
@ -707,6 +707,45 @@ class MappingRuleEngineTests(FederationTests):
|
|||
self.assertEqual(name, user_name)
|
||||
self.assertIn(mapping_fixtures.EMPLOYEE_GROUP_ID, group_ids)
|
||||
|
||||
def test_rule_engine_not_any_of_regex_verify_pass(self):
|
||||
"""Should return group DEVELOPER_GROUP_ID.
|
||||
|
||||
The DEVELOPER_ASSERTION should successfully have a match in
|
||||
MAPPING_DEVELOPER_REGEX. This will test the case where many
|
||||
remote rules must be matched, including a `not_any_of`, with
|
||||
regex set to True.
|
||||
|
||||
"""
|
||||
|
||||
mapping = mapping_fixtures.MAPPING_DEVELOPER_REGEX
|
||||
assertion = mapping_fixtures.DEVELOPER_ASSERTION
|
||||
rp = mapping_utils.RuleProcessor(mapping['rules'])
|
||||
values = rp.process(assertion)
|
||||
|
||||
user_name = assertion.get('UserName')
|
||||
group_ids = values.get('group_ids')
|
||||
name = values.get('name')
|
||||
|
||||
self.assertEqual(user_name, name)
|
||||
self.assertIn(mapping_fixtures.DEVELOPER_GROUP_ID, group_ids)
|
||||
|
||||
def test_rule_engine_not_any_of_regex_verify_fail(self):
|
||||
"""Should deny authorization.
|
||||
|
||||
The email in the assertion will fail the regex test.
|
||||
It is set to reject any @example.org address, but the
|
||||
incoming value is set to evildeveloper@example.org.
|
||||
RuleProcessor should return list of empty group_ids.
|
||||
|
||||
"""
|
||||
|
||||
mapping = mapping_fixtures.MAPPING_DEVELOPER_REGEX
|
||||
assertion = mapping_fixtures.BAD_DEVELOPER_ASSERTION
|
||||
rp = mapping_utils.RuleProcessor(mapping['rules'])
|
||||
mapped_properties = rp.process(assertion)
|
||||
self.assertIsNone(mapped_properties['name'])
|
||||
self.assertListEqual(list(), mapped_properties['group_ids'])
|
||||
|
||||
def _rule_engine_regex_match_and_many_groups(self, assertion):
|
||||
"""Should return group DEVELOPER_GROUP_ID and TESTER_GROUP_ID.
|
||||
|
||||
|
|
Loading…
Reference in New Issue