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:
zhiyuan_cai 2015-01-29 13:16:03 +08:00
parent 76342b77cf
commit ac928df1b9
3 changed files with 100 additions and 7 deletions

View File

@ -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:

View File

@ -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(),

View File

@ -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.