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
def test_authn_response(self, context, idp_conf, sp_conf): response_binding = BINDING_HTTP_REDIRECT fakesp = FakeSP(SPConfig().load(sp_conf, metadata_construction=False)) fakeidp = FakeIdP(USERS, config=IdPConfig().load(idp_conf, metadata_construction=False)) destination, request_params = fakesp.make_auth_req( idp_conf["entityid"]) url, auth_resp = fakeidp.handle_auth_req( request_params["SAMLRequest"], request_params["RelayState"], BINDING_HTTP_REDIRECT, "testuser1", response_binding=response_binding) context.request = auth_resp context.state[self.samlbackend.name] = { "relay_state": request_params["RelayState"] } self.samlbackend.authn_response(context, response_binding) context, internal_resp = self.samlbackend.auth_callback_func.call_args[ 0] self.assert_authn_response(internal_resp) assert self.samlbackend.name not in context.state
def test_authn_response_no_name_id(self, context, idp_conf, sp_conf): response_binding = BINDING_HTTP_REDIRECT fakesp_conf = SPConfig().load(sp_conf, metadata_construction=False) fakesp = FakeSP(fakesp_conf) fakeidp_conf = IdPConfig().load(idp_conf, metadata_construction=False) fakeidp = FakeIdP(USERS, config=fakeidp_conf) destination, request_params = fakesp.make_auth_req( idp_conf["entityid"]) # Use the fake IdP to mock up an authentication request that has no # <NameID> element. url, auth_resp = fakeidp.handle_auth_req_no_name_id( request_params["SAMLRequest"], request_params["RelayState"], BINDING_HTTP_REDIRECT, "testuser1", response_binding=response_binding) backend = self.samlbackend context.request = auth_resp context.state[backend.name] = { "relay_state": request_params["RelayState"], } backend.authn_response(context, response_binding) context, internal_resp = backend.auth_callback_func.call_args[0] assert_authn_response(internal_resp) assert backend.name not in context.state
def test_authn_response_no_name_id(self, context, idp_conf, sp_conf): response_binding = BINDING_HTTP_REDIRECT fakesp_conf = SPConfig().load(sp_conf, metadata_construction=False) fakesp = FakeSP(fakesp_conf) fakeidp_conf = IdPConfig().load(idp_conf, metadata_construction=False) fakeidp = FakeIdP(USERS, config=fakeidp_conf) destination, request_params = fakesp.make_auth_req( idp_conf["entityid"]) # Use the fake IdP to mock up an authentication request that has no # <NameID> element. url, auth_resp = fakeidp.handle_auth_req_no_name_id( request_params["SAMLRequest"], request_params["RelayState"], BINDING_HTTP_REDIRECT, "testuser1", response_binding=response_binding) backend = self.samlbackend context.request = auth_resp context.state[backend.name] = { "relay_state": request_params["RelayState"], } backend.authn_response(context, response_binding) context, internal_resp = backend.auth_callback_func.call_args[0] self.assert_authn_response(internal_resp) assert backend.name not in context.state
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
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
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
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 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 test_authn_response(self, context, idp_conf, sp_conf): response_binding = BINDING_HTTP_REDIRECT fakesp = FakeSP(SPConfig().load(sp_conf, metadata_construction=False)) fakeidp = FakeIdP(USERS, config=IdPConfig().load(idp_conf, metadata_construction=False)) destination, request_params = fakesp.make_auth_req(idp_conf["entityid"]) url, auth_resp = fakeidp.handle_auth_req(request_params["SAMLRequest"], request_params["RelayState"], BINDING_HTTP_REDIRECT, "testuser1", response_binding=response_binding) context.request = auth_resp context.state[self.samlbackend.name] = {"relay_state": request_params["RelayState"]} self.samlbackend.authn_response(context, response_binding) context, internal_resp = self.samlbackend.auth_callback_func.call_args[0] self.assert_authn_response(internal_resp) assert self.samlbackend.name not in context.state
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
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]
class TestProxy: """ Performs a complete flow test for the proxy. Verifies SAML -> PROXY -> SAML. """ @pytest.fixture(autouse=True) def setup(self): """ Initiates the test. :return: None """ self.sp = FakeSP(None, config=SPConfig().load(TestConfiguration.get_instance(). fake_sp_config, metadata_construction=False)) self.idp = FakeIdP(USERS, IdPConfig().load(TestConfiguration.get_instance().fake_idp_config, metadata_construction=False)) def test_flow(self): """ Performs the test. """ e_id = 'https://localhost:8090/proxy.xml' target_id = 'https://example.com/unittest_idp.xml' url = "{}&entityID={}".format(self.sp.make_auth_req(e_id), quote(target_id)) app = WsgiApplication(config=TestConfiguration.get_instance().proxy_config) test_client = Client(app.run_server, BaseResponse) parsed = urlparse(url) request = "{}?{}".format(parsed.path, parsed.query) resp = test_client.get(request) assert resp.status == '303 See Other' headers = dict(resp.headers) assert headers["Set-Cookie"], "Did not save state in cookie!" url = headers["location"] req = parse_qs(urlsplit(url).query) assert 'SAMLRequest' in req assert 'RelayState' in req action, body = self.idp.handle_auth_req(req['SAMLRequest'][0], req['RelayState'][0], BINDING_HTTP_REDIRECT, 'testuser1') parsed = urlparse(action) request = "{}?{}".format(parsed.path, parsed.query) resp = test_client.post(request, data=urlencode(body), headers=[("Cookie", headers["Set-Cookie"]), ("Content-Type", "application/x-www-form-urlencoded")]) assert resp.status == '302 Found' headers = dict(resp.headers) url = headers["location"] req = parse_qs(urlsplit(url).query) assert 'SAMLResponse' in req assert 'RelayState' in req resp = self.sp.parse_authn_request_response(req['SAMLResponse'][0], BINDING_HTTP_REDIRECT) identity = resp.ava assert identity["displayName"][0] == "Test Testsson"
class TestProxy: """ Performs a complete flow test for the proxy. Verifies SAML -> PROXY -> SAML. """ @pytest.fixture(autouse=True) def setup(self): """ Initiates the test. :return: None """ self.sp = FakeSP(None, config=SPConfig().load( TestConfiguration.get_instance().fake_sp_config, metadata_construction=False)) self.idp = FakeIdP( USERS, IdPConfig().load(TestConfiguration.get_instance().fake_idp_config, metadata_construction=False)) def test_flow(self): """ Performs the test. """ e_id = 'https://localhost:8090/proxy.xml' target_id = 'https://example.com/unittest_idp.xml' url = "{}&entityID={}".format(self.sp.make_auth_req(e_id), quote(target_id)) app = WsgiApplication( config=TestConfiguration.get_instance().proxy_config) test_client = Client(app.run_server, BaseResponse) parsed = urlparse(url) request = "{}?{}".format(parsed.path, parsed.query) resp = test_client.get(request) assert resp.status == '303 See Other' headers = dict(resp.headers) assert headers["Set-Cookie"], "Did not save state in cookie!" url = headers["location"] req = parse_qs(urlsplit(url).query) assert 'SAMLRequest' in req assert 'RelayState' in req action, body = self.idp.handle_auth_req(req['SAMLRequest'][0], req['RelayState'][0], BINDING_HTTP_REDIRECT, 'testuser1') parsed = urlparse(action) request = "{}?{}".format(parsed.path, parsed.query) resp = test_client.post(request, data=urlencode(body), headers=[("Cookie", headers["Set-Cookie"]), ("Content-Type", "application/x-www-form-urlencoded") ]) assert resp.status == '302 Found' headers = dict(resp.headers) url = headers["location"] req = parse_qs(urlsplit(url).query) assert 'SAMLResponse' in req assert 'RelayState' in req resp = self.sp.parse_authn_request_response(req['SAMLResponse'][0], BINDING_HTTP_REDIRECT) identity = resp.ava assert identity["displayName"][0] == "Test Testsson"