#!/usr/bin/env python from saml2 import attribute_converter, saml from attribute_statement_data import * from pathutils import full_path from saml2.attribute_converter import AttributeConverterNOOP, from_local from saml2.attribute_converter import AttributeConverter from saml2.attribute_converter import to_local from saml2.saml import attribute_from_string, name_id_from_string, NameID, NAMEID_FORMAT_PERSISTENT from saml2.saml import attribute_statement_from_string import saml2.attributemaps.saml_uri as saml_map 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()