def test_config_loader_with_real_conf(request): config = SPConfig() config.load( conf.create_conf(sp_host='sp.example.com', idp_hosts=['idp.example.com'], metadata_file='remote_metadata_one_idp.xml')) return config
def get_saml_config(request): hostname = get_hostname(request) config = { 'xmlsec_binary': '/usr/bin/xmlsec1', 'entityid': 'https://{}{}/saml2/metadata/'.format(hostname, settings.RELATIVE_PATH), 'allow_unknown_attributes': True, 'debug': 1, 'service': { 'sp': { 'name': 'VPS Request', 'want_assertions_signed': False, 'want_response_signed': False, 'endpoints': { 'assertion_consumer_service': [ ('https://{}{}/saml2/acs/'.format(hostname, settings.RELATIVE_PATH), saml2.BINDING_HTTP_POST), ], 'single_logout_service': [ ('https://{}{}/saml2/ls/'.format(hostname, settings.RELATIVE_PATH), saml2.BINDING_HTTP_REDIRECT), ], }, 'attribute_map_dir': '{}/saml2/attributemaps/'.format(get_python_lib()), }, }, 'key_file': settings.HOST_KEY, # private part 'cert_file': settings.HOST_CERT, # public part 'metadata': { 'local': [settings.SAML_METADATA] } } return SPConfig().load(config)
def test_wayf(): c = SPConfig().load_file("server_conf") c.context = "sp" idps = c.metadata.with_descriptor("idpsso") ent = list(idps.values())[0] assert name(ent) == 'Example Co.' assert name(ent, "se") == 'Exempel AB' c.setup_logger() assert root_logger.level != logging.NOTSET assert root_logger.level == logging.INFO assert len(root_logger.handlers) == 1 assert isinstance(root_logger.handlers[0], logging.handlers.RotatingFileHandler) handler = root_logger.handlers[0] assert handler.backupCount == 5 try: assert handler.maxBytes == 100000 except AssertionError: assert handler.maxBytes == 500000 assert handler.mode == "a" assert root_logger.name == "saml2" assert root_logger.level == 20
def test_handle_authn_request_without_name_id_policy( self, idp_conf, sp_conf): """ Performs a complete test for the module. The flow should be accepted. """ context, samlfrontend = self.setup_for_authn_req(idp_conf, sp_conf, "") _, internal_req = samlfrontend.handle_authn_request( context, BINDING_HTTP_REDIRECT) assert internal_req.requestor == sp_conf["entityid"] auth_info = AuthenticationInformation(PASSWORD, "2015-09-30T12:21:37Z", "unittest_idp.xml") internal_response = InternalResponse(auth_info=auth_info) internal_response.set_user_id_hash_type(internal_req.user_id_hash_type) internal_response.add_attributes(USERS["testuser1"]) resp = samlfrontend.handle_authn_response(context, internal_response) resp_dict = parse_qs(urlparse(resp.message).query) fakesp = FakeSP(None, config=SPConfig().load(sp_conf, metadata_construction=False)) resp = fakesp.parse_authn_request_response( resp_dict['SAMLResponse'][0], BINDING_HTTP_REDIRECT) for key in resp.ava: assert USERS["testuser1"][key] == resp.ava[key]
def __init__(self, outgoing, internal_attributes, config): """ :type outgoing: (satosa.context.Context, satosa.internal_data.InternalResponse) -> satosa.response.Response :type internal_attributes: dict[str, dict[str, list[str] | str]] :type config: dict[str, Any] :param outgoing: Callback should be called by the module after the authorization in the backend is done. :param internal_attributes: Internal attribute map :param config: The module config """ super(SamlBackend, self).__init__(outgoing, internal_attributes) sp_config = SPConfig().load(copy.deepcopy(config["config"]), False) self.sp = Base(sp_config) self.idp_disco_query_param = "entityID" self.config = config self.attribute_profile = config.get("attribute_profile", "saml") self.bindings = [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST] self.discosrv = None self.state_id = config["state_id"] try: self.discosrv = config["disco_srv"] except KeyError: pass
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 get_auth_response(self, samlfrontend, context, internal_response, sp_conf, idp_metadata_str): sp_config = SPConfig().load(sp_conf, metadata_construction=False) 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 = samlfrontend._create_state_data(context, resp_args, "") context.state[samlfrontend.name] = request_state resp = samlfrontend.handle_authn_response(context, internal_response) sp_conf["metadata"]["inline"].append(idp_metadata_str) fakesp = FakeSP(sp_config) resp_dict = parse_qs(urlparse(resp.message).query) return fakesp.parse_authn_request_response( resp_dict["SAMLResponse"][0], BINDING_HTTP_REDIRECT)
def test_1(): c = SPConfig().load(sp1) c.context = "sp" print(c) assert c._sp_endpoints assert c._sp_name assert c._sp_idp md = c.metadata assert isinstance(md, MetadataStore) assert len(c._sp_idp) == 1 assert list(c._sp_idp.keys()) == ["urn:mace:example.com:saml:roland:idp"] assert list(c._sp_idp.values()) == [{ 'single_sign_on_service': { 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect': ('http://localhost:8088/sso/') } }] assert c.only_use_keys_in_metadata assert type(c.getattr("requested_authn_context")) is dict assert c.getattr("requested_authn_context").get( "authn_context_class_ref") == [ AUTHN_PASSWORD_PROTECTED, AUTHN_TIME_SYNC_TOKEN, ] assert c.getattr("requested_authn_context").get("comparison") == "exact"
def test_do_sp_sso_descriptor(): conf = SPConfig().load(SP) spsso = metadata.do_spsso_descriptor(conf) assert isinstance(spsso, md.SPSSODescriptor) assert _eq(spsso.keyswv(), [ 'authn_requests_signed', 'attribute_consuming_service', 'single_logout_service', 'protocol_support_enumeration', 'assertion_consumer_service', 'want_assertions_signed' ]) assert spsso.authn_requests_signed == "false" assert spsso.want_assertions_signed == "true" assert len(spsso.attribute_consuming_service) == 1 acs = spsso.attribute_consuming_service[0] print(acs.keyswv()) assert _eq(acs.keyswv(), [ 'requested_attribute', 'service_name', 'service_description', 'index' ]) assert acs.service_name[0].text == SP["name"] assert acs.service_description[0].text == SP["description"] assert len(acs.requested_attribute) == 4 assert acs.requested_attribute[0].friendly_name == "sn" assert acs.requested_attribute[0].name == 'urn:oid:2.5.4.4' assert acs.requested_attribute[0].name_format == NAME_FORMAT_URI assert acs.requested_attribute[0].is_required == "true"
def test_do_sp_sso_descriptor_2(): SP["service"]["sp"]["discovery_response"] = "http://example.com/sp/ds" conf = SPConfig().load(SP, metadata_construction=True) spsso = metadata.do_spsso_descriptor(conf) assert isinstance(spsso, md.SPSSODescriptor) print spsso.keyswv() assert _eq(spsso.keyswv(), ['authn_requests_signed', 'attribute_consuming_service', 'single_logout_service', 'protocol_support_enumeration', 'assertion_consumer_service', 'want_assertions_signed', 'extensions']) exts = spsso.extensions.extension_elements assert len(exts) == 1 print exts idpd = saml2.extension_element_to_element(exts[0], idpdisc.ELEMENT_FROM_STRING, namespace=idpdisc.NAMESPACE) print idpd assert idpd.location == "http://example.com/sp/ds" assert idpd.index == "0" assert idpd.binding == "urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol"
def 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_conf_syslog(): c = SPConfig().load_file("server_conf_syslog") c.context = "sp" # otherwise the logger setting is not changed root_logger.level = logging.NOTSET while root_logger.handlers: handler = root_logger.handlers[-1] root_logger.removeHandler(handler) handler.flush() handler.close() print(c.logger) c.setup_logger() assert root_logger.level != logging.NOTSET assert root_logger.level == logging.INFO assert len(root_logger.handlers) == 1 assert isinstance(root_logger.handlers[0], logging.handlers.SysLogHandler) handler = root_logger.handlers[0] print(handler.__dict__) assert handler.facility == "local3" assert handler.address == ('localhost', 514) if ((sys.version_info.major == 2 and sys.version_info.minor >= 7) or sys.version_info.major > 2): assert handler.socktype == 2 else: pass assert root_logger.name == "saml2" assert root_logger.level == 20
def test_sp_attr_policy2(self): # create a pysaml SP self.sp_conf = SPConfig() _sp_conf = copy.deepcopy(SAML_SP_CONFIG) _sp_conf['service']['sp']['required_attributes'] = [ 'email', 'givenName', 'eduPersonPrincipalName', 'sn', 'telexNumber' ] self.sp_conf.load(_sp_conf) # put sp metadata into IDP md store sp_metadata = entity_descriptor(self.sp_conf) with open(IDP_SP_METADATA_PATH + '/sp.xml', 'wb') as fd: fd.write(sp_metadata.to_string()) sp_client = Saml2Client(self.sp_conf) session_id, result = sp_client.prepare_for_authenticate( entityid=idp_eid, relay_state='/', binding=BINDING_HTTP_POST) url, data = extract_saml_authn_data(result) response = self.client.post(url, data, follow=True) # login again to update existing user on db login_response = self.client.post(login_url, data=self.login_data, follow=True) # is there a SAML response? saml_resp = re.findall(samlresponse_form_regexp, login_response.content.decode())
def test_conf_syslog(): c = SPConfig().load_file("server_conf_syslog") c.context = "sp" # otherwise the logger setting is not changed root_logger.level = logging.NOTSET root_logger.handlers = [] print c.logger c.setup_logger() assert root_logger.level != logging.NOTSET assert root_logger.level == logging.INFO assert len(root_logger.handlers) == 1 assert isinstance(root_logger.handlers[0], logging.handlers.SysLogHandler) handler = root_logger.handlers[0] print handler.__dict__ assert handler.facility == "local3" assert handler.address == ('localhost', 514) if sys.version >= (2, 7): assert handler.socktype == 2 else: pass assert root_logger.name == "saml2" assert root_logger.level == 20
def test(): with closing(Server(config_file=dotname("idp_all_conf"))) as idp: conf = SPConfig() conf.load_file(dotname("servera_conf")) sp = Saml2Client(conf) srvs = sp.metadata.single_sign_on_service(idp.config.entityid, BINDING_HTTP_REDIRECT) destination = srvs[0]["location"] req_id, req = sp.create_authn_request(destination, id="id1") info = http_redirect_message( req, destination, relay_state="RS", typ="SAMLRequest", sigalg=SIG_RSA_SHA1, sign=True, backend=sp.sec.sec_backend, ) verified_ok = False for param, val in info["headers"]: if param == "Location": _dict = parse_qs(val.split("?")[1]) _certs = idp.metadata.certs(sp.config.entityid, "any", "signing") for cert in _certs: if verify_redirect_signature(list_values2simpletons(_dict), sp.sec.sec_backend, cert[1]): verified_ok = True assert verified_ok
def get_saml2_config(module_path): module = imp.load_source('saml2_settings', module_path) conf = SPConfig() conf.load(module.SAML_CONFIG) return conf
def sp_configure(self, metadata_construction=False): """ Need to know where 4 different things are. The config, key_file and cert_file files and the attributemaps directory """ # Always first look in the present working directory sys.path.insert(0, self.args.path) if self.args.path != ".": sys.path.insert(0, ".") mod = import_module(self.args.spconfig) if self.args.path != ".": for param in ["attribute_map_dir", "key_file", "cert_file"]: if mod.CONFIG[param].startswith("/"): # Absolute path continue for _path in [".", self.args.path]: _obj = os.path.join(_path, mod.CONFIG[param]) _obj = os.path.normpath(_obj) if os.path.exists(_obj): mod.CONFIG[param] = _obj break self.sp_config = SPConfig().load(mod.CONFIG, metadata_construction) if not self.args.insecure: self.sp_config.verify_ssl_cert = False else: if self.args.ca_certs: self.sp_config.ca_certs = self.args.ca_certs else: self.sp_config.ca_certs = "../keys/cacert.pem"
def test_sp(): cnf = SPConfig() cnf.load_file("sp_1_conf") assert cnf.single_logout_services("urn:mace:example.com:saml:roland:idp", BINDING_HTTP_POST) == ["http://localhost:8088/slo"] assert cnf.endpoint("assertion_consumer_service") == \ ["http://lingon.catalogix.se:8087/"] assert len(cnf.idps()) == 1
def test_wayf(): c = SPConfig().load_file("server_conf") c.context = "sp" idps = c.metadata.with_descriptor("idpsso") ent = list(idps.values())[0] assert name(ent) == 'Example Co.' assert name(ent, "se") == 'Exempel AB'
def config_settings_loader(request: Optional[HttpRequest] = None) -> SPConfig: """ Utility function to load the pysaml2 configuration. The configuration can be modified based on the request being passed. This is the default config loader, which just loads the config from the settings. """ conf = SPConfig() conf.load(copy.deepcopy(settings.SAML_CONFIG)) return conf
def setup_class(self): self.server = FakeIDP("idp_all_conf") conf = SPConfig() conf.load_file("servera_conf") self.client = Saml2Client(conf) self.client.send = self.server.receive
def config_settings_loader(request=None): """Utility function to load the pysaml2 configuration. This is also the default config loader. """ conf = SPConfig() conf.load(copy.deepcopy(settings.SAML_CONFIG)) return conf
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 test_ecp(): cnf = SPConfig() cnf.load(ECP_SP) assert cnf.endpoint("assertion_consumer_service") == \ ["http://lingon.catalogix.se:8087/"] eid = cnf.ecp_endpoint("130.239.16.3") assert eid == "http://example.com/idp" eid = cnf.ecp_endpoint("130.238.20.20") assert eid is None
def test_signed_metadata_proper_str_bytes_handling(): sp_conf_2 = sp_conf.copy() sp_conf_2['key_file'] = full_path("test.key") sp_conf_2['cert_file'] = full_path("inc-md-cert.pem") # requires xmlsec binaries per https://pysaml2.readthedocs.io/en/latest/examples/sp.html sp_conf_2['xmlsec_binary'] = sigver.get_xmlsec_binary(["/opt/local/bin"]) cnf = SPConfig().load(sp_conf_2, metadata_construction=True) # This will raise TypeError if string/bytes handling is not correct sp_metadata = create_metadata_string('', config=cnf, sign=True)
def test_requested_attribute_name_format(): cnf = SPConfig().load(sp_conf, metadata_construction=True) ed = entity_descriptor(cnf) assert len(ed.spsso_descriptor.attribute_consuming_service) == 1 acs = ed.spsso_descriptor.attribute_consuming_service[0] assert len(acs.requested_attribute) == 4 for req_attr in acs.requested_attribute: assert req_attr.name_format == NAME_FORMAT_URI sp2 = copy.copy(sp_conf) sp2["service"]["sp"]["requested_attribute_name_format"] = NAME_FORMAT_BASIC cnf2 = SPConfig().load(sp2, metadata_construction=True) ed = entity_descriptor(cnf2) acs = ed.spsso_descriptor.attribute_consuming_service[0] assert len(acs.requested_attribute) == 4 for req_attr in acs.requested_attribute: assert req_attr.name_format == NAME_FORMAT_BASIC
def generate_sp_metadata(): form = MetadataForm() if request.method == 'POST' and form.validate_on_submit(): conf = SPConfig() context = "" conf.setattr(context, 'description', form.sp_description.data) conf.setattr(context, 'entityid', form.sp_entity_id.data) conf.setattr(context, 'encryption_type', 'signing') sp_endpoints = { 'single_logout_service': [(form.sp_single_logout_endpoint.data, 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'), (form.sp_back_channel_slo_endpoint.data, 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST')], 'assertion_consumer_service': [(form.sp_assertion_consumer_service_endpoint.data, 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST')] } conf.setattr(context, '_sp_endpoints', sp_endpoints) conf.setattr( context, 'cert_file', '/home/shiv0150/Projects/workspace/metadata/data/sso_cert') organization = { 'url': form.sp_entity_id.data, 'display_name': form.team_name.data, 'name': form.team_name.data } conf.setattr(context, 'organization', organization) contact_person = [{ 'telephone_number': form.technical_contact_telephone.data, 'email_address': form.technical_contact_email.data, 'sur_name': form.technical_contact_surname.data, 'given_name': form.technical_contact_firstname.data, 'contact_type': 'technical' }, { 'telephone_number': form.support_contact_telephone.data, 'email_address': form.support_contact_email.data, 'sur_name': form.support_contact_surname.data, 'given_name': form.support_contact_firstname.data, 'contact_type': 'support' }] conf.setattr(context, 'contact_person', contact_person) conf.setattr(context, 'serves', 'sp') conf.setattr(context, 'name_id_format', 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent') sp = generate_sp_meta.AstraServer(config=conf, stype='sp') sp_metadata = sp.create_sp_metadata() flash(sp_metadata) return redirect('/astra/tools/sp/generated_metadata') return render_template('metadata.html', title='Faws', form=form)
def test_entity_description(): #confd = eval(open("../tests/server.config").read()) confd = SPConfig().load_file("server_conf") print confd.attribute_converters entd = metadata.entity_descriptor(confd) assert entd is not None print entd.keyswv() assert _eq(entd.keyswv(), ['valid_until', 'entity_id', 'contact_person', 'spsso_descriptor', 'organization']) print entd assert entd.entity_id == "urn:mace:example.com:saml:roland:sp"
def test_handle_authn_request(self, context, idp_conf, sp_conf, internal_response): samlfrontend = self.setup_for_authn_req(context, idp_conf, sp_conf) _, internal_req = samlfrontend.handle_authn_request(context, BINDING_HTTP_REDIRECT) assert internal_req.requester == sp_conf["entityid"] resp = samlfrontend.handle_authn_response(context, internal_response) resp_dict = parse_qs(urlparse(resp.message).query) fakesp = FakeSP(SPConfig().load(sp_conf, metadata_construction=False)) resp = fakesp.parse_authn_request_response(resp_dict["SAMLResponse"][0], BINDING_HTTP_REDIRECT) for key in resp.ava: assert USERS["testuser1"][key] == resp.ava[key]