Mapping which yield no identities should result in ValidationError

Currently mapping produce a bogus "blind" default identity when no
rules match the incoming attributes. This is unnecessary and downright
dangerous. There's absolutely no use case for the "blind" identity.
Furthermore, consumers of mapped properties assumed that the "blind"
identity is legit. This lead to expected failures such as KeyError when they
try to reference the required identity attributes such as user['name'].

We should raise ValidationError if the rules yield no valid identity.
This patch also removed the tests where the bogus "blind" identity is
expected.

Change-Id: I117621673ffc0b4f8e2c48721329daa3b6090327
Closes-Bug: 1557238
This commit is contained in:
guang-yee 2016-03-15 17:29:42 -07:00
parent 196c4ad3f9
commit e5dcb3b4b6
4 changed files with 33 additions and 48 deletions

View File

@ -135,9 +135,14 @@ def handle_unscoped_token(context, auth_payload, auth_context,
user_id = None
try:
mapped_properties, mapping_id = apply_mapping_filter(
identity_provider, protocol, assertion, resource_api,
federation_api, identity_api)
try:
mapped_properties, mapping_id = apply_mapping_filter(
identity_provider, protocol, assertion, resource_api,
federation_api, identity_api)
except exception.ValidationError as e:
# if mapping is either invalid or yield no valid identity,
# it is considered a failed authentication
raise exception.Unauthorized(e)
if is_ephemeral_user(mapped_properties):
unique_id, display_name = (

View File

@ -599,6 +599,15 @@ class RuleProcessor(object):
group_names = list()
groups_by_domain = dict()
# if mapping yield no valid identity values, we should bail right away
# instead of continuing on with a normalized bogus user
if not identity_values:
msg = _("Could not map any federated user properties to identity "
"values. Check debug logs or the mapping used for "
"additional details.")
LOG.warning(msg)
raise exception.ValidationError(msg)
for identity_value in identity_values:
if 'user' in identity_value:
# if a mapping outputs more than one user name, log it

View File

@ -77,17 +77,15 @@ class MappingRuleEngineTests(unit.BaseTestCase):
This will not match since the email in the assertion will fail
the regex test. It is set to match any @example.com address.
But the incoming value is set to eviltester@example.org.
RuleProcessor should return list of empty group_ids.
RuleProcessor should raise ValidationError.
"""
mapping = mapping_fixtures.MAPPING_LARGE
assertion = mapping_fixtures.BAD_TESTER_ASSERTION
rp = mapping_utils.RuleProcessor(FAKE_MAPPING_ID, mapping['rules'])
mapped_properties = rp.process(assertion)
self.assertValidMappedUserObject(mapped_properties)
self.assertIsNone(mapped_properties['user'].get('name'))
self.assertListEqual(list(), mapped_properties['group_ids'])
self.assertRaises(exception.ValidationError,
rp.process,
assertion)
def test_rule_engine_regex_many_groups(self):
"""Should return group CONTRACTOR_GROUP_ID.
@ -203,17 +201,15 @@ class MappingRuleEngineTests(unit.BaseTestCase):
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.
RuleProcessor should yield ValidationError.
"""
mapping = mapping_fixtures.MAPPING_DEVELOPER_REGEX
assertion = mapping_fixtures.BAD_DEVELOPER_ASSERTION
rp = mapping_utils.RuleProcessor(FAKE_MAPPING_ID, mapping['rules'])
mapped_properties = rp.process(assertion)
self.assertValidMappedUserObject(mapped_properties)
self.assertIsNone(mapped_properties['user'].get('name'))
self.assertListEqual(list(), mapped_properties['group_ids'])
self.assertRaises(exception.ValidationError,
rp.process,
assertion)
def _rule_engine_regex_match_and_many_groups(self, assertion):
"""Should return group DEVELOPER_GROUP_ID and TESTER_GROUP_ID.
@ -263,16 +259,15 @@ class MappingRuleEngineTests(unit.BaseTestCase):
Expect RuleProcessor to discard non string object, which
is required for a correct rule match. RuleProcessor will result with
empty list of groups.
ValidationError.
"""
mapping = mapping_fixtures.MAPPING_SMALL
rp = mapping_utils.RuleProcessor(FAKE_MAPPING_ID, mapping['rules'])
assertion = mapping_fixtures.CONTRACTOR_MALFORMED_ASSERTION
mapped_properties = rp.process(assertion)
self.assertValidMappedUserObject(mapped_properties)
self.assertIsNone(mapped_properties['user'].get('name'))
self.assertListEqual(list(), mapped_properties['group_ids'])
self.assertRaises(exception.ValidationError,
rp.process,
assertion)
def test_using_remote_direct_mapping_that_doesnt_exist_fails(self):
"""Test for the correct error when referring to a bad remote match.
@ -466,28 +461,6 @@ class MappingRuleEngineTests(unit.BaseTestCase):
self.assertIsNotNone(mapped_properties)
self.assertValidMappedUserObject(mapped_properties)
def test_create_user_object_with_bad_mapping(self):
"""Test if user object is created even with bad mapping.
User objects will be created by mapping engine always as long as there
is corresponding local rule. This test shows, that even with assertion
where no group names nor ids are matched, but there is 'blind' rule for
mapping user, such object will be created.
In this test MAPPING_EHPEMERAL_USER expects UserName set to jsmith
whereas value from assertion is 'tbo'.
"""
mapping = mapping_fixtures.MAPPING_EPHEMERAL_USER
rp = mapping_utils.RuleProcessor(FAKE_MAPPING_ID, mapping['rules'])
assertion = mapping_fixtures.CONTRACTOR_ASSERTION
mapped_properties = rp.process(assertion)
self.assertIsNotNone(mapped_properties)
self.assertValidMappedUserObject(mapped_properties)
self.assertNotIn('id', mapped_properties['user'])
self.assertNotIn('name', mapped_properties['user'])
def test_set_ephemeral_domain_to_ephemeral_users(self):
"""Test auto assigning service domain to ephemeral users.
@ -645,11 +618,9 @@ class MappingRuleEngineTests(unit.BaseTestCase):
mapping = mapping_fixtures.MAPPING_GROUPS_WHITELIST_PASS_THROUGH
rp = mapping_utils.RuleProcessor(FAKE_MAPPING_ID, 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'])
self.assertRaises(exception.ValidationError,
rp.process,
assertion)
def test_rule_engine_group_ids_mapping_whitelist(self):
"""Test mapping engine when group_ids is explicitly set

View File

@ -1698,7 +1698,7 @@ class FederatedTokenTests(test_v3.RestfulTestCase, FederatedSetupMixin):
def test_issue_unscoped_token_with_remote_unavailable(self):
self.config_fixture.config(group='federation',
remote_id_attribute=self.REMOTE_ID_ATTR)
self.assertRaises(exception.ValidationError,
self.assertRaises(exception.Unauthorized,
self._issue_unscoped_token,
idp=self.IDP_WITH_REMOTE,
environment={