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)
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)
def test_two_saml_frontends(self, satosa_config_dict, saml_frontend_config, saml_mirror_frontend_config, oidc_backend_config): satosa_config_dict["FRONTEND_MODULES"] = [ saml_frontend_config, saml_mirror_frontend_config ] satosa_config_dict["BACKEND_MODULES"] = [oidc_backend_config] satosa_config = SATOSAConfig(satosa_config_dict) frontend_metadata, backend_metadata = create_entity_descriptors( satosa_config) assert len(frontend_metadata) == 2 saml_entities = frontend_metadata[saml_frontend_config["name"]] assert len(saml_entities) == 1 entity_descriptor = saml_entities[0] self.assert_single_sign_on_endpoints_for_saml_frontend( entity_descriptor, saml_frontend_config, [oidc_backend_config["name"]]) mirrored_saml_entities = frontend_metadata[ saml_mirror_frontend_config["name"]] assert len(mirrored_saml_entities) == 1 target_entity_id = oidc_backend_config["config"]["provider_metadata"][ "issuer"] 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( mirrored_saml_entities, encoded_target_entity_id, saml_mirror_frontend_config, [oidc_backend_config["name"]]) # OIDC backend does not produce any SAML metadata assert not backend_metadata
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]
def test_two_saml_frontends(self, satosa_config_dict, saml_frontend_config, saml_mirror_frontend_config, oidc_backend_config): satosa_config_dict["FRONTEND_MODULES"] = [saml_frontend_config, saml_mirror_frontend_config] satosa_config_dict["BACKEND_MODULES"] = [oidc_backend_config] satosa_config = SATOSAConfig(satosa_config_dict) frontend_metadata, backend_metadata = create_entity_descriptors(satosa_config) assert len(frontend_metadata) == 2 saml_entities = frontend_metadata[saml_frontend_config["name"]] assert len(saml_entities) == 1 entity_descriptor = saml_entities[0] self.assert_single_sign_on_endpoints_for_saml_frontend(entity_descriptor, saml_frontend_config, [oidc_backend_config["name"]]) mirrored_saml_entities = frontend_metadata[saml_mirror_frontend_config["name"]] assert len(mirrored_saml_entities) == 1 target_entity_id = oidc_backend_config["config"]["provider_metadata"]["issuer"] 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(mirrored_saml_entities, encoded_target_entity_id, saml_mirror_frontend_config, [oidc_backend_config["name"]]) # OIDC backend does not produce any SAML metadata assert not backend_metadata
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)
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)
def test_full_flow(self, satosa_config_dict, oidc_frontend_config, saml_backend_config, idp_conf): subject_id = "testuser1" # proxy config satosa_config_dict["FRONTEND_MODULES"] = [oidc_frontend_config] satosa_config_dict["BACKEND_MODULES"] = [saml_backend_config] satosa_config_dict["INTERNAL_ATTRIBUTES"]["attributes"] = {attr_name: {"openid": [attr_name], "saml": [attr_name]} for attr_name in USERS[subject_id]} _, backend_metadata = create_entity_descriptors(SATOSAConfig(satosa_config_dict)) # application test_client = Client(make_app(SATOSAConfig(satosa_config_dict)), Response) # get frontend OP config info provider_config = json.loads(test_client.get("/.well-known/openid-configuration").data.decode("utf-8")) # create auth req claims_request = ClaimsRequest(id_token=Claims(**{k: None for k in USERS[subject_id]})) req_args = {"scope": "openid", "response_type": "id_token", "client_id": CLIENT_ID, "redirect_uri": REDIRECT_URI, "nonce": "nonce", "claims": claims_request.to_json()} auth_req = urlparse(provider_config["authorization_endpoint"]).path + "?" + urlencode(req_args) # make auth req to proxy proxied_auth_req = test_client.get(auth_req) assert proxied_auth_req.status == "303 See Other" # config test IdP backend_metadata_str = str(backend_metadata[saml_backend_config["name"]][0]) idp_conf["metadata"]["inline"].append(backend_metadata_str) fakeidp = FakeIdP(USERS, config=IdPConfig().load(idp_conf)) # create auth resp req_params = dict(parse_qsl(urlparse(proxied_auth_req.data.decode("utf-8")).query)) url, authn_resp = fakeidp.handle_auth_req( req_params["SAMLRequest"], req_params["RelayState"], BINDING_HTTP_REDIRECT, subject_id, response_binding=BINDING_HTTP_REDIRECT) # make auth resp to proxy authn_resp_req = urlparse(url).path + "?" + urlencode(authn_resp) authn_resp = test_client.get(authn_resp_req) assert authn_resp.status == "303 See Other" # verify auth resp from proxy resp_dict = dict(parse_qsl(urlparse(authn_resp.data.decode("utf-8")).fragment)) signing_key = RSAKey(key=rsa_load(oidc_frontend_config["config"]["signing_key_path"]), use="sig", alg="RS256") id_token_claims = JWS().verify_compact(resp_dict["id_token"], keys=[signing_key]) assert all( (name, values) in id_token_claims.items() for name, values in OIDC_USERS[subject_id].items() )
def test_full_flow(self, satosa_config_dict, oidc_frontend_config, saml_backend_config, idp_conf): user_id = "testuser1" # proxy config satosa_config_dict["FRONTEND_MODULES"] = [oidc_frontend_config] satosa_config_dict["BACKEND_MODULES"] = [saml_backend_config] satosa_config_dict["INTERNAL_ATTRIBUTES"]["attributes"] = {attr_name: {"openid": [attr_name], "saml": [attr_name]} for attr_name in USERS[user_id]} _, backend_metadata = create_entity_descriptors(SATOSAConfig(satosa_config_dict)) # application test_client = Client(make_app(SATOSAConfig(satosa_config_dict)), BaseResponse) # get frontend OP config info provider_config = json.loads(test_client.get("/.well-known/openid-configuration").data.decode("utf-8")) # create auth req claims_request = ClaimsRequest(id_token=Claims(**{k: None for k in USERS[user_id]})) req_args = {"scope": "openid", "response_type": "id_token", "client_id": CLIENT_ID, "redirect_uri": REDIRECT_URI, "nonce": "nonce", "claims": claims_request.to_json()} auth_req = urlparse(provider_config["authorization_endpoint"]).path + "?" + urlencode(req_args) # make auth req to proxy proxied_auth_req = test_client.get(auth_req) assert proxied_auth_req.status == "303 See Other" # config test IdP backend_metadata_str = str(backend_metadata[saml_backend_config["name"]][0]) idp_conf["metadata"]["inline"].append(backend_metadata_str) fakeidp = FakeIdP(USERS, config=IdPConfig().load(idp_conf, metadata_construction=False)) # create auth resp req_params = dict(parse_qsl(urlparse(proxied_auth_req.data.decode("utf-8")).query)) url, authn_resp = fakeidp.handle_auth_req( req_params["SAMLRequest"], req_params["RelayState"], BINDING_HTTP_REDIRECT, user_id, response_binding=BINDING_HTTP_REDIRECT) # make auth resp to proxy authn_resp_req = urlparse(url).path + "?" + urlencode(authn_resp) authn_resp = test_client.get("/" + authn_resp_req) assert authn_resp.status == "303 See Other" # verify auth resp from proxy resp_dict = dict(parse_qsl(urlparse(authn_resp.data.decode("utf-8")).fragment)) signing_key = RSAKey(key=rsa_load(oidc_frontend_config["config"]["signing_key_path"]), use="sig", alg="RS256") id_token_claims = JWS().verify_compact(resp_dict["id_token"], keys=[signing_key]) assert all((k, v[0]) in id_token_claims.items() for k, v in USERS[user_id].items())
def test_saml_frontend_with_oidc_backend(self, satosa_config_dict, saml_frontend_config, oidc_backend_config): satosa_config_dict["FRONTEND_MODULES"] = [saml_frontend_config] satosa_config_dict["BACKEND_MODULES"] = [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_frontend_config["name"]]) == 1 entity_descriptor = frontend_metadata[saml_frontend_config["name"]][0] self.assert_single_sign_on_endpoints_for_saml_frontend(entity_descriptor, saml_frontend_config, [oidc_backend_config["name"]]) # OIDC backend does not produce any SAML metadata assert not backend_metadata
def run_test(self, satosa_config_dict, sp_conf, oidc_backend_config, frontend_config): subject_id = "testuser1" # proxy config satosa_config_dict["FRONTEND_MODULES"] = [frontend_config] satosa_config_dict["BACKEND_MODULES"] = [oidc_backend_config] satosa_config_dict["INTERNAL_ATTRIBUTES"]["attributes"] = {attr_name: {"openid": [attr_name], "saml": [attr_name]} for attr_name in USERS[subject_id]} frontend_metadata, backend_metadata = create_entity_descriptors(SATOSAConfig(satosa_config_dict)) # application test_client = Client(make_app(SATOSAConfig(satosa_config_dict)), BaseResponse) # config test SP frontend_metadata_str = str(frontend_metadata[frontend_config["name"]][0]) sp_conf["metadata"]["inline"].append(frontend_metadata_str) fakesp = FakeSP(SPConfig().load(sp_conf, metadata_construction=False)) # create auth req destination, req_args = fakesp.make_auth_req(frontend_metadata[frontend_config["name"]][0].entity_id) auth_req = urlparse(destination).path + "?" + urlencode(req_args) # make auth req to proxy proxied_auth_req = test_client.get(auth_req) assert proxied_auth_req.status == "302 Found" parsed_auth_req = dict(parse_qsl(urlparse(proxied_auth_req.data.decode("utf-8")).query)) # create auth resp id_token_claims = {k: v[0] for k, v in USERS[subject_id].items()} id_token_claims["sub"] = subject_id id_token_claims["iat"] = time.time() id_token_claims["exp"] = time.time() + 3600 id_token_claims["iss"] = "https://op.example.com" id_token_claims["aud"] = oidc_backend_config["config"]["client"]["client_metadata"]["client_id"] id_token_claims["nonce"] = parsed_auth_req["nonce"] id_token = IdToken(**id_token_claims).to_jwt() authn_resp = {"state": parsed_auth_req["state"], "id_token": id_token} # make auth resp to proxy redirect_uri_path = urlparse( oidc_backend_config["config"]["client"]["client_metadata"]["redirect_uris"][0]).path authn_resp_req = redirect_uri_path + "?" + urlencode(authn_resp) authn_resp = test_client.get(authn_resp_req) assert authn_resp.status == "303 See Other" # verify auth resp from proxy resp_dict = dict(parse_qsl(urlparse(authn_resp.data.decode("utf-8")).query)) auth_resp = fakesp.parse_authn_request_response(resp_dict["SAMLResponse"], BINDING_HTTP_REDIRECT) assert auth_resp.ava == USERS[subject_id]
def test_saml_frontend_with_saml_backend(self, satosa_config_dict, saml_frontend_config, saml_backend_config): satosa_config_dict["FRONTEND_MODULES"] = [saml_frontend_config] 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_frontend_config["name"]]) == 1 entity_descriptor = frontend_metadata[saml_frontend_config["name"]][0] self.assert_single_sign_on_endpoints_for_saml_frontend(entity_descriptor, saml_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)
def run_test(self, satosa_config_dict, sp_conf, idp_conf, saml_backend_config, frontend_config): user_id = "testuser1" # proxy config satosa_config_dict["FRONTEND_MODULES"] = [frontend_config] satosa_config_dict["BACKEND_MODULES"] = [saml_backend_config] satosa_config_dict["INTERNAL_ATTRIBUTES"]["attributes"] = {attr_name: {"saml": [attr_name]} for attr_name in USERS[user_id]} frontend_metadata, backend_metadata = create_entity_descriptors(SATOSAConfig(satosa_config_dict)) # application test_client = Client(make_app(SATOSAConfig(satosa_config_dict)), BaseResponse) # config test SP frontend_metadata_str = str(frontend_metadata[frontend_config["name"]][0]) sp_conf["metadata"]["inline"].append(frontend_metadata_str) fakesp = FakeSP(SPConfig().load(sp_conf, metadata_construction=False)) # create auth req destination, req_args = fakesp.make_auth_req(frontend_metadata[frontend_config["name"]][0].entity_id) auth_req = urlparse(destination).path + "?" + urlencode(req_args) # make auth req to proxy proxied_auth_req = test_client.get(auth_req) assert proxied_auth_req.status == "303 See Other" # config test IdP backend_metadata_str = str(backend_metadata[saml_backend_config["name"]][0]) idp_conf["metadata"]["inline"].append(backend_metadata_str) fakeidp = FakeIdP(USERS, config=IdPConfig().load(idp_conf, metadata_construction=False)) # create auth resp req_params = dict(parse_qsl(urlparse(proxied_auth_req.data.decode("utf-8")).query)) url, authn_resp = fakeidp.handle_auth_req( req_params["SAMLRequest"], req_params["RelayState"], BINDING_HTTP_REDIRECT, user_id, response_binding=BINDING_HTTP_REDIRECT) # make auth resp to proxy authn_resp_req = urlparse(url).path + "?" + urlencode(authn_resp) authn_resp = test_client.get("/" + authn_resp_req) assert authn_resp.status == "303 See Other" # verify auth resp from proxy resp_dict = dict(parse_qsl(urlparse(authn_resp.data.decode("utf-8")).query)) auth_resp = fakesp.parse_authn_request_response(resp_dict["SAMLResponse"], BINDING_HTTP_REDIRECT) assert auth_resp.ava == USERS[user_id]
def run_test(self, satosa_config_dict, sp_conf, idp_conf, saml_backend_config, frontend_config): subject_id = "testuser1" # proxy config satosa_config_dict["FRONTEND_MODULES"] = [frontend_config] satosa_config_dict["BACKEND_MODULES"] = [saml_backend_config] satosa_config_dict["INTERNAL_ATTRIBUTES"]["attributes"] = { attr_name: { "saml": [attr_name] } for attr_name in USERS[subject_id] } frontend_metadata, backend_metadata = create_entity_descriptors( SATOSAConfig(satosa_config_dict)) # application test_client = Client(make_app(SATOSAConfig(satosa_config_dict)), BaseResponse) # config test SP frontend_metadata_str = str( frontend_metadata[frontend_config["name"]][0]) sp_conf["metadata"]["inline"].append(frontend_metadata_str) fakesp = FakeSP(SPConfig().load(sp_conf, metadata_construction=False)) # create auth req destination, req_args = fakesp.make_auth_req( frontend_metadata[frontend_config["name"]][0].entity_id) auth_req = urlparse(destination).path + "?" + urlencode(req_args) # make auth req to proxy proxied_auth_req = test_client.get(auth_req) assert proxied_auth_req.status == "303 See Other" # config test IdP backend_metadata_str = str( backend_metadata[saml_backend_config["name"]][0]) idp_conf["metadata"]["inline"].append(backend_metadata_str) fakeidp = FakeIdP(USERS, config=IdPConfig().load(idp_conf, metadata_construction=False)) # create auth resp req_params = dict( parse_qsl(urlparse(proxied_auth_req.data.decode("utf-8")).query)) url, authn_resp = fakeidp.handle_auth_req( req_params["SAMLRequest"], req_params["RelayState"], BINDING_HTTP_REDIRECT, subject_id, response_binding=BINDING_HTTP_REDIRECT) # make auth resp to proxy authn_resp_req = urlparse(url).path + "?" + urlencode(authn_resp) authn_resp = test_client.get("/" + authn_resp_req) assert authn_resp.status == "303 See Other" # verify auth resp from proxy resp_dict = dict( parse_qsl(urlparse(authn_resp.data.decode("utf-8")).query)) auth_resp = fakesp.parse_authn_request_response( resp_dict["SAMLResponse"], BINDING_HTTP_REDIRECT) assert auth_resp.ava == USERS[subject_id]