import saml2 from saml2 import mdstore from saml2 import md from saml2 import BINDING_HTTP_POST from saml2 import extension_elements_to_elements from saml2.extension import shibmd from saml2.extension import mdui from saml2.extension import idpdisc from saml2.attribute_converter import ac_factory from saml2.saml import NAME_FORMAT_URI from saml2.config import SPConfig, IdPConfig def _eq(l1,l2): return set(l1) == set(l2) SP = { "name" : "Rolands SP", "description": "One of the best SPs in business", "service": { "sp": { "endpoints": { "single_logout_service" : ["http://localhost:8087/logout"], "assertion_consumer_service" : [{"location":"http://localhost:8087/", "binding":BINDING_HTTP_POST},] }, "required_attributes": ["sn", "givenName", "mail"], "optional_attributes": ["title"], "idp": { "" : "https://example.com/saml2/idp/SSOService.php", }, } }, "metadata": { "local": ["foo.xml"], }, "attribute_map_dir" : "attributemaps", } IDP = { "name" : "Rolands IdP", "service": { "idp": { "endpoints": { "single_sign_on_service" : ["http://localhost:8088/sso"], }, "policy": { "default": { "lifetime": {"minutes":15}, "attribute_restrictions": None, # means all I have "name_form": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri", }, "urn:mace:example.com:saml:roland:sp": { "lifetime": {"minutes": 5}, "nameid_format": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", } }, "scope": ["example.org"], "ui_info": { "privacy_statement_url": "http://example.com/saml2/privacyStatement.html", "information_url": "http://example.com/saml2/info.html", "logo": { "height": "40", "width" : "30", "text": "http://example.com/logo.jpg" }, "display_name": "Example Co.", "description" : {"text":"Exempel bolag","lang":"se"}, "keywords": {"lang":"en", "text":["foo", "bar"]} }, } }, "metadata": { "local": ["bar.xml"], }, } def test_org_1(): desc = { "name": [("Example Company","en"), ("Exempel AB","se"), "Example",], "display_name": ["Example AS", ("Voorbeeld AZ", "")], "url": [("http://example.com","en")], } org = metadata.do_organization_info(desc) print(org) assert isinstance(org, md.Organization) print(org.keyswv()) assert _eq(org.keyswv(), ['organization_name', 'organization_display_name','organization_url']) assert len(org.organization_name) == 3 assert len(org.organization_display_name) == 2 assert len(org.organization_url) == 1 def test_org_2(): desc = { "name": [("Example Company","en"), ("Exempel AB","se"), "Example",], "display_name": "Example AS", "url": ("http://example.com","en"), } org = metadata.do_organization_info(desc) print(org) assert _eq(org.keyswv(), ['organization_name', 'organization_display_name','organization_url']) assert len(org.organization_name) == 3 assert len(org.organization_display_name) == 1 assert org.organization_display_name[0].text == 'Example AS' assert len(org.organization_url) == 1 assert isinstance(org.organization_url[0], md.OrganizationURL) assert org.organization_url[0].lang == "en" assert org.organization_url[0].text == 'http://example.com' def test_org_3(): desc = { "display_name": ["Rolands SAML"] } org = metadata.do_organization_info(desc) assert _eq(org.keyswv(), ['organization_display_name']) assert len(org.organization_display_name) == 1 def test_contact_0(): conf = [{ "given_name":"Roland", "sur_name": "Hedberg", "telephone_number": "+46 70 100 00 00", "email_address": ["foo@eample.com", "foo@example.org"], "contact_type": "technical" }] contact_person = metadata.do_contact_person_info(conf) assert _eq(contact_person[0].keyswv(), ['given_name', 'sur_name', 'contact_type', 'telephone_number', "email_address"]) print(contact_person[0]) person = contact_person[0] assert person.contact_type == "technical" assert isinstance(person.given_name, md.GivenName) assert person.given_name.text == "Roland" assert isinstance(person.sur_name, md.SurName) assert person.sur_name.text == "Hedberg" assert isinstance(person.telephone_number[0], md.TelephoneNumber) assert person.telephone_number[0].text == "+46 70 100 00 00" assert len(person.email_address) == 2 assert isinstance(person.email_address[0], md.EmailAddress) assert person.email_address[0].text == "foo@eample.com" def test_do_endpoints(): eps = metadata.do_endpoints(SP["service"]["sp"]["endpoints"], metadata.ENDPOINTS["sp"]) print(eps) assert _eq(eps.keys(), ["assertion_consumer_service", "single_logout_service"]) assert len(eps["single_logout_service"]) == 1 sls = eps["single_logout_service"][0] assert sls.location == "http://localhost:8087/logout" assert sls.binding == BINDING_HTTP_POST assert len(eps["assertion_consumer_service"]) == 1 acs = eps["assertion_consumer_service"][0] assert acs.location == "http://localhost:8087/" assert acs.binding == BINDING_HTTP_POST assert "artifact_resolution_service" not in eps assert "manage_name_id_service" not in eps def test_required_attributes(): attrconverters = ac_factory("../tests/attributemaps") ras = metadata.do_requested_attribute( SP["service"]["sp"]["required_attributes"], attrconverters, is_required="true") assert len(ras) == len(SP["service"]["sp"]["required_attributes"]) print(ras[0]) assert ras[0].name == 'urn:oid:2.5.4.4' assert ras[0].name_format == NAME_FORMAT_URI assert ras[0].is_required == "true" def test_optional_attributes(): attrconverters = ac_factory("../tests/attributemaps") ras = metadata.do_requested_attribute( SP["service"]["sp"]["optional_attributes"], attrconverters) assert len(ras) == len(SP["service"]["sp"]["optional_attributes"]) print(ras[0]) assert ras[0].name == 'urn:oid:2.5.4.12' assert ras[0].name_format == NAME_FORMAT_URI assert ras[0].is_required == "false" def test_do_sp_sso_descriptor(): conf = SPConfig().load(SP) spsso = metadata.do_spsso_descriptor(conf) assert isinstance(spsso, md.SPSSODescriptor) assert _eq(spsso.keyswv(), ['authn_requests_signed', 'attribute_consuming_service', 'single_logout_service', 'protocol_support_enumeration', 'assertion_consumer_service', 'want_assertions_signed']) assert spsso.authn_requests_signed == "false" assert spsso.want_assertions_signed == "true" assert len (spsso.attribute_consuming_service) == 1 acs = spsso.attribute_consuming_service[0] print(acs.keyswv()) assert _eq(acs.keyswv(), ['requested_attribute', 'service_name', 'service_description', 'index']) assert acs.service_name[0].text == SP["name"] assert acs.service_description[0].text == SP["description"] assert len(acs.requested_attribute) == 4 assert acs.requested_attribute[0].friendly_name == "sn" assert acs.requested_attribute[0].name == 'urn:oid:2.5.4.4' assert acs.requested_attribute[0].name_format == NAME_FORMAT_URI assert acs.requested_attribute[0].is_required == "true" def test_do_sp_sso_descriptor_2(): SP["service"]["sp"]["discovery_response"] = "http://example.com/sp/ds" conf = SPConfig().load(SP) spsso = metadata.do_spsso_descriptor(conf) assert isinstance(spsso, md.SPSSODescriptor) print(spsso.keyswv()) assert _eq(spsso.keyswv(), ['authn_requests_signed', 'attribute_consuming_service', 'single_logout_service', 'protocol_support_enumeration', 'assertion_consumer_service', 'want_assertions_signed', 'extensions']) exts = spsso.extensions.extension_elements assert len(exts) == 1 print(exts) idpd = saml2.extension_element_to_element(exts[0], idpdisc.ELEMENT_FROM_STRING, namespace=idpdisc.NAMESPACE) print(idpd) assert idpd.location == "http://example.com/sp/ds" assert idpd.index == "0" assert idpd.binding == "urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" def test_entity_description(): #confd = eval(open("../tests/server.config").read()) confd = SPConfig().load_file("server_conf") print(confd.attribute_converters) entd = metadata.entity_descriptor(confd) assert entd is not None print(entd.keyswv()) assert _eq(entd.keyswv(), ['valid_until', 'entity_id', 'contact_person', 'spsso_descriptor', 'organization']) print(entd) assert entd.entity_id == "urn:mace:example.com:saml:roland:sp" def test_do_idp_sso_descriptor(): conf = IdPConfig().load(IDP) idpsso = metadata.do_idpsso_descriptor(conf) assert isinstance(idpsso, md.IDPSSODescriptor) assert _eq(idpsso.keyswv(), ['protocol_support_enumeration', 'single_sign_on_service', 'want_authn_requests_signed', "extensions"]) exts = idpsso.extensions.extension_elements assert len(exts) == 2 print(exts) inst = saml2.extension_element_to_element(exts[0], shibmd.ELEMENT_FROM_STRING, namespace=shibmd.NAMESPACE) assert isinstance(inst, shibmd.Scope) assert inst.text == "example.org" assert inst.regexp == "false" uiinfo = saml2.extension_element_to_element(exts[1], mdui.ELEMENT_FROM_STRING, namespace=mdui.NAMESPACE) assert uiinfo assert _eq(uiinfo.keyswv(), ['display_name', 'description', 'information_url', 'privacy_statement_url', 'keywords', 'logo']) assert len(uiinfo.privacy_statement_url) == 1 assert uiinfo.privacy_statement_url[0].text == "http://example.com/saml2/privacyStatement.html" assert len(uiinfo.description) == 1 assert uiinfo.description[0].text == "Exempel bolag" assert uiinfo.description[0].lang == "se" res = extension_elements_to_elements(exts,[shibmd, mdui]) assert len(res) == 2 # one is a shibmd.Scope instance and the other a mdui.UIInfo instance if isinstance(res[0], shibmd.Scope): assert isinstance(res[1], mdui.UIInfo) elif isinstance(res[1], shibmd.Scope): assert isinstance(res[0], mdui.UIInfo) found = idpsso.extensions.find_extensions(mdui.UIInfo.c_tag, mdui.NAMESPACE) assert len(found) == 1 elem = idpsso.extensions.extensions_as_elements(mdui.UIInfo.c_tag, mdui) assert len(elem) == 1 assert isinstance(elem[0], mdui.UIInfo)