diff --git a/src/saml2/assertion.py b/src/saml2/assertion.py index ad08345..86def2e 100644 --- a/src/saml2/assertion.py +++ b/src/saml2/assertion.py @@ -78,7 +78,8 @@ def _match(attr, ava): return None -def filter_on_attributes(ava, required=None, optional=None, acs=None): +def filter_on_attributes(ava, required=None, optional=None, acs=None, + fail_on_unfulfilled_requirements=True): """ Filter :param ava: An attribute value assertion as a dictionary @@ -86,6 +87,8 @@ def filter_on_attributes(ava, required=None, optional=None, acs=None): required :param optional: list of RequestedAttribute instances defined to be optional + :param fail_on_unfulfilled_requirements: If required attributes + are missing fail or fail not depending on this parameter. :return: The modified attribute value assertion """ res = {} @@ -116,7 +119,7 @@ def filter_on_attributes(ava, required=None, optional=None, acs=None): values = [] res[_fn] = _filter_values(ava[_fn], values, True) continue - else: + elif fail_on_unfulfilled_requirements: desc = "Required attribute missing: '%s' (%s)" % (attr["name"], _name) raise MissingValue(desc) @@ -434,6 +437,16 @@ class Policy(object): return self.get("attribute_restrictions", sp_entity_id) + def get_fail_on_missing_requested(self, sp_entity_id): + """ Return the whether the IdP should should fail if the SPs + requested attributes could not be found. + + :param sp_entity_id: The SP entity ID + :return: The restrictions + """ + + return self.get("fail_on_missing_requested", sp_entity_id, True) + def entity_category_attributes(self, ec): if not self._restrictions: return None @@ -492,7 +505,9 @@ class Policy(object): if required or optional: logger.debug("required: %s, optional: %s" % (required, optional)) - ava = filter_on_attributes(ava, required, optional, self.acs) + ava = filter_on_attributes( + ava, required, optional, self.acs, + self.get_fail_on_missing_requested(sp_entity_id)) return ava diff --git a/src/saml2/config.py b/src/saml2/config.py index 1a96f16..4dc6f21 100644 --- a/src/saml2/config.py +++ b/src/saml2/config.py @@ -269,7 +269,8 @@ class Config(object): acs = ac_factory() if not acs: - raise ConfigurationError("No attribute converters, something is wrong!!") + raise ConfigurationError( + "No attribute converters, something is wrong!!") _acs = self.getattr("attribute_converters", typ) if _acs: diff --git a/tests/test_20_assertion.py b/tests/test_20_assertion.py index 4c65438..820b2da 100644 --- a/tests/test_20_assertion.py +++ b/tests/test_20_assertion.py @@ -172,6 +172,8 @@ def test_ava_filter_2(): "surName": "Jeter", "mail": "derek@example.com"} + # mail removed because it doesn't match the regular expression + # So this should fail. raises(MissingValue, policy.filter, ava, 'urn:mace:umu.se:saml:roland:sp', None, [mail], [gn, sn]) @@ -183,6 +185,44 @@ def test_ava_filter_2(): None, [gn, sn, mail]) +def test_ava_filter_dont_fail(): + conf = { + "default": { + "lifetime": {"minutes": 15}, + "attribute_restrictions": None, # means all I have + }, + "urn:mace:umu.se:saml:roland:sp": { + "lifetime": {"minutes": 5}, + "attribute_restrictions": { + "givenName": None, + "surName": None, + "mail": [".*@.*\.umu\.se"], + }, + "fail_on_missing_requested": False + }} + + policy = Policy(conf) + + ava = {"givenName": "Derek", + "surName": "Jeter", + "mail": "derek@example.com"} + + # mail removed because it doesn't match the regular expression + # So it should fail if the 'fail_on_ ...' flag wasn't set + _ava = policy.filter(ava,'urn:mace:umu.se:saml:roland:sp', None, + [mail], [gn, sn]) + + assert _ava + + ava = {"givenName": "Derek", + "surName": "Jeter"} + + # it wasn't there to begin with + _ava = policy.filter(ava, 'urn:mace:umu.se:saml:roland:sp', + None, [gn, sn, mail]) + + assert _ava + def test_filter_attribute_value_assertions_0(AVA): p = Policy({ "default": { @@ -802,4 +842,4 @@ def test_assertion_with_authn_instant(): if __name__ == "__main__": - test_assertion_2() + test_ava_filter_dont_fail()