def test_consent_not_given(self, internal_response, internal_request, consent_verify_endpoint_regex, consent_registration_endpoint_regex): consent_config = SATOSAConfig(self.satosa_config) consent_module = ConsentModule(consent_config, identity_callback) expected_ticket = "my_ticket" responses.add(responses.GET, consent_verify_endpoint_regex, status=401) responses.add(responses.GET, consent_registration_endpoint_regex, status=200, body=expected_ticket) context = Context() state = State() context.state = state consent_module.save_state(internal_request, state) resp = consent_module.manage_consent(context, internal_response) self.assert_redirect(resp, expected_ticket) self.assert_registstration_req(responses.calls[1].request, consent_config.CONSENT["sign_key"]) context = Context() context.state = state # Verify endpoint of consent service still gives 401 (no consent given) context, internal_response = consent_module._handle_consent_response( context) assert not internal_response.get_attributes()
def test_consent_not_given(self, internal_response, internal_request, consent_verify_endpoint_regex, consent_registration_endpoint_regex): consent_config = SATOSAConfig(self.satosa_config) consent_module = ConsentModule(consent_config, identity_callback) expected_ticket = "my_ticket" responses.add(responses.GET, consent_verify_endpoint_regex, status=401) responses.add(responses.GET, consent_registration_endpoint_regex, status=200, body=expected_ticket) context = Context() state = State() context.state = state consent_module.save_state(internal_request, state) resp = consent_module.manage_consent(context, internal_response) self.assert_redirect(resp, expected_ticket) self.assert_registstration_req(responses.calls[1].request, consent_config.CONSENT["sign_key"]) context = Context() context.state = state # Verify endpoint of consent service still gives 401 (no consent given) context, internal_response = consent_module._handle_consent_response(context) assert not internal_response.get_attributes()
def test_start_auth_no_request_info(self, sp_conf): """ Performs a complete test for the module satosa.backends.saml2. The flow should be accepted. """ disco_srv = "https://my.dicso.com/role/idp.ds" samlbackend = SamlBackend(None, INTERNAL_ATTRIBUTES, {"config": sp_conf, "disco_srv": disco_srv, "state_id": "saml_backend_test_id"}) internal_data = InternalRequest(None, None) state = State() context = Context() context.state = state resp = samlbackend.start_auth(context, internal_data) assert resp.status == "303 See Other", "Must be a redirect to the discovery server." assert resp.message.startswith("https://my.dicso.com/role/idp.ds"), \ "Redirect to wrong URL." # create_name_id_policy_transient() state = State() context = Context() context.state = state user_id_hash_type = UserIdHashType.transient internal_data = InternalRequest(user_id_hash_type, None) resp = samlbackend.start_auth(context, internal_data) assert resp.status == "303 See Other", "Must be a redirect to the discovery server."
def test_consent_full_flow(self, internal_response, internal_request, consent_verify_endpoint_regex, consent_registration_endpoint_regex): consent_config = SATOSAConfig(self.satosa_config) consent_module = ConsentModule(consent_config, identity_callback) expected_ticket = "my_ticket" context = Context() state = State() context.state = state consent_module.save_state(internal_request, state) with responses.RequestsMock() as rsps: rsps.add(responses.GET, consent_verify_endpoint_regex, status=401) rsps.add(responses.GET, consent_registration_endpoint_regex, status=200, body=expected_ticket) resp = consent_module.manage_consent(context, internal_response) self.assert_redirect(resp, expected_ticket) self.assert_registstration_req(rsps.calls[1].request, consent_config.CONSENT["sign_key"]) with responses.RequestsMock() as rsps: # Now consent has been given, consent service returns 200 OK rsps.add(responses.GET, consent_verify_endpoint_regex, status=200, body=json.dumps(FILTER)) context = Context() context.state = state context, internal_response = consent_module._handle_consent_response(context) assert internal_response.get_attributes()["displayName"] == ["Test"] assert internal_response.get_attributes()["co"] == ["example"] assert "sn" not in internal_response.get_attributes() # 'sn' should be filtered
def test_start_auth_no_request_info(self, sp_conf): """ Performs a complete test for the module satosa.backends.saml2. The flow should be accepted. """ disco_srv = "https://my.dicso.com/role/idp.ds" samlbackend = SamlBackend( None, INTERNAL_ATTRIBUTES, { "config": sp_conf, "disco_srv": disco_srv, "state_id": "saml_backend_test_id" }) internal_data = InternalRequest(None, None) state = State() context = Context() context.state = state resp = samlbackend.start_auth(context, internal_data) assert resp.status == "303 See Other", "Must be a redirect to the discovery server." assert resp.message.startswith("https://my.dicso.com/role/idp.ds"), \ "Redirect to wrong URL." # create_name_id_policy_transient() state = State() context = Context() context.state = state user_id_hash_type = UserIdHashType.transient internal_data = InternalRequest(user_id_hash_type, None) resp = samlbackend.start_auth(context, internal_data) assert resp.status == "303 See Other", "Must be a redirect to the discovery server."
def test_start_auth_disco(self, sp_conf, idp_conf): """ Performs a complete test for the module satosa.backends.saml2. The flow should be accepted. """ samlbackend = SamlBackend(lambda context, internal_resp: (context, internal_resp), INTERNAL_ATTRIBUTES, {"config": sp_conf, "disco_srv": "https://my.dicso.com/role/idp.ds", "state_id": "saml_backend_test_id"}) test_state_key = "test_state_key_456afgrh" response_binding = BINDING_HTTP_REDIRECT fakeidp = FakeIdP(USERS, config=IdPConfig().load(idp_conf, metadata_construction=False)) internal_req = InternalRequest(UserIdHashType.persistent, "example.se/sp.xml") state = State() state.add(test_state_key, "my_state") context = Context() context.state = state resp = samlbackend.start_auth(context, internal_req) assert resp.status == "303 See Other", "Must be a redirect to the discovery server." disco_resp = parse_qs(urlparse(resp.message).query) info = parse_qs(urlparse(disco_resp["return"][0]).query) info[samlbackend.idp_disco_query_param] = idp_conf["entityid"] context = Context() context.request = info context.state = state resp = samlbackend.disco_response(context) assert resp.status == "303 See Other" req_params = dict(parse_qsl(urlparse(resp.message).query)) url, fake_idp_resp = fakeidp.handle_auth_req( req_params["SAMLRequest"], req_params["RelayState"], BINDING_HTTP_REDIRECT, "testuser1", response_binding=response_binding) context = Context() context.request = fake_idp_resp context.state = state context, internal_resp = samlbackend.authn_response(context, response_binding) assert isinstance(context, Context), "Not correct instance!" assert context.state.get(test_state_key) == "my_state", "Not correct state!" assert internal_resp.auth_info.auth_class_ref == PASSWORD, "Not correct authentication!" _dict = internal_resp.get_attributes() expected_data = {'surname': ['Testsson 1'], 'mail': ['*****@*****.**'], 'displayname': ['Test Testsson'], 'givenname': ['Test 1'], 'edupersontargetedid': ['one!for!all']} for key in _dict: assert expected_data[key] == _dict[key]
def test_with_pyoidc(self): responses.add(responses.POST, "https://graph.facebook.com/v2.5/oauth/access_token", body=json.dumps({ "access_token": "qwerty", "token_type": "bearer", "expires_in": 9999999999999 }), adding_headers={"set-cookie": "TEST=testing; path=/"}, status=200, content_type='application/json') responses.add(responses.GET, "https://graph.facebook.com/v2.5/me", match_querystring=False, body=json.dumps(FB_RESPONSE), status=200, content_type='application/json') context = Context() context.path = 'facebook/sso/redirect' context.state = State() internal_request = InternalRequest(UserIdHashType.transient, 'http://localhost:8087/sp.xml') get_state = Mock() get_state.return_value = STATE resp = self.fb_backend.start_auth(context, internal_request, get_state) context.cookie = resp.headers[0][1] context.request = {"code": FB_RESPONSE_CODE, "state": STATE} self.fb_backend.auth_callback_func = self.verify_callback self.fb_backend.authn_response(context)
def test_start_auth_name_id_policy(self, sp_conf): """ Performs a complete test for the module satosa.backends.saml2. The flow should be accepted. """ samlbackend = SamlBackend( None, INTERNAL_ATTRIBUTES, { "config": sp_conf, "disco_srv": "https://my.dicso.com/role/idp.ds", "state_id": "saml_backend_test_id" }) test_state_key = "sauyghj34589fdh" state = State() state.add(test_state_key, "my_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", "Must be a redirect to the discovery server." disco_resp = parse_qs(urlparse(resp.message).query) sp_disco_resp = \ sp_conf["service"]["sp"]["endpoints"]["discovery_response"][0][0] assert "return" in disco_resp and disco_resp["return"][0].startswith(sp_disco_resp), \ "Not a valid return url in the call to the discovery server" assert "entityID" in disco_resp and disco_resp["entityID"][0] == sp_conf["entityid"], \ "Not a valid entity id in the call to the discovery server" request_info_tmp = context.state assert request_info_tmp.get( test_state_key) == "my_state", "Wrong state!"
def test_attributes_general(self, ldap_attribute_store): ldap_to_internal_map = (self.ldap_attribute_store_config['default'] ['ldap_to_internal_map']) for dn, attributes in self.ldap_person_records: # Mock up the internal response the LDAP attribute store is # expecting to receive. response = InternalData(auth_info=AuthenticationInformation()) # The LDAP attribute store configuration and the mock records # expect to use a LDAP search filter for the uid attribute. uid = attributes['uid'] response.attributes = {'uid': uid} context = Context() context.state = dict() ldap_attribute_store.process(context, response) # Verify that the LDAP attribute store has retrieved the mock # records from the mock LDAP server and has added the appropriate # internal attributes. for ldap_attr, ldap_value in attributes.items(): if ldap_attr in ldap_to_internal_map: internal_attr = ldap_to_internal_map[ldap_attr] response_attr = response.attributes[internal_attr] assert(ldap_value in response_attr)
def test_consent_not_given(self, context, consent_config, internal_response, internal_request, consent_verify_endpoint_regex, consent_registration_endpoint_regex): expected_ticket = "my_ticket" responses.add(responses.GET, consent_verify_endpoint_regex, status=401) responses.add(responses.GET, consent_registration_endpoint_regex, status=200, body=expected_ticket) requester_name = internal_response.requester_name context.state[consent.STATE_KEY] = {} resp = self.consent_module.process(context, internal_response) self.assert_redirect(resp, expected_ticket) self.assert_registration_req(responses.calls[1].request, internal_response, consent_config["sign_key"], self.consent_module.base_url, requester_name) new_context = Context() new_context.state = context.state # Verify endpoint of consent service still gives 401 (no consent given) context, internal_response = self.consent_module._handle_consent_response( context) assert not internal_response.attributes
def test_start_auth_name_id_policy(self, sp_conf): """ Performs a complete test for the module satosa.backends.saml2. The flow should be accepted. """ samlbackend = SamlBackend(None, INTERNAL_ATTRIBUTES, {"config": sp_conf, "disco_srv": "https://my.dicso.com/role/idp.ds", "state_id": "saml_backend_test_id"}) test_state_key = "sauyghj34589fdh" state = State() state.add(test_state_key, "my_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", "Must be a redirect to the discovery server." disco_resp = parse_qs(urlparse(resp.message).query) sp_disco_resp = \ sp_conf["service"]["sp"]["endpoints"]["discovery_response"][0][0] assert "return" in disco_resp and disco_resp["return"][0].startswith(sp_disco_resp), \ "Not a valid return url in the call to the discovery server" assert "entityID" in disco_resp and disco_resp["entityID"][0] == sp_conf["entityid"], \ "Not a valid entity id in the call to the discovery server" request_info_tmp = context.state assert request_info_tmp.get(test_state_key) == "my_state", "Wrong state!"
def test_with_pyoidc(self): responses.add(responses.POST, "https://graph.facebook.com/v2.5/oauth/access_token", body=json.dumps({"access_token": "qwerty", "token_type": "bearer", "expires_in": 9999999999999}), adding_headers={"set-cookie": "TEST=testing; path=/"}, status=200, content_type='application/json') responses.add(responses.GET, "https://graph.facebook.com/v2.5/me", match_querystring=False, body=json.dumps(FB_RESPONSE), status=200, content_type='application/json') context = Context() context.path = 'facebook/sso/redirect' context.state = State() internal_request = InternalRequest(UserIdHashType.transient, 'http://localhost:8087/sp.xml') get_state = Mock() get_state.return_value = STATE resp = self.fb_backend.start_auth(context, internal_request, get_state) context.cookie = resp.headers[0][1] context.request = { "code": FB_RESPONSE_CODE, "state": STATE } self.fb_backend.auth_callback_func = self.verify_callback self.fb_backend.authn_response(context)
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 test_redirect_to_login_at_auth_endpoint(self): self.fake_op.setup_webfinger_endpoint() self.fake_op.setup_opienid_config_endpoint() self.fake_op.setup_client_registration_endpoint() context = Context() context.state = State() auth_response = self.openid_backend.start_auth(context, None) assert auth_response._status == Redirect._status
def test_full_flow(self, context, idp_conf, sp_conf): test_state_key = "test_state_key_456afgrh" response_binding = BINDING_HTTP_REDIRECT fakeidp = FakeIdP(USERS, config=IdPConfig().load(idp_conf, metadata_construction=False)) context.state[test_state_key] = "my_state" # start auth flow (redirecting to discovery server) resp = self.samlbackend.start_auth(context, InternalRequest(None, None)) self.assert_redirect_to_discovery_server(resp, sp_conf) # fake response from discovery server disco_resp = parse_qs(urlparse(resp.message).query) info = parse_qs(urlparse(disco_resp["return"][0]).query) info["entityID"] = idp_conf["entityid"] request_context = Context() request_context.request = info request_context.state = context.state # pass discovery response to backend and check that it redirects to the selected IdP resp = self.samlbackend.disco_response(request_context) self.assert_redirect_to_idp(resp, idp_conf) # fake auth response to the auth request req_params = dict(parse_qsl(urlparse(resp.message).query)) url, fake_idp_resp = fakeidp.handle_auth_req( req_params["SAMLRequest"], req_params["RelayState"], BINDING_HTTP_REDIRECT, "testuser1", response_binding=response_binding) response_context = Context() response_context.request = fake_idp_resp response_context.state = request_context.state # pass auth response to backend and verify behavior self.samlbackend.authn_response(response_context, response_binding) context, internal_resp = self.samlbackend.auth_callback_func.call_args[ 0] assert self.samlbackend.name not in context.state assert context.state[test_state_key] == "my_state" self.assert_authn_response(internal_resp)
def test_frontend(path, provider, receiver, endpoint): context = Context() context.state = State() context.path = path spec = router.endpoint_routing(context) assert spec[0] == receiver assert spec[1] == endpoint assert context.target_frontend == receiver assert context.target_backend == provider
def test_set_state_in_start_auth_and_use_in_redirect_endpoint(self): self.fake_op.setup_webfinger_endpoint() self.fake_op.setup_opienid_config_endpoint() self.fake_op.setup_client_registration_endpoint() context = Context() context.state = State() self.openid_backend.start_auth(context, None) context = self.setup_fake_op_endpoints(FakeOP.STATE) self.openid_backend.redirect_endpoint(context)
def test_test_restore_state_with_separate_backends(self): openid_backend_1 = OpenIdBackend(MagicMock, INTERNAL_ATTRIBUTES, TestConfiguration.get_instance().config) openid_backend_2 = OpenIdBackend(MagicMock, INTERNAL_ATTRIBUTES, TestConfiguration.get_instance().config) self.fake_op.setup_webfinger_endpoint() self.fake_op.setup_opienid_config_endpoint() self.fake_op.setup_client_registration_endpoint() context = Context() context.state = State() openid_backend_1.start_auth(context, None) context = self.setup_fake_op_endpoints(FakeOP.STATE) openid_backend_2.redirect_endpoint(context)
def test_full_flow(self, context, idp_conf, sp_conf): test_state_key = "test_state_key_456afgrh" response_binding = BINDING_HTTP_REDIRECT fakeidp = FakeIdP(USERS, config=IdPConfig().load(idp_conf, metadata_construction=False)) context.state[test_state_key] = "my_state" # start auth flow (redirecting to discovery server) resp = self.samlbackend.start_auth(context, InternalData()) self.assert_redirect_to_discovery_server(resp, sp_conf) # fake response from discovery server disco_resp = parse_qs(urlparse(resp.message).query) info = parse_qs(urlparse(disco_resp["return"][0]).query) info["entityID"] = idp_conf["entityid"] request_context = Context() request_context.request = info request_context.state = context.state # pass discovery response to backend and check that it redirects to the selected IdP resp = self.samlbackend.disco_response(request_context) self.assert_redirect_to_idp(resp, idp_conf) # fake auth response to the auth request req_params = dict(parse_qsl(urlparse(resp.message).query)) url, fake_idp_resp = fakeidp.handle_auth_req( req_params["SAMLRequest"], req_params["RelayState"], BINDING_HTTP_REDIRECT, "testuser1", response_binding=response_binding) response_context = Context() response_context.request = fake_idp_resp response_context.state = request_context.state # pass auth response to backend and verify behavior self.samlbackend.authn_response(response_context, response_binding) context, internal_resp = self.samlbackend.auth_callback_func.call_args[0] assert self.samlbackend.name not in context.state assert context.state[test_state_key] == "my_state" self.assert_authn_response(internal_resp)
def test_routing(path, provider, receiver, _): context = Context() context.path = path context.state = state router.endpoint_routing(context) backend = router.backend_routing(context) assert backend == backends[provider] frontend = router.frontend_routing(context) assert frontend == frontends[receiver] assert context.target_frontend == receiver
def setup_authentication_response(self, state=None): context = Context() context.path = 'openid/authz_cb' op_base = TestConfiguration.get_instance().rp_config.OP_URL if not state: state = rndstr() context.request = { 'code': 'F+R4uWbN46U+Bq9moQPC4lEvRd2De4o=', 'scope': 'openid profile email address phone', 'state': state} context.state = self.generate_state(op_base) return context
def test_consent_full_flow(self, internal_response, internal_request, consent_verify_endpoint_regex, consent_registration_endpoint_regex): consent_config = SATOSAConfig(self.satosa_config) consent_module = ConsentModule(consent_config, identity_callback) expected_ticket = "my_ticket" context = Context() state = State() context.state = state consent_module.save_state(internal_request, state) with responses.RequestsMock() as rsps: rsps.add(responses.GET, consent_verify_endpoint_regex, status=401) rsps.add(responses.GET, consent_registration_endpoint_regex, status=200, body=expected_ticket) resp = consent_module.manage_consent(context, internal_response) self.assert_redirect(resp, expected_ticket) self.assert_registstration_req(rsps.calls[1].request, consent_config.CONSENT["sign_key"]) with responses.RequestsMock() as rsps: # Now consent has been given, consent service returns 200 OK rsps.add(responses.GET, consent_verify_endpoint_regex, status=200, body=json.dumps(FILTER)) context = Context() context.state = state context, internal_response = consent_module._handle_consent_response( context) assert internal_response.get_attributes()["displayName"] == ["Test"] assert internal_response.get_attributes()["co"] == ["example"] assert "sn" not in internal_response.get_attributes( ) # 'sn' should be filtered
def setup_authentication_response(self, state=None): context = Context() context.path = 'openid/authz_cb' op_base = TestConfiguration.get_instance().rp_config.OP_URL if not state: state = rndstr() context.request = { 'code': 'F+R4uWbN46U+Bq9moQPC4lEvRd2De4o=', 'scope': 'openid profile email address phone', 'state': state } context.state = self.generate_state(op_base) return context
def test_generate_static(self): synthetic_attributes = {"": {"default": {"a0": "value1;value2"}}} authz_service = self.create_syn_service(synthetic_attributes) resp = InternalData(auth_info=AuthenticationInformation()) resp.attributes = { "a1": ["*****@*****.**"], } ctx = Context() ctx.state = dict() authz_service.process(ctx, resp) assert ("value1" in resp.attributes['a0']) assert ("value2" in resp.attributes['a0']) assert ("*****@*****.**" in resp.attributes['a1'])
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
def _handle_satosa_authentication_error(self, error): """ Sends a response to the requestor about the error :type error: satosa.exception.SATOSAAuthenticationError :rtype: satosa.response.Response :param error: The exception :return: response """ context = Context() context.state = error.state frontend = self.module_router.frontend_routing(context) return frontend.handle_backend_error(error)
def test_consent_prev_given(self, internal_response, internal_request, consent_verify_endpoint_regex): consent_config = SATOSAConfig(self.satosa_config) consent_module = ConsentModule(consent_config, identity_callback) responses.add(responses.GET, consent_verify_endpoint_regex, status=200, body=json.dumps(FILTER)) context = Context() state = State() context.state = state consent_module.save_state(internal_request, state) context, internal_response = consent_module.manage_consent(context, internal_response) assert context assert "displayName" in internal_response.get_attributes()
def test_generate_static(self): synthetic_attributes = { "": { "default": {"a0": "value1;value2" }} } authz_service = self.create_syn_service(synthetic_attributes) resp = InternalData(auth_info=AuthenticationInformation()) resp.attributes = { "a1": ["*****@*****.**"], } ctx = Context() ctx.state = dict() authz_service.process(ctx, resp) assert("value1" in resp.attributes['a0']) assert("value2" in resp.attributes['a0']) assert("*****@*****.**" in resp.attributes['a1'])
def test_authz_deny_fail(self): attribute_deny = {"": {"default": {"a0": ['foo1', 'foo2']}}} attribute_allow = {} authz_service = self.create_authz_service(attribute_allow, attribute_deny) resp = InternalResponse(AuthenticationInformation(None, None, None)) resp.attributes = { "a0": ["foo3"], } try: ctx = Context() ctx.state = dict() authz_service.process(ctx, resp) except SATOSAAuthenticationError as ex: assert False
def test_test_restore_state_with_separate_backends(self): openid_backend_1 = OpenIdBackend( MagicMock, INTERNAL_ATTRIBUTES, TestConfiguration.get_instance().config) openid_backend_2 = OpenIdBackend( MagicMock, INTERNAL_ATTRIBUTES, TestConfiguration.get_instance().config) self.fake_op.setup_webfinger_endpoint() self.fake_op.setup_opienid_config_endpoint() self.fake_op.setup_client_registration_endpoint() context = Context() context.state = State() openid_backend_1.start_auth(context, None) context = self.setup_fake_op_endpoints(FakeOP.STATE) openid_backend_2.redirect_endpoint(context)
def test_authz_allow_second(self): attribute_allow = {"": {"default": {"a0": ['foo1', 'foo2']}}} attribute_deny = {} authz_service = self.create_authz_service(attribute_allow, attribute_deny) resp = InternalData(auth_info=AuthenticationInformation()) resp.attributes = { "a0": ["foo2", "kaka"], } try: ctx = Context() ctx.state = dict() authz_service.process(ctx, resp) except SATOSAAuthenticationError as ex: assert False
def test_authz_deny_fail(self): attribute_deny = { "": { "default": {"a0": ['foo1','foo2']} } } attribute_allow = {} authz_service = self.create_authz_service(attribute_allow, attribute_deny) resp = InternalData(auth_info=AuthenticationInformation()) resp.attributes = { "a0": ["foo3"], } try: ctx = Context() ctx.state = dict() authz_service.process(ctx, resp) except SATOSAAuthenticationError as ex: assert False
def setup_for_authn_response(self, auth_req): context = Context() context.state = self.create_state(auth_req) auth_info = AuthenticationInformation(PASSWORD, "2015-09-30T12:21:37Z", "unittest_idp.xml") internal_response = InternalResponse(auth_info=auth_info) internal_response.add_attributes( DataConverter(INTERNAL_ATTRIBUTES).to_internal("saml", USERS["testuser1"])) internal_response.set_user_id(USERS["testuser1"]["eduPersonTargetedID"][0]) self.instance.provider.cdb = { "client1": {"response_types": ["id_token"], "redirect_uris": [(auth_req["redirect_uri"], None)], "client_salt": "salt"}} return context, internal_response
def test_generate_mustache2(self): synthetic_attributes = { "": { "default": {"a0": "{{kaka.first}}#{{eppn.scope}}" }} } authz_service = self.create_syn_service(synthetic_attributes) resp = InternalData(auth_info=AuthenticationInformation()) resp.attributes = { "kaka": ["kaka1","kaka2"], "eppn": ["*****@*****.**","*****@*****.**"] } ctx = Context() ctx.state = dict() authz_service.process(ctx, resp) assert("kaka1#example.com" in resp.attributes['a0']) assert("kaka1" in resp.attributes['kaka']) assert("*****@*****.**" in resp.attributes['eppn']) assert("*****@*****.**" in resp.attributes['eppn'])
def test_consent_handles_connection_error(self, internal_response, internal_request, consent_verify_endpoint_regex): consent_config = SATOSAConfig(self.satosa_config) consent_module = ConsentModule(consent_config, identity_callback) state = State() context = Context() context.state = state consent_module.save_state(internal_request, state) with responses.RequestsMock(assert_all_requests_are_fired=True) as rsps: rsps.add(responses.GET, consent_verify_endpoint_regex, body=requests.ConnectionError("No connection")) context, internal_response = consent_module.manage_consent(context, internal_response) assert context assert not internal_response.get_attributes()
def test_consent_prev_given(self, internal_response, internal_request, consent_verify_endpoint_regex): consent_config = SATOSAConfig(self.satosa_config) consent_module = ConsentModule(consent_config, identity_callback) responses.add(responses.GET, consent_verify_endpoint_regex, status=200, body=json.dumps(FILTER)) context = Context() state = State() context.state = state consent_module.save_state(internal_request, state) context, internal_response = consent_module.manage_consent( context, internal_response) assert context assert "displayName" in internal_response.get_attributes()
def test_attribute_policy(self): requester = "requester" attribute_policies = { "attribute_policy": { "requester_everything_allowed": {}, "requester_nothing_allowed": { "allowed": {} }, "requester_subset_allowed": { "allowed": { "attr1", "attr2", }, }, }, } attributes = { "attr1": ["foo"], "attr2": ["foo", "bar"], "attr3": ["foo"] } results = { "requester_everything_allowed": attributes.keys(), "requester_nothing_allowed": set(), "requester_subset_allowed": {"attr1", "attr2"}, } for requester, result in results.items(): attribute_policy_service = self.create_attribute_policy_service( attribute_policies) ctx = Context() ctx.state = dict() resp = InternalData(auth_info=AuthenticationInformation()) resp.requester = requester resp.attributes = { "attr1": ["foo"], "attr2": ["foo", "bar"], "attr3": ["foo"] } filtered = attribute_policy_service.process(ctx, resp) assert (filtered.attributes.keys() == result)
def test_start_auth(self): context = Context() context.path = 'facebook/sso/redirect' context.state = State() internal_request = InternalRequest(UserIdHashType.transient, 'http://localhost:8087/sp.xml') get_state = Mock() get_state.return_value = STATE resp = self.fb_backend.start_auth(context, internal_request, get_state) # assert resp.headers[0][0] == "Set-Cookie", "Not the correct return cookie" # assert len(resp.headers[0][1]) > 1, "Not the correct return cookie" resp_url = resp.message.split("?") test_url = FB_REDIRECT_URL.split("?") resp_attr = parse_qs(resp_url[1]) test_attr = parse_qs(test_url[1]) assert resp_url[0] == test_url[0] assert len(resp_attr) == len(test_attr), "Redirect url is not correct!" for key in test_attr: assert key in resp_attr, "Redirect url is not correct!" assert test_attr[key] == resp_attr[key], "Redirect url is not correct!"
def test_authn_response(self): context = Context() context.path = 'facebook/sso/redirect' context.state = State() internal_request = InternalRequest(UserIdHashType.transient, 'http://localhost:8087/sp.xml') get_state = Mock() get_state.return_value = STATE resp = self.fb_backend.start_auth(context, internal_request, get_state) context.cookie = resp.headers[0][1] context.request = {"code": FB_RESPONSE_CODE, "state": STATE} # context.request = json.dumps(context.request) self.fb_backend.auth_callback_func = self.verify_callback tmp_consumer = self.fb_backend.get_consumer() tmp_consumer.do_access_token_request = self.verify_do_access_token_request self.fb_backend.get_consumer = Mock() self.fb_backend.get_consumer.return_value = tmp_consumer self.fb_backend.request_fb = self.verify_request_fb self.fb_backend.authn_response(context)
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)
def test_consent_handles_connection_error(self, internal_response, internal_request, consent_verify_endpoint_regex): consent_config = SATOSAConfig(self.satosa_config) consent_module = ConsentModule(consent_config, identity_callback) state = State() context = Context() context.state = state consent_module.save_state(internal_request, state) with responses.RequestsMock( assert_all_requests_are_fired=True) as rsps: rsps.add(responses.GET, consent_verify_endpoint_regex, body=requests.ConnectionError("No connection")) context, internal_response = consent_module.manage_consent( context, internal_response) assert context assert not internal_response.get_attributes()
def test_generate_mustache_empty_attribute(self): synthetic_attributes = { "": { "default": { "a0": "{{kaka.first}}#{{eppn.scope}}" } } } authz_service = self.create_syn_service(synthetic_attributes) resp = InternalData(auth_info=AuthenticationInformation()) resp.attributes = { "kaka": ["kaka1", "kaka2"], "eppn": None, } ctx = Context() ctx.state = dict() authz_service.process(ctx, resp) assert ("kaka1#" in resp.attributes['a0']) assert ("kaka1" in resp.attributes['kaka']) assert ("kaka2" in resp.attributes['kaka'])
def setUp(self): context = Context() context.state = State() config = { 'disco_endpoints': [ '.*/disco', ], } plugin = DiscoToTargetIssuer( config=config, name='test_disco_to_target_issuer', base_url='https://satosa.example.org', ) plugin.next = lambda ctx, data: (ctx, data) self.config = config self.context = context self.plugin = plugin
def test_generate_mustache1(self): synthetic_attributes = { "": { "default": { "a0": "{{kaka}}#{{eppn.scope}}" } } } authz_service = self.create_syn_service(synthetic_attributes) resp = InternalData(auth_info=AuthenticationInformation()) resp.attributes = { "kaka": ["kaka1"], "eppn": ["*****@*****.**", "*****@*****.**"] } ctx = Context() ctx.state = dict() authz_service.process(ctx, resp) assert ("kaka1#example.com" in resp.attributes['a0']) assert ("kaka1" in resp.attributes['kaka']) assert ("*****@*****.**" in resp.attributes['eppn']) assert ("*****@*****.**" in resp.attributes['eppn'])
def test_authn_response(self): context = Context() context.path = 'facebook/sso/redirect' context.state = State() internal_request = InternalRequest(UserIdHashType.transient, 'http://localhost:8087/sp.xml') get_state = Mock() get_state.return_value = STATE resp = self.fb_backend.start_auth(context, internal_request, get_state) context.cookie = resp.headers[0][1] context.request = { "code": FB_RESPONSE_CODE, "state": STATE } # context.request = json.dumps(context.request) self.fb_backend.auth_callback_func = self.verify_callback tmp_consumer = self.fb_backend.get_consumer() tmp_consumer.do_access_token_request = self.verify_do_access_token_request self.fb_backend.get_consumer = Mock() self.fb_backend.get_consumer.return_value = tmp_consumer self.fb_backend.request_fb = self.verify_request_fb self.fb_backend.authn_response(context)
def setUp(self): context = Context() context.state = State() config = { 'default_backend': 'default_backend', 'target_mapping': { 'mapped_idp.example.org': 'mapped_backend', }, } plugin = DecideBackendByTargetIssuer( config=config, name='test_decide_service', base_url='https://satosa.example.org', ) plugin.next = lambda ctx, data: (ctx, data) self.config = config self.context = context self.plugin = plugin
def test_micro_service(): """ Test the micro service flow """ data_list = ["1", "2", "3"] service_list = [] for d in data_list: service = MicroService() service.process = create_process_func(d) service_list.append(service) service_queue = build_micro_service_queue(service_list) test_data = "test_data" context = Context() context.state = State() data = service_queue.process_service_queue(context, test_data) for d in data_list: test_data = "{}{}".format(test_data, d) assert data == test_data
def test_start_auth(self): context = Context() context.path = 'facebook/sso/redirect' context.state = State() internal_request = InternalRequest(UserIdHashType.transient, 'http://localhost:8087/sp.xml') get_state = Mock() get_state.return_value = STATE resp = self.fb_backend.start_auth(context, internal_request, get_state) # assert resp.headers[0][0] == "Set-Cookie", "Not the correct return cookie" # assert len(resp.headers[0][1]) > 1, "Not the correct return cookie" resp_url = resp.message.split("?") test_url = FB_REDIRECT_URL.split("?") resp_attr = parse_qs(resp_url[1]) test_attr = parse_qs(test_url[1]) assert resp_url[0] == test_url[0] assert len(resp_attr) == len(test_attr), "Redirect url is not correct!" for key in test_attr: assert key in resp_attr, "Redirect url is not correct!" assert test_attr[key] == resp_attr[ key], "Redirect url is not correct!"
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
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)
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 test_mirco_service_error(): """ Test that the process_service_queue raises a SATOSAAuthenticationError if anything goes wrong with a micro service """ data_list = ["1", "2", "3"] service_list = [] fail_service = MicroService() fail_service.process = create_process_fail_func("4") service_list.append(fail_service) for d in data_list: service = MicroService() service.process = create_process_func(d) service_list.append(service) service_queue = build_micro_service_queue(service_list) test_data = "test_data" context = Context() context.state = State() with pytest.raises(SATOSAAuthenticationError): service_queue.process_service_queue(context, test_data)
def test_consent_not_given(self, context, consent_config, internal_response, internal_request, consent_verify_endpoint_regex, consent_registration_endpoint_regex): expected_ticket = "my_ticket" responses.add(responses.GET, consent_verify_endpoint_regex, status=401) responses.add(responses.GET, consent_registration_endpoint_regex, status=200, body=expected_ticket) context.state[consent.STATE_KEY] = {"filter": [], "requester_name": None} resp = self.consent_module.process(context, internal_response) self.assert_redirect(resp, expected_ticket) self.assert_registration_req(responses.calls[1].request, internal_response, consent_config["sign_key"], self.consent_module.base_url, None) new_context = Context() new_context.state = context.state # Verify endpoint of consent service still gives 401 (no consent given) context, internal_response = self.consent_module._handle_consent_response(context) assert not internal_response.attributes
def context(): context = Context() context.state = State() return context