#!/usr/bin/env python from attribute_statement_data import * from pathutils import full_path from saml2 import attribute_converter from saml2 import saml from saml2.attribute_converter import AttributeConverter from saml2.attribute_converter import AttributeConverterNOOP from saml2.attribute_converter import from_local from saml2.attribute_converter import to_local import saml2.attributemaps.saml_uri as saml_map from saml2.saml import attribute_from_string from saml2.saml import attribute_statement_from_string def _eq(l1, l2): return set(l1) == set(l2) BASIC_NF = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic" URI_NF = "urn:oasis:names:tc:SAML:2.0:attrname-format:uri" SAML1 = "urn:mace:shibboleth:1.0:attributeNamespace:uri" def test_default(): acs = attribute_converter.ac_factory() assert acs class TestAC: def setup_class(self): self.acs = attribute_converter.ac_factory(full_path("attributemaps")) def test_setup(self): print(self.acs) assert len(self.acs) == 3 assert _eq([a.name_format for a in self.acs], [BASIC_NF, URI_NF, SAML1]) def test_ava_fro_1(self): ats = saml.attribute_statement_from_string(STATEMENT1) # print(ats) ava = None for ac in self.acs: try: ava = ac.fro(ats) except attribute_converter.UnknownNameFormat: pass # break if we have something if ava: break print(ava.keys()) assert _eq( ava.keys(), [ "givenName", "displayName", "uid", "eduPersonNickname", "street", "eduPersonScopedAffiliation", "employeeType", "eduPersonAffiliation", "eduPersonPrincipalName", "sn", "postalCode", "physicalDeliveryOfficeName", "ou", "eduPersonTargetedID", "cn", ], ) def test_ava_fro_2(self): ats = saml.attribute_statement_from_string(STATEMENT2) # print(ats) ava = {} for ac in self.acs: ava.update(ac.fro(ats)) print(ava.keys()) assert _eq(ava.keys(), ["eduPersonEntitlement", "eduPersonAffiliation", "uid", "mail", "givenName", "sn"]) def test_to_attrstat_1(self): ava = {"givenName": "Roland", "sn": "Hedberg"} statement = attribute_converter.from_local(self.acs, ava, BASIC_NF) assert statement is not None assert len(statement) == 2 a0 = statement[0] a1 = statement[1] if a0.friendly_name == "sn": assert a0.name == "urn:mace:dir:attribute-def:sn" assert a0.name_format == BASIC_NF assert a1.friendly_name == "givenName" assert a1.name == "urn:mace:dir:attribute-def:givenName" assert a1.name_format == BASIC_NF elif a0.friendly_name == "givenName": assert a0.name == "urn:mace:dir:attribute-def:givenName" assert a0.name_format == BASIC_NF assert a1.friendly_name == "sn" assert a1.name == "urn:mace:dir:attribute-def:sn" assert a1.name_format == BASIC_NF else: assert False def test_to_attrstat_2(self): ava = {"givenName": "Roland", "surname": "Hedberg"} statement = attribute_converter.from_local(self.acs, ava, URI_NF) assert len(statement) == 2 a0 = statement[0] a1 = statement[1] if a0.friendly_name == "surname": assert a0.name == "urn:oid:2.5.4.4" assert a0.name_format == URI_NF assert a1.friendly_name == "givenName" assert a1.name == "urn:oid:2.5.4.42" assert a1.name_format == URI_NF elif a0.friendly_name == "givenName": assert a0.name == "urn:oid:2.5.4.42" assert a0.name_format == URI_NF assert a1.friendly_name == "surname" assert a1.name == "urn:oid:2.5.4.4" assert a1.name_format == URI_NF else: print(a0.friendly_name) assert False def test_to_local_name(self): attr = [ saml.Attribute( friendly_name="surName", name="urn:oid:2.5.4.4", name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri", ), saml.Attribute( friendly_name="efternamn", name="urn:oid:2.5.4.42", name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri", ), saml.Attribute( friendly_name="titel", name="urn:oid:2.5.4.12", name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri", ), ] lan = [attribute_converter.to_local_name(self.acs, a) for a in attr] assert _eq(lan, ["sn", "givenName", "title"]) def test_to_local_name_from_unspecified(self): _xml = """ foo@bar.com """ attr = attribute_statement_from_string(_xml) ava = attribute_converter.to_local(self.acs, attr) assert _eq(list(ava.keys()), ["EmailAddress"]) def test_to_local_name_from_basic(self): attr = [ saml.Attribute( name="urn:mace:dir:attribute-def:eduPersonPrimaryOrgUnitDN", name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:basic", ) ] lan = [attribute_converter.to_local_name(self.acs, a) for a in attr] assert _eq(lan, ["eduPersonPrimaryOrgUnitDN"]) def test_to_and_for(self): ava = {"givenName": "Roland", "surname": "Hedberg"} basic_ac = [a for a in self.acs if a.name_format == BASIC_NF][0] attr_state = saml.AttributeStatement(basic_ac.to_(ava)) oava = basic_ac.fro(attr_state) assert _eq(ava.keys(), oava.keys()) def test_unspecified_name_format(self): ats = saml.attribute_statement_from_string(STATEMENT4) ava = to_local(self.acs, ats) assert ava == {"user_id": ["bob"], "NameID": ["bobsnameagain"]} def test_mixed_attributes_1(self): ats = saml.attribute_statement_from_string(STATEMENT_MIXED) ava = to_local(self.acs, ats) assert ava == { "eduPersonAffiliation": ["staff"], "givenName": ["Roland"], "sn": ["Hedberg"], "uid": ["demouser"], "user_id": ["bob"], } # Allow unknown ava = to_local(self.acs, ats, True) assert ava == { "eduPersonAffiliation": ["staff"], "givenName": ["Roland"], "sn": ["Hedberg"], "urn:oid:2.16.756.1.2.5.1.1.5": ["others"], "uid": ["demouser"], "urn:example:com:foo": ["Thing"], "user_id": ["bob"], } def test_adjust_with_only_from_defined(self): attr_conv = AttributeConverter() attr_conv._fro = {"id1": "name1", "id2": "name2"} attr_conv.adjust() assert attr_conv._to is not None def test_adjust_with_only_to_defined(self): attr_conv = AttributeConverter() attr_conv._to = {"id1": "name1", "id2": "name2"} attr_conv.adjust() assert attr_conv._fro is not None def test_adjust_with_no_mapping_defined(self): attr_conv = AttributeConverter() attr_conv.adjust() assert attr_conv._fro is None and attr_conv._to is None def test_from_local_nest_eduPersonTargetedID_in_NameID(self): ava = {"edupersontargetedid": ["test value1", "test value2"]} attributes = from_local(self.acs, ava, URI_NF) assert len(attributes) == 1 assert len(attributes[0].attribute_value) == 2 assert attributes[0].attribute_value[0].extension_elements[0].text == "test value1" assert attributes[0].attribute_value[1].extension_elements[0].text == "test value2" def test_from_local_eduPersonTargetedID_with_qualifiers(self): IDP_ENTITY_ID = "https://some.org/idp" SP_ENTITY_ID = "https://some.org/sp" ava = { "edupersontargetedid": [ { "text": "test value1", "NameQualifier": IDP_ENTITY_ID, "SPNameQualifier": SP_ENTITY_ID, } ] } attributes = from_local(self.acs, ava, URI_NF) assert len(attributes) == 1 element = attributes[0].attribute_value[0].extension_elements[0] assert element.text == "test value1" assert element.attributes["NameQualifier"] == IDP_ENTITY_ID assert element.attributes["SPNameQualifier"] == SP_ENTITY_ID def test_noop_attribute_conversion(): ava = {"urn:oid:2.5.4.4": "Roland", "urn:oid:2.5.4.42": "Hedberg"} aconv = AttributeConverterNOOP(URI_NF) res = aconv.to_(ava) print(res) assert len(res) == 2 for attr in res: assert len(attr.attribute_value) == 1 if attr.name == "urn:oid:2.5.4.42": assert attr.name_format == URI_NF assert attr.attribute_value[0].text == "Hedberg" elif attr.name == "urn:oid:2.5.4.4": assert attr.name_format == URI_NF assert attr.attribute_value[0].text == "Roland" class BuilderAVA: def __init__(self, name, friendly_name, name_format): template = """ uu.se """ self.ava = template.format(attr_name=name, attr_friendly_name=friendly_name, attr_name_format=name_format) class TestSchac: def test(self): failures = 0 friendly_name = "schacHomeOrganization" ava_schac = BuilderAVA("urn:oid:1.3.6.1.4.1.25178.1.2.9", friendly_name, saml_map.MAP["identifier"]) attr = attribute_from_string(ava_schac.ava) acs = attribute_converter.ac_factory() for ac in acs: try: res = ac.ava_from(attr) except KeyError: failures += 1 else: assert res[0] == "schacHomeOrganization" assert failures != len(acs) class TestEIDAS: def test(self): failures = 0 friendly_name = "PersonIdentifier" ava_eidas = BuilderAVA(saml_map.EIDAS_NATURALPERSON + friendly_name, friendly_name, saml_map.MAP["identifier"]) attr = attribute_from_string(ava_eidas.ava) acs = attribute_converter.ac_factory() for ac in acs: try: res = ac.ava_from(attr) except KeyError: failures += 1 else: assert res[0] == friendly_name assert failures != len(acs) if __name__ == "__main__": t = TestAC() t.setup_class() t.test_to_local_name_from_unspecified()