Ejemplo n.º 1
0
    def test_saml_mirror_frontend_with_saml_backend_with_multiple_target_providers(
            self, satosa_config_dict, idp_conf, saml_mirror_frontend_config,
            saml_backend_config):
        idp_conf2 = copy.deepcopy(idp_conf)
        idp_conf2["entityid"] = "https://idp2.example.com"
        satosa_config_dict["FRONTEND_MODULES"] = [saml_mirror_frontend_config]
        saml_backend_config["config"]["sp_config"]["metadata"] = {
            "inline": [
                create_metadata_from_config_dict(idp_conf),
                create_metadata_from_config_dict(idp_conf2)
            ]
        }
        satosa_config_dict["BACKEND_MODULES"] = [saml_backend_config]
        satosa_config = SATOSAConfig(satosa_config_dict)
        frontend_metadata, backend_metadata = create_entity_descriptors(
            satosa_config)

        assert len(frontend_metadata) == 1
        assert len(frontend_metadata[saml_mirror_frontend_config["name"]]) == 2

        entity_descriptors = frontend_metadata[
            saml_mirror_frontend_config["name"]]
        for target_entity_id in [idp_conf["entityid"], idp_conf2["entityid"]]:
            encoded_target_entity_id = urlsafe_b64encode(
                target_entity_id.encode("utf-8")).decode("utf-8")
            self.assert_single_sign_on_endpoints_for_saml_mirror_frontend(
                entity_descriptors, encoded_target_entity_id,
                saml_mirror_frontend_config, [saml_backend_config["name"]])
        assert len(backend_metadata) == 1
        self.assert_assertion_consumer_service_endpoints_for_saml_backend(
            backend_metadata[saml_backend_config["name"]][0],
            saml_backend_config)
Ejemplo n.º 2
0
    def setup_for_authn_req(self, context, idp_conf, sp_conf, nameid_format=None, relay_state="relay_state",
                            internal_attributes=INTERNAL_ATTRIBUTES, extra_config={}):
        config = {"idp_config": idp_conf, "endpoints": ENDPOINTS}
        config.update(extra_config)
        sp_metadata_str = create_metadata_from_config_dict(sp_conf)
        idp_conf["metadata"]["inline"] = [sp_metadata_str]

        base_url = self.construct_base_url_from_entity_id(idp_conf["entityid"])
        samlfrontend = SAMLFrontend(lambda ctx, internal_req: (ctx, internal_req),
                                    internal_attributes, config, base_url, "saml_frontend")
        samlfrontend.register_endpoints(["saml"])

        idp_metadata_str = create_metadata_from_config_dict(samlfrontend.idp_config)
        sp_conf["metadata"]["inline"].append(idp_metadata_str)

        fakesp = FakeSP(SPConfig().load(sp_conf, metadata_construction=False))
        destination, auth_req = fakesp.make_auth_req(samlfrontend.idp_config["entityid"], nameid_format, relay_state)
        context.request = auth_req
        tmp_dict = {}
        for val in context.request:
            if isinstance(context.request[val], list):
                tmp_dict[val] = context.request[val][0]
            else:
                tmp_dict[val] = context.request[val]
        context.request = tmp_dict

        return samlfrontend
Ejemplo n.º 3
0
    def setup_for_authn_req(self, idp_conf, sp_conf, nameid_format):
        base = self.construct_base_url_from_entity_id(idp_conf["entityid"])
        config = {"idp_config": idp_conf, "endpoints": ENDPOINTS, "base": base,
                  "state_id": "state_id"}
        sp_metadata_str = create_metadata_from_config_dict(sp_conf)
        idp_conf["metadata"]["inline"] = [sp_metadata_str]

        samlfrontend = SamlFrontend(lambda context, internal_req: (context, internal_req),
                                    INTERNAL_ATTRIBUTES, config)
        samlfrontend.register_endpoints(["saml"])

        idp_metadata_str = create_metadata_from_config_dict(samlfrontend.config)
        sp_conf["metadata"]["inline"].append(idp_metadata_str)

        fakesp = FakeSP(None, config=SPConfig().load(sp_conf, metadata_construction=False))
        context = Context()
        context.state = State()
        context.request = parse.parse_qs(
                urlparse(fakesp.make_auth_req(samlfrontend.config["entityid"], nameid_format)).query)
        tmp_dict = {}
        for val in context.request:
            if isinstance(context.request[val], list):
                tmp_dict[val] = context.request[val][0]
            else:
                tmp_dict[val] = context.request[val]
        context.request = tmp_dict

        return context, samlfrontend
Ejemplo n.º 4
0
    def test_saml_mirror_frontend_with_saml_backend_with_multiple_target_providers(self, satosa_config_dict, idp_conf,
                                                                                   saml_mirror_frontend_config,
                                                                                   saml_backend_config):
        idp_conf2 = copy.deepcopy(idp_conf)
        idp_conf2["entityid"] = "https://idp2.example.com"
        satosa_config_dict["FRONTEND_MODULES"] = [saml_mirror_frontend_config]
        saml_backend_config["config"]["sp_config"]["metadata"] = {"inline": [create_metadata_from_config_dict(idp_conf),
                                                                             create_metadata_from_config_dict(
                                                                                 idp_conf2)]}
        satosa_config_dict["BACKEND_MODULES"] = [saml_backend_config]
        satosa_config = SATOSAConfig(satosa_config_dict)
        frontend_metadata, backend_metadata = create_entity_descriptors(satosa_config)

        assert len(frontend_metadata) == 1
        assert len(frontend_metadata[saml_mirror_frontend_config["name"]]) == 2

        entity_descriptors = frontend_metadata[saml_mirror_frontend_config["name"]]
        for target_entity_id in [idp_conf["entityid"], idp_conf2["entityid"]]:
            encoded_target_entity_id = urlsafe_b64encode(target_entity_id.encode("utf-8")).decode("utf-8")
            self.assert_single_sign_on_endpoints_for_saml_mirror_frontend(entity_descriptors, encoded_target_entity_id,
                                                                          saml_mirror_frontend_config,
                                                                          [saml_backend_config["name"]])
        assert len(backend_metadata) == 1
        self.assert_assertion_consumer_service_endpoints_for_saml_backend(
            backend_metadata[saml_backend_config["name"]][0],
            saml_backend_config)
Ejemplo n.º 5
0
    def setup_for_authn_req(self, context, idp_conf, sp_conf, nameid_format=None, relay_state="relay_state",
                            internal_attributes=INTERNAL_ATTRIBUTES, extra_config={},
                            subject=None):
        config = {"idp_config": idp_conf, "endpoints": ENDPOINTS}
        config.update(extra_config)
        sp_metadata_str = create_metadata_from_config_dict(sp_conf)
        idp_conf["metadata"]["inline"] = [sp_metadata_str]

        base_url = self.construct_base_url_from_entity_id(idp_conf["entityid"])
        samlfrontend = SAMLFrontend(lambda ctx, internal_req: (ctx, internal_req),
                                    internal_attributes, config, base_url, "saml_frontend")
        samlfrontend.register_endpoints(["saml"])

        idp_metadata_str = create_metadata_from_config_dict(samlfrontend.idp_config)
        sp_conf["metadata"]["inline"].append(idp_metadata_str)

        fakesp = FakeSP(SPConfig().load(sp_conf, metadata_construction=False))
        destination, auth_req = fakesp.make_auth_req(
            samlfrontend.idp_config["entityid"],
            nameid_format,
            relay_state,
            subject=subject,
        )
        context.request = auth_req
        tmp_dict = {}
        for val in context.request:
            if isinstance(context.request[val], list):
                tmp_dict[val] = context.request[val][0]
            else:
                tmp_dict[val] = context.request[val]
        context.request = tmp_dict

        return samlfrontend
Ejemplo n.º 6
0
def setup_test_config(sp_conf, idp_conf):
    idp_metadata_str = create_metadata_from_config_dict(idp_conf)
    sp_conf["metadata"]["inline"].append(idp_metadata_str)
    idp2_config = idp_conf.copy()
    idp2_config["entityid"] = "just_an_extra_idp"
    idp_metadata_str2 = create_metadata_from_config_dict(idp2_config)
    sp_conf["metadata"]["inline"].append(idp_metadata_str2)

    sp_metadata_str = create_metadata_from_config_dict(sp_conf)
    idp_conf["metadata"]["inline"] = [sp_metadata_str]
Ejemplo n.º 7
0
def setup_test_config(sp_conf, idp_conf):
    idp_metadata_str = create_metadata_from_config_dict(idp_conf)
    sp_conf["metadata"]["inline"].append(idp_metadata_str)
    idp2_config = idp_conf.copy()
    idp2_config["entityid"] = "just_an_extra_idp"
    idp_metadata_str2 = create_metadata_from_config_dict(idp2_config)
    sp_conf["metadata"]["inline"].append(idp_metadata_str2)

    sp_metadata_str = create_metadata_from_config_dict(sp_conf)
    idp_conf["metadata"]["inline"] = [sp_metadata_str]
Ejemplo n.º 8
0
    def test_get_metadata_desc_with_logo_without_lang(self, sp_conf, idp_conf):
        # add logo without 'lang'
        idp_conf["service"]["idp"]["ui_info"]["logo"] = [{"text": "https://idp.example.com/static/logo.png",
                                                          "width": "120", "height": "60"}]

        sp_conf["metadata"]["inline"] = [create_metadata_from_config_dict(idp_conf)]
        # instantiate new backend, with a single backing IdP
        samlbackend = SAMLBackend(None, INTERNAL_ATTRIBUTES, {"sp_config": sp_conf}, "base_url", "saml_backend")
        entity_descriptions = samlbackend.get_metadata_desc()

        assert len(entity_descriptions) == 1

        idp_desc = entity_descriptions[0].to_dict()

        assert idp_desc["entityid"] == urlsafe_b64encode(idp_conf["entityid"].encode("utf-8")).decode("utf-8")
        assert idp_desc["contact_person"] == idp_conf["contact_person"]

        assert idp_desc["organization"]["name"][0] == tuple(idp_conf["organization"]["name"][0])
        assert idp_desc["organization"]["display_name"][0] == tuple(idp_conf["organization"]["display_name"][0])
        assert idp_desc["organization"]["url"][0] == tuple(idp_conf["organization"]["url"][0])

        expected_ui_info = idp_conf["service"]["idp"]["ui_info"]
        ui_info = idp_desc["service"]["idp"]["ui_info"]
        assert ui_info["display_name"] == expected_ui_info["display_name"]
        assert ui_info["description"] == expected_ui_info["description"]
        assert ui_info["logo"] == expected_ui_info["logo"]
Ejemplo n.º 9
0
    def test_use_of_disco_or_redirect_to_idp_when_using_mdq_and_forceauthn_is_set_1(
        self, context, sp_conf, idp_conf
    ):
        sp_conf["metadata"]["inline"] = [create_metadata_from_config_dict(idp_conf)]
        sp_conf["metadata"]["mdq"] = ["https://mdq.example.com"]

        context.decorate(Context.KEY_FORCE_AUTHN, "1")
        context.state[Context.KEY_MEMORIZED_IDP] = idp_conf["entityid"]

        backend_conf = {
            SAMLBackend.KEY_SP_CONFIG: sp_conf,
            SAMLBackend.KEY_DISCO_SRV: DISCOSRV_URL,
            SAMLBackend.KEY_MEMORIZE_IDP: True,
            SAMLBackend.KEY_MIRROR_FORCE_AUTHN: True,
        }
        samlbackend = SAMLBackend(
            None, INTERNAL_ATTRIBUTES, backend_conf, "base_url", "saml_backend"
        )
        resp = samlbackend.start_auth(context, InternalData())
        assert_redirect_to_discovery_server(resp, sp_conf, DISCOSRV_URL)

        backend_conf[SAMLBackend.KEY_USE_MEMORIZED_IDP_WHEN_FORCE_AUTHN] = True
        samlbackend = SAMLBackend(
            None, INTERNAL_ATTRIBUTES, backend_conf, "base_url", "saml_backend"
        )
        resp = samlbackend.start_auth(context, InternalData())
        assert_redirect_to_idp(resp, idp_conf)
Ejemplo n.º 10
0
    def test_respect_sp_entity_categories(self, context, entity_category, entity_category_module, expected_attributes,
                                          idp_conf, sp_conf, internal_response):
        idp_metadata_str = create_metadata_from_config_dict(idp_conf)
        idp_conf["service"]["idp"]["policy"]["default"]["entity_categories"] = [entity_category_module]
        if all(entity_category):  # don't insert empty entity category
            sp_conf["entity_category"] = entity_category
        if entity_category == [COCO]:
            sp_conf["service"]["sp"]["required_attributes"] = expected_attributes

        expected_attributes_in_all_entity_categories = list(
            itertools.chain(swamid.RELEASE[""], edugain.RELEASE[COCO], refeds.RELEASE[RESEARCH_AND_SCHOLARSHIP],
                            swamid.RELEASE[(RESEARCH_AND_EDUCATION, EU)], swamid.RELEASE[(RESEARCH_AND_EDUCATION, HEI)],
                            swamid.RELEASE[(RESEARCH_AND_EDUCATION, NREN)], swamid.RELEASE[SFS_1993_1153]))
        attribute_mapping = {}
        for expected_attribute in expected_attributes_in_all_entity_categories:
            attribute_mapping[expected_attribute.lower()] = {"saml": [expected_attribute]}

        internal_attributes = dict(attributes=attribute_mapping)
        samlfrontend = self.setup_for_authn_req(context, idp_conf, sp_conf, internal_attributes=internal_attributes)

        user_attributes = {k: "foo" for k in expected_attributes_in_all_entity_categories}
        internal_response.attributes = AttributeMapper(internal_attributes).to_internal("saml", user_attributes)
        internal_response.requester = sp_conf["entityid"]

        resp = self.get_auth_response(samlfrontend, context, internal_response, sp_conf, idp_metadata_str)
        assert Counter(resp.ava.keys()) == Counter(expected_attributes)
Ejemplo n.º 11
0
    def test_get_metadata_desc(self, sp_conf, idp_conf):
        sp_conf["metadata"]["inline"] = [
            create_metadata_from_config_dict(idp_conf)
        ]
        # instantiate new backend, with a single backing IdP
        samlbackend = SAMLBackend(None, INTERNAL_ATTRIBUTES,
                                  {"sp_config": sp_conf}, "base_url",
                                  "saml_backend")
        entity_descriptions = samlbackend.get_metadata_desc()

        assert len(entity_descriptions) == 1

        idp_desc = entity_descriptions[0].to_dict()

        assert idp_desc["entityid"] == urlsafe_b64encode(
            idp_conf["entityid"].encode("utf-8")).decode("utf-8")
        assert idp_desc["contact_person"] == idp_conf["contact_person"]

        assert idp_desc["organization"]["name"][0] == tuple(
            idp_conf["organization"]["name"][0])
        assert idp_desc["organization"]["display_name"][0] == tuple(
            idp_conf["organization"]["display_name"][0])
        assert idp_desc["organization"]["url"][0] == tuple(
            idp_conf["organization"]["url"][0])

        expected_ui_info = idp_conf["service"]["idp"]["ui_info"]
        ui_info = idp_desc["service"]["idp"]["ui_info"]
        assert ui_info["display_name"] == expected_ui_info["display_name"]
        assert ui_info["description"] == expected_ui_info["description"]
        assert ui_info["logo"] == expected_ui_info["logo"]
Ejemplo n.º 12
0
    def test_create_mirrored_metadata_does_not_contain_target_contact_info(self, satosa_config_dict, idp_conf,
                                                                           saml_mirror_frontend_config,
                                                                           saml_backend_config):

        satosa_config_dict["FRONTEND_MODULES"] = [saml_mirror_frontend_config]
        saml_backend_config["config"]["sp_config"]["metadata"] = {
            "inline": [create_metadata_from_config_dict(idp_conf)]}
        satosa_config_dict["BACKEND_MODULES"] = [saml_backend_config]
        satosa_config = SATOSAConfig(satosa_config_dict)
        frontend_metadata, backend_metadata = create_entity_descriptors(satosa_config)

        assert len(frontend_metadata) == 1
        entity_descriptors = frontend_metadata[saml_mirror_frontend_config["name"]]
        metadata = InMemoryMetaData(None, str(entity_descriptors[0]))
        metadata.load()

        entity_info = list(metadata.values())[0]
        expected_entity_info = saml_mirror_frontend_config["config"]["idp_config"]
        assert len(entity_info["contact_person"]) == len(expected_entity_info["contact_person"])
        for i, contact in enumerate(expected_entity_info["contact_person"]):
            assert entity_info["contact_person"][i]["contact_type"] == contact["contact_type"]
            assert entity_info["contact_person"][i]["email_address"][0]["text"] == contact["email_address"][0]
            assert entity_info["contact_person"][i]["given_name"]["text"] == contact["given_name"]
            assert entity_info["contact_person"][i]["sur_name"]["text"] == contact["sur_name"]

        expected_org_info = expected_entity_info["organization"]
        assert entity_info["organization"]["organization_display_name"][0]["text"] == \
               expected_org_info["display_name"][0][0]
        assert entity_info["organization"]["organization_name"][0]["text"] == expected_org_info["name"][0][0]
        assert entity_info["organization"]["organization_url"][0]["text"] == expected_org_info["url"][0][0]
Ejemplo n.º 13
0
    def test_create_mirrored_metadata_does_not_contain_target_contact_info(self, satosa_config_dict, idp_conf,
                                                                           saml_mirror_frontend_config,
                                                                           saml_backend_config):

        satosa_config_dict["FRONTEND_MODULES"] = [saml_mirror_frontend_config]
        saml_backend_config["config"]["sp_config"]["metadata"] = {
            "inline": [create_metadata_from_config_dict(idp_conf)]}
        satosa_config_dict["BACKEND_MODULES"] = [saml_backend_config]
        satosa_config = SATOSAConfig(satosa_config_dict)
        frontend_metadata, backend_metadata = create_entity_descriptors(satosa_config)

        assert len(frontend_metadata) == 1
        entity_descriptors = frontend_metadata[saml_mirror_frontend_config["name"]]
        metadata = InMemoryMetaData(None, str(entity_descriptors[0]))
        metadata.load()

        entity_info = list(metadata.values())[0]
        expected_entity_info = saml_mirror_frontend_config["config"]["idp_config"]
        assert len(entity_info["contact_person"]) == len(expected_entity_info["contact_person"])
        for i, contact in enumerate(expected_entity_info["contact_person"]):
            assert entity_info["contact_person"][i]["contact_type"] == contact["contact_type"]
            assert entity_info["contact_person"][i]["email_address"][0]["text"] == contact["email_address"][0]
            assert entity_info["contact_person"][i]["given_name"]["text"] == contact["given_name"]
            assert entity_info["contact_person"][i]["sur_name"]["text"] == contact["sur_name"]

        expected_org_info = expected_entity_info["organization"]
        assert entity_info["organization"]["organization_display_name"][0]["text"] == \
               expected_org_info["display_name"][0][0]
        assert entity_info["organization"]["organization_name"][0]["text"] == expected_org_info["name"][0][0]
        assert entity_info["organization"]["organization_url"][0]["text"] == expected_org_info["url"][0][0]
Ejemplo n.º 14
0
    def test_saml_mirror_frontend_with_multiple_backends(self, satosa_config_dict, idp_conf,
                                                         saml_mirror_frontend_config,
                                                         saml_backend_config, oidc_backend_config):
        satosa_config_dict["FRONTEND_MODULES"] = [saml_mirror_frontend_config]
        saml_backend_config["config"]["sp_config"]["metadata"] = {
            "inline": [create_metadata_from_config_dict(idp_conf)]}
        satosa_config_dict["BACKEND_MODULES"] = [saml_backend_config, oidc_backend_config]
        satosa_config = SATOSAConfig(satosa_config_dict)
        frontend_metadata, backend_metadata = create_entity_descriptors(satosa_config)

        assert len(frontend_metadata) == 1
        assert len(frontend_metadata[saml_mirror_frontend_config["name"]]) == 2
        params = zip([idp_conf["entityid"], oidc_backend_config["config"]["provider_metadata"]["issuer"]],
                     [saml_backend_config["name"], oidc_backend_config["name"]])
        entity_descriptors = frontend_metadata[saml_mirror_frontend_config["name"]]
        for target_entity_id, backend_name in params:
            encoded_target_entity_id = urlsafe_b64encode(target_entity_id.encode("utf-8")).decode("utf-8")
            self.assert_single_sign_on_endpoints_for_saml_mirror_frontend(entity_descriptors, encoded_target_entity_id,
                                                                          saml_mirror_frontend_config,
                                                                          [backend_name])

        # only the SAML backend produces SAML metadata
        assert len(backend_metadata)
        self.assert_assertion_consumer_service_endpoints_for_saml_backend(
            backend_metadata[saml_backend_config["name"]][0],
            saml_backend_config)
Ejemplo n.º 15
0
    def test_redirect_to_idp_if_only_one_idp_in_metadata(self, context, sp_conf, idp_conf):
        sp_conf["metadata"]["inline"] = [create_metadata_from_config_dict(idp_conf)]
        # instantiate new backend, without any discovery service configured
        samlbackend = SAMLBackend(None, INTERNAL_ATTRIBUTES, {"sp_config": sp_conf}, "base_url", "saml_backend")

        resp = samlbackend.start_auth(context, InternalData())
        self.assert_redirect_to_idp(resp, idp_conf)
Ejemplo n.º 16
0
    def test_saml_mirror_frontend_with_multiple_backends(
            self, satosa_config_dict, idp_conf, saml_mirror_frontend_config,
            saml_backend_config, oidc_backend_config):
        satosa_config_dict["FRONTEND_MODULES"] = [saml_mirror_frontend_config]
        saml_backend_config["config"]["sp_config"]["metadata"] = {
            "inline": [create_metadata_from_config_dict(idp_conf)]
        }
        satosa_config_dict["BACKEND_MODULES"] = [
            saml_backend_config, oidc_backend_config
        ]
        satosa_config = SATOSAConfig(satosa_config_dict)
        frontend_metadata, backend_metadata = create_entity_descriptors(
            satosa_config)

        assert len(frontend_metadata) == 1
        assert len(frontend_metadata[saml_mirror_frontend_config["name"]]) == 2
        params = zip([
            idp_conf["entityid"],
            oidc_backend_config["config"]["provider_metadata"]["issuer"]
        ], [saml_backend_config["name"], oidc_backend_config["name"]])
        entity_descriptors = frontend_metadata[
            saml_mirror_frontend_config["name"]]
        for target_entity_id, backend_name in params:
            encoded_target_entity_id = urlsafe_b64encode(
                target_entity_id.encode("utf-8")).decode("utf-8")
            self.assert_single_sign_on_endpoints_for_saml_mirror_frontend(
                entity_descriptors, encoded_target_entity_id,
                saml_mirror_frontend_config, [backend_name])

        # only the SAML backend produces SAML metadata
        assert len(backend_metadata)
        self.assert_assertion_consumer_service_endpoints_for_saml_backend(
            backend_metadata[saml_backend_config["name"]][0],
            saml_backend_config)
Ejemplo n.º 17
0
    def test_respect_sp_entity_categories(self, context, entity_category, entity_category_module, expected_attributes,
                                          idp_conf, sp_conf, internal_response):
        idp_metadata_str = create_metadata_from_config_dict(idp_conf)
        idp_conf["service"]["idp"]["policy"]["default"]["entity_categories"] = [entity_category_module]
        if all(entity_category):  # don't insert empty entity category
            sp_conf["entity_category"] = entity_category
        if entity_category == [COCO]:
            sp_conf["service"]["sp"]["required_attributes"] = expected_attributes

        expected_attributes_in_all_entity_categories = list(
            itertools.chain(swamid.RELEASE[""], edugain.RELEASE[COCO], refeds.RELEASE[RESEARCH_AND_SCHOLARSHIP],
                            swamid.RELEASE[(RESEARCH_AND_EDUCATION, EU)], swamid.RELEASE[(RESEARCH_AND_EDUCATION, HEI)],
                            swamid.RELEASE[(RESEARCH_AND_EDUCATION, NREN)], swamid.RELEASE[SFS_1993_1153]))
        attribute_mapping = {}
        for expected_attribute in expected_attributes_in_all_entity_categories:
            attribute_mapping[expected_attribute.lower()] = {"saml": [expected_attribute]}

        internal_attributes = dict(attributes=attribute_mapping)
        samlfrontend = self.setup_for_authn_req(context, idp_conf, sp_conf, internal_attributes=internal_attributes)

        user_attributes = {k: "foo" for k in expected_attributes_in_all_entity_categories}
        internal_response.attributes = AttributeMapper(internal_attributes).to_internal("saml", user_attributes)
        internal_response.requester = sp_conf["entityid"]

        resp = self.get_auth_response(samlfrontend, context, internal_response, sp_conf, idp_metadata_str)
        assert Counter(resp.ava.keys()) == Counter(expected_attributes)
Ejemplo n.º 18
0
    def test_redirect_to_idp_if_only_one_idp_in_metadata(self, context, sp_conf, idp_conf):
        sp_conf["metadata"]["inline"] = [create_metadata_from_config_dict(idp_conf)]
        # instantiate new backend, without any discovery service configured
        samlbackend = SAMLBackend(None, INTERNAL_ATTRIBUTES, {"sp_config": sp_conf}, "base_url", "saml_backend")

        resp = samlbackend.start_auth(context, InternalData())
        assert_redirect_to_idp(resp, idp_conf)
Ejemplo n.º 19
0
    def test_get_metadata_desc_with_logo_without_lang(self, sp_conf, idp_conf):
        # add logo without 'lang'
        idp_conf["service"]["idp"]["ui_info"]["logo"] = [{"text": "https://idp.example.com/static/logo.png",
                                                          "width": "120", "height": "60"}]

        sp_conf["metadata"]["inline"] = [create_metadata_from_config_dict(idp_conf)]
        # instantiate new backend, with a single backing IdP
        samlbackend = SAMLBackend(None, INTERNAL_ATTRIBUTES, {"sp_config": sp_conf}, "base_url", "saml_backend")
        entity_descriptions = samlbackend.get_metadata_desc()

        assert len(entity_descriptions) == 1

        idp_desc = entity_descriptions[0].to_dict()

        assert idp_desc["entityid"] == urlsafe_b64encode(idp_conf["entityid"].encode("utf-8")).decode("utf-8")
        assert idp_desc["contact_person"] == idp_conf["contact_person"]

        assert idp_desc["organization"]["name"][0] == tuple(idp_conf["organization"]["name"][0])
        assert idp_desc["organization"]["display_name"][0] == tuple(idp_conf["organization"]["display_name"][0])
        assert idp_desc["organization"]["url"][0] == tuple(idp_conf["organization"]["url"][0])

        expected_ui_info = idp_conf["service"]["idp"]["ui_info"]
        ui_info = idp_desc["service"]["idp"]["ui_info"]
        assert ui_info["display_name"] == expected_ui_info["display_name"]
        assert ui_info["description"] == expected_ui_info["description"]
        assert ui_info["logo"] == expected_ui_info["logo"]
Ejemplo n.º 20
0
 def test_always_redirect_to_discovery_service_if_using_mdq(self, context, sp_conf, idp_conf):
     # one IdP in the metadata, but MDQ also configured so should always redirect to the discovery service
     sp_conf["metadata"]["inline"] = [create_metadata_from_config_dict(idp_conf)]
     sp_conf["metadata"]["mdq"] = ["https://mdq.example.com"]
     samlbackend = SAMLBackend(None, INTERNAL_ATTRIBUTES, {"sp_config": sp_conf, "disco_srv": DISCOSRV_URL,},
                               "base_url", "saml_backend")
     resp = samlbackend.start_auth(context, InternalData())
     self.assert_redirect_to_discovery_server(resp, sp_conf)
Ejemplo n.º 21
0
    def test_co_static_attributes(self, frontend, context, internal_response,
                                  idp_conf, sp_conf):
        # Use the frontend and context fixtures to dynamically create the
        # proxy IdP server that would be created during a flow.
        idp_server = frontend._create_co_virtual_idp(context)

        # Use the context fixture to find the CO name and the backend name
        # and then use those to dynamically update the ipd_conf fixture.
        co_name = frontend._get_co_name(context)
        backend_name = context.target_backend
        idp_conf = frontend._add_endpoints_to_config(idp_conf, co_name,
                                                     backend_name)
        idp_conf = frontend._add_entity_id(idp_conf, co_name)

        # Use a utility function to serialize the idp_conf IdP configuration
        # fixture to a string and then dynamically update the sp_conf
        # SP configuration fixture with the metadata.
        idp_metadata_str = create_metadata_from_config_dict(idp_conf)
        sp_conf["metadata"]["inline"].append(idp_metadata_str)
        sp_config = SPConfig().load(sp_conf, metadata_construction=False)

        # Use the updated sp_config fixture to generate a fake SP and then
        # use the fake SP to generate an authentication request aimed at the
        # proxy CO virtual IdP.
        fakesp = FakeSP(sp_config)
        destination, auth_req = fakesp.make_auth_req(
            idp_server.config.entityid,
            nameid_format=None,
            relay_state="relay_state",
            subject=None,
        )

        # Update the context with the authentication request.
        context.request = auth_req

        # Create the response arguments necessary for the IdP to respond to
        # the authentication request, update the request state and with it
        # the context, and then use the frontend fixture and the
        # internal_response fixture to handle the authentication response
        # and generate a response from the proxy IdP to the SP.
        resp_args = {
            "name_id_policy": NameIDPolicy(format=NAMEID_FORMAT_TRANSIENT),
            "in_response_to": None,
            "destination": sp_config.endpoint(
                            "assertion_consumer_service",
                            binding=BINDING_HTTP_REDIRECT
                            )[0],
            "sp_entity_id": sp_conf["entityid"],
            "binding": BINDING_HTTP_REDIRECT
        }
        request_state = frontend._create_state_data(context, resp_args, "")
        context.state[frontend.name] = request_state
        frontend.handle_authn_response(context, internal_response)

        # Verify that the frontend added the CO static SAML attributes to the
        # internal response.
        for attr, value in self.CO_STATIC_SAML_ATTRIBUTES.items():
            assert internal_response.attributes[attr] == value
Ejemplo n.º 22
0
    def test_acr_mapping_per_idp_in_authn_response(self, context, idp_conf, sp_conf, internal_response):
        expected_loa = "LoA1"
        loa = {"": "http://eidas.europa.eu/LoA/low", idp_conf["entityid"]: expected_loa}
        samlfrontend = self.setup_for_authn_req(context, idp_conf, sp_conf, extra_config={"acr_mapping": loa})
        idp_metadata_str = create_metadata_from_config_dict(samlfrontend.idp_config)

        resp = self.get_auth_response(samlfrontend, context, internal_response, sp_conf, idp_metadata_str)
        assert len(resp.assertion.authn_statement) == 1
        authn_context_class_ref = resp.assertion.authn_statement[0].authn_context.authn_context_class_ref
        assert authn_context_class_ref.text == expected_loa
Ejemplo n.º 23
0
    def test_acr_mapping_per_idp_in_authn_response(self, context, idp_conf, sp_conf, internal_response):
        expected_loa = "LoA1"
        loa = {"": "http://eidas.europa.eu/LoA/low", idp_conf["entityid"]: expected_loa}
        samlfrontend = self.setup_for_authn_req(context, idp_conf, sp_conf, extra_config={"acr_mapping": loa})
        idp_metadata_str = create_metadata_from_config_dict(samlfrontend.idp_config)

        resp = self.get_auth_response(samlfrontend, context, internal_response, sp_conf, idp_metadata_str)
        assert len(resp.assertion.authn_statement) == 1
        authn_context_class_ref = resp.assertion.authn_statement[0].authn_context.authn_context_class_ref
        assert authn_context_class_ref.text == expected_loa
Ejemplo n.º 24
0
 def test_default_redirect_to_discovery_service_if_using_mdq(
     self, context, sp_conf, idp_conf
 ):
     # one IdP in the metadata, but MDQ also configured so should always redirect to the discovery service
     sp_conf["metadata"]["inline"] = [create_metadata_from_config_dict(idp_conf)]
     sp_conf["metadata"]["mdq"] = ["https://mdq.example.com"]
     samlbackend = SAMLBackend(None, INTERNAL_ATTRIBUTES, {"sp_config": sp_conf, "disco_srv": DISCOSRV_URL,},
                               "base_url", "saml_backend")
     resp = samlbackend.start_auth(context, InternalData())
     assert_redirect_to_discovery_server(resp, sp_conf, DISCOSRV_URL)
Ejemplo n.º 25
0
    def test_acr_mapping_per_idp_in_authn_response(self, idp_conf, sp_conf):
        expected_loa = "LoA1"
        loa = {
            "": "http://eidas.europa.eu/LoA/low",
            idp_conf["entityid"]: expected_loa
        }

        base = self.construct_base_url_from_entity_id(idp_conf["entityid"])
        conf = {
            "idp_config": idp_conf,
            "endpoints": ENDPOINTS,
            "base": base,
            "state_id": "state_id",
            "acr_mapping": loa
        }

        samlfrontend = SamlFrontend(None, INTERNAL_ATTRIBUTES, conf)
        samlfrontend.register_endpoints(["foo"])

        idp_metadata_str = create_metadata_from_config_dict(
            samlfrontend.config)
        sp_conf["metadata"]["inline"].append(idp_metadata_str)
        fakesp = FakeSP(None,
                        config=SPConfig().load(sp_conf,
                                               metadata_construction=False))

        auth_info = AuthenticationInformation(PASSWORD, "2015-09-30T12:21:37Z",
                                              idp_conf["entityid"])
        internal_response = InternalResponse(auth_info=auth_info)
        context = Context()
        context.state = State()

        resp_args = {
            "name_id_policy": NameIDPolicy(format=NAMEID_FORMAT_TRANSIENT),
            "in_response_to": None,
            "destination": "",
            "sp_entity_id": None,
            "binding": BINDING_HTTP_REDIRECT
        }
        request_state = samlfrontend.save_state(context, resp_args, "")
        context.state.add(conf["state_id"], request_state)

        resp = samlfrontend.handle_authn_response(context, internal_response)
        resp_dict = parse_qs(urlparse(resp.message).query)
        resp = fakesp.parse_authn_request_response(
            resp_dict['SAMLResponse'][0], BINDING_HTTP_REDIRECT)

        assert len(resp.assertion.authn_statement) == 1
        authn_context_class_ref = resp.assertion.authn_statement[
            0].authn_context.authn_context_class_ref
        assert authn_context_class_ref.text == expected_loa
Ejemplo n.º 26
0
    def setup_for_authn_req(self, idp_conf, sp_conf, nameid_format):
        base = self.construct_base_url_from_entity_id(idp_conf["entityid"])
        config = {
            "idp_config": idp_conf,
            "endpoints": ENDPOINTS,
            "base": base,
            "state_id": "state_id"
        }
        sp_metadata_str = create_metadata_from_config_dict(sp_conf)
        idp_conf["metadata"]["inline"] = [sp_metadata_str]

        samlfrontend = SamlFrontend(
            lambda context, internal_req: (context, internal_req),
            INTERNAL_ATTRIBUTES, config)
        samlfrontend.register_endpoints(["saml"])

        idp_metadata_str = create_metadata_from_config_dict(
            samlfrontend.config)
        sp_conf["metadata"]["inline"].append(idp_metadata_str)

        fakesp = FakeSP(None,
                        config=SPConfig().load(sp_conf,
                                               metadata_construction=False))
        context = Context()
        context.state = State()
        context.request = parse.parse_qs(
            urlparse(
                fakesp.make_auth_req(samlfrontend.config["entityid"],
                                     nameid_format)).query)
        tmp_dict = {}
        for val in context.request:
            if isinstance(context.request[val], list):
                tmp_dict[val] = context.request[val][0]
            else:
                tmp_dict[val] = context.request[val]
        context.request = tmp_dict

        return context, samlfrontend
Ejemplo n.º 27
0
    def frontend(self, idp_conf, sp_conf):
        """
        This fixture is an instance of the SAMLVirtualCoFrontend with an IdP
        configuration that includes SAML metadata for the test SP configured
        by the sp_conf fixture so that we can test a SAML Response sent
        from the IdP.
        """
        # Use a utility function to serialize the sp_conf fixture as
        # a string and then dynamically add it as the metadata available
        # as part of the idp_conf fixture.
        sp_metadata_str = create_metadata_from_config_dict(sp_conf)
        idp_conf["metadata"]["inline"] = [sp_metadata_str]

        # Dynamically add configuration details for the CO including static
        # SAML attributes so their presence in a SAML Response can be tested.
        collab_org = {
            "encodeable_name": self.CO,
            "co_static_saml_attributes": self.CO_STATIC_SAML_ATTRIBUTES,
            "co_attribute_scope": self.CO_SCOPE
        }

        # Use the dynamically updated idp_conf fixture, the configured
        # endpoints, and the collaborative organization configuration to
        # create the configuration for the frontend.
        conf = {
            "idp_config": idp_conf,
            "endpoints": ENDPOINTS,
            "collaborative_organizations": [collab_org]
        }

        # Use a richer set of internal attributes than what is provided
        # for the parent class so that we can test for the static SAML
        # attributes about the CO being asserted.
        internal_attributes = INTERNAL_ATTRIBUTES
        internal_attributes["attributes"][self.CO_O] = {"saml": ["o"]}
        internal_attributes["attributes"][self.CO_C] = {"saml": ["c"]}
        internal_attributes["attributes"][self.CO_CO] = {"saml": ["co"]}
        internal_attributes["attributes"][self.CO_NOREDUORGACRONYM] = ({
            "saml": ["norEduOrgAcronym"]
        })

        # Create, register the endpoints, and then return the frontend
        # instance.
        frontend = SAMLVirtualCoFrontend(lambda ctx, req: None,
                                         internal_attributes, conf, BASE_URL,
                                         "saml_virtual_co_frontend")
        frontend.register_endpoints([self.BACKEND])

        return frontend
Ejemplo n.º 28
0
    def test_redirect_to_idp_if_only_one_idp_in_metadata(self, sp_conf, idp_conf):
        sp_conf["metadata"]["inline"] = [create_metadata_from_config_dict(idp_conf)]
        samlbackend = SamlBackend(None, INTERNAL_ATTRIBUTES,
                                  {"config": sp_conf, "state_id": "saml_backend_test_id"})

        state = State()
        state.add("test", "state")
        context = Context()
        context.state = state
        internal_req = InternalRequest(UserIdHashType.transient, None)

        resp = samlbackend.start_auth(context, internal_req)

        assert resp.status == "303 See Other"
        parsed = urlparse(resp.message)
        assert "{parsed.scheme}://{parsed.netloc}{parsed.path}".format(
                parsed=parsed) == \
               idp_conf["service"]["idp"]["endpoints"]["single_sign_on_service"][0][0]
        assert "SAMLRequest" in parse_qs(parsed.query)
Ejemplo n.º 29
0
    def test_custom_attribute_release_with_less_attributes_than_entity_category(self, context, idp_conf, sp_conf,
                                                                                internal_response):
        idp_metadata_str = create_metadata_from_config_dict(idp_conf)
        idp_conf["service"]["idp"]["policy"]["default"]["entity_categories"] = ["swamid"]
        sp_conf["entity_category"] = [SFS_1993_1153]
        expected_attributes = swamid.RELEASE[SFS_1993_1153]

        attribute_mapping = {}
        for expected_attribute in expected_attributes:
            attribute_mapping[expected_attribute.lower()] = {"saml": [expected_attribute]}
        internal_attributes = dict(attributes=attribute_mapping)

        user_attributes = {k: "foo" for k in expected_attributes}
        internal_response.attributes = AttributeMapper(internal_attributes).to_internal("saml", user_attributes)

        custom_attributes = {idp_conf["entityid"]: {sp_conf["entityid"]: {"exclude": ["norEduPersonNIN"]}}}
        samlfrontend = self.setup_for_authn_req(context, idp_conf, sp_conf, internal_attributes=internal_attributes,
                                                extra_config=dict(custom_attribute_release=custom_attributes))

        resp = self.get_auth_response(samlfrontend, context, internal_response, sp_conf, idp_metadata_str)
        assert len(resp.ava.keys()) == 0
Ejemplo n.º 30
0
    def test_custom_attribute_release_with_less_attributes_than_entity_category(self, context, idp_conf, sp_conf,
                                                                                internal_response):
        idp_metadata_str = create_metadata_from_config_dict(idp_conf)
        idp_conf["service"]["idp"]["policy"]["default"]["entity_categories"] = ["swamid"]
        sp_conf["entity_category"] = [SFS_1993_1153]
        expected_attributes = swamid.RELEASE[SFS_1993_1153]

        attribute_mapping = {}
        for expected_attribute in expected_attributes:
            attribute_mapping[expected_attribute.lower()] = {"saml": [expected_attribute]}
        internal_attributes = dict(attributes=attribute_mapping)

        user_attributes = {k: "foo" for k in expected_attributes}
        internal_response.attributes = AttributeMapper(internal_attributes).to_internal("saml", user_attributes)

        custom_attributes = {idp_conf["entityid"]: {sp_conf["entityid"]: {"exclude": ["norEduPersonNIN"]}}}
        samlfrontend = self.setup_for_authn_req(context, idp_conf, sp_conf, internal_attributes=internal_attributes,
                                                extra_config=dict(custom_attribute_release=custom_attributes))

        resp = self.get_auth_response(samlfrontend, context, internal_response, sp_conf, idp_metadata_str)
        assert len(resp.ava.keys()) == 0
Ejemplo n.º 31
0
    def test_acr_mapping_per_idp_in_authn_response(self, idp_conf, sp_conf):
        expected_loa = "LoA1"
        loa = {"": "http://eidas.europa.eu/LoA/low", idp_conf["entityid"]: expected_loa}

        base = self.construct_base_url_from_entity_id(idp_conf["entityid"])
        conf = {"idp_config": idp_conf, "endpoints": ENDPOINTS, "base": base,
                "state_id": "state_id", "acr_mapping": loa}

        samlfrontend = SamlFrontend(None, INTERNAL_ATTRIBUTES, conf)
        samlfrontend.register_endpoints(["foo"])

        idp_metadata_str = create_metadata_from_config_dict(samlfrontend.config)
        sp_conf["metadata"]["inline"].append(idp_metadata_str)
        fakesp = FakeSP(None, config=SPConfig().load(sp_conf, metadata_construction=False))

        auth_info = AuthenticationInformation(PASSWORD, "2015-09-30T12:21:37Z", idp_conf["entityid"])
        internal_response = InternalResponse(auth_info=auth_info)
        context = Context()
        context.state = State()

        resp_args = {
            "name_id_policy": NameIDPolicy(format=NAMEID_FORMAT_TRANSIENT),
            "in_response_to": None,
            "destination": "",
            "sp_entity_id": None,
            "binding": BINDING_HTTP_REDIRECT

        }
        request_state = samlfrontend.save_state(context, resp_args, "")
        context.state.add(conf["state_id"], request_state)

        resp = samlfrontend.handle_authn_response(context, internal_response)
        resp_dict = parse_qs(urlparse(resp.message).query)
        resp = fakesp.parse_authn_request_response(resp_dict['SAMLResponse'][0],
                                                   BINDING_HTTP_REDIRECT)

        assert len(resp.assertion.authn_statement) == 1
        authn_context_class_ref = resp.assertion.authn_statement[
            0].authn_context.authn_context_class_ref
        assert authn_context_class_ref.text == expected_loa
Ejemplo n.º 32
0
    def test_get_metadata_desc(self, sp_conf, idp_conf):
        sp_conf["metadata"]["inline"] = [create_metadata_from_config_dict(idp_conf)]
        # instantiate new backend, with a single backing IdP
        samlbackend = SAMLBackend(None, INTERNAL_ATTRIBUTES, {"sp_config": sp_conf}, "base_url", "saml_backend")
        entity_descriptions = samlbackend.get_metadata_desc()

        assert len(entity_descriptions) == 1

        idp_desc = entity_descriptions[0].to_dict()

        assert idp_desc["entityid"] == urlsafe_b64encode(idp_conf["entityid"].encode("utf-8")).decode("utf-8")
        assert idp_desc["contact_person"] == idp_conf["contact_person"]

        assert idp_desc["organization"]["name"][0] == tuple(idp_conf["organization"]["name"][0])
        assert idp_desc["organization"]["display_name"][0] == tuple(idp_conf["organization"]["display_name"][0])
        assert idp_desc["organization"]["url"][0] == tuple(idp_conf["organization"]["url"][0])

        expected_ui_info = idp_conf["service"]["idp"]["ui_info"]
        ui_info = idp_desc["service"]["idp"]["ui_info"]
        assert ui_info["display_name"] == expected_ui_info["display_name"]
        assert ui_info["description"] == expected_ui_info["description"]
        assert ui_info["logo"] == expected_ui_info["logo"]
Ejemplo n.º 33
0
    def test_respect_sp_entity_categories(self, entity_category, expected_attributes, idp_conf, sp_conf):
        base = self.construct_base_url_from_entity_id(idp_conf["entityid"])
        conf = {"idp_config": idp_conf, "endpoints": ENDPOINTS, "base": base,
                "state_id": "state_id"}

        internal_attributes = {attr_name: {"saml": [attr_name.lower()]} for attr_name in expected_attributes}
        samlfrontend = SamlFrontend(None, dict(attributes=internal_attributes), conf)
        samlfrontend.register_endpoints(["foo"])

        idp_metadata_str = create_metadata_from_config_dict(samlfrontend.idp_config)
        sp_conf["metadata"]["inline"].append(idp_metadata_str)
        sp_conf["entity_category"] = entity_category
        fakesp = FakeSP(None, config=SPConfig().load(sp_conf, metadata_construction=False))

        auth_info = AuthenticationInformation(PASSWORD, "2015-09-30T12:21:37Z", idp_conf["entityid"])
        internal_response = InternalResponse(auth_info=auth_info)

        user_attributes = {k: "foo" for k in expected_attributes}
        user_attributes.update({k: "bar" for k in ["extra", "more", "stuff"]})
        internal_response.add_attributes(user_attributes)
        context = Context()
        context.state = State()

        resp_args = {
            "name_id_policy": NameIDPolicy(format=NAMEID_FORMAT_TRANSIENT),
            "in_response_to": None,
            "destination": "",
            "sp_entity_id": None,
            "binding": BINDING_HTTP_REDIRECT
        }
        request_state = samlfrontend.save_state(context, resp_args, "")
        context.state.add(conf["state_id"], request_state)

        resp = samlfrontend.handle_authn_response(context, internal_response)
        resp_dict = parse_qs(urlparse(resp.message).query)
        resp = fakesp.parse_authn_request_response(resp_dict['SAMLResponse'][0],
                                                   BINDING_HTTP_REDIRECT)

        assert Counter(resp.ava.keys()) == Counter(expected_attributes)
Ejemplo n.º 34
0
    def test_redirect_to_idp_if_only_one_idp_in_metadata(
            self, sp_conf, idp_conf):
        sp_conf["metadata"]["inline"] = [
            create_metadata_from_config_dict(idp_conf)
        ]
        samlbackend = SamlBackend(None, INTERNAL_ATTRIBUTES, {
            "config": sp_conf,
            "state_id": "saml_backend_test_id"
        })

        state = State()
        state.add("test", "state")
        context = Context()
        context.state = state
        internal_req = InternalRequest(UserIdHashType.transient, None)

        resp = samlbackend.start_auth(context, internal_req)

        assert resp.status == "303 See Other"
        parsed = urlparse(resp.message)
        assert "{parsed.scheme}://{parsed.netloc}{parsed.path}".format(
                parsed=parsed) == \
               idp_conf["service"]["idp"]["endpoints"]["single_sign_on_service"][0][0]
        assert "SAMLRequest" in parse_qs(parsed.query)