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 slo(self, request): """ generate a SAML2 logout request; reset session; return IDP URL """ session = request.SESSION session.set(self.session_auth_key, False) del session[self.session_user_properties] config = self._saml2_config() scl = Saml2Client(config) samluid = session.get(self.session_samluid_key, "") entityid = config.metadata.keys()[0] sp_url = self.saml2_sp_url actual_url = request.get("ACTUAL_URL", "") if not actual_url.startswith(sp_url): # the request was made from within a context we cannot handle return None session.set(self.session_storedurl_key, request.URL1) # we cannot simply call global_logout on the client since it doesn't know about our user... srvs = scl.metadata.single_logout_service(entityid, BINDING_HTTP_REDIRECT, "idpsso") destination = destinations(srvs)[0] samlrequest = scl.create_logout_request(destination, entityid, name_id=saml.NameID(text=samluid)) samlrequest.session_index = samlp.SessionIndex(session.get(self.session_samlsessionindex_key)) to_sign = [] samlrequest = signed_instance_factory(samlrequest, scl.sec, to_sign) logger.info("SSO logout request: %s" % samlrequest.to_string()) session_id = samlrequest.id rstate = scl._relay_state(session_id) msg = http_redirect_message(samlrequest, destination, rstate) headers = dict(msg["headers"]) location = headers["Location"] logger.info("attempting to post: {loc}".format(loc=headers["Location"])) return location
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") try: key = sp.sec.key except AttributeError: key = import_rsa_key_from_file(sp.sec.key_file) info = http_redirect_message(req, destination, relay_state="RS", typ="SAMLRequest", sigalg=SIG_RSA_SHA1, key=key) 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(_dict, cert): verified_ok = True assert verified_ok
def use_http_get(message, destination, relay_state, typ="SAMLRequest", sigalg="", signer=None, **kwargs): """ Send a message using GET, this is the HTTP-Redirect case so no direct response is expected to this request. :param message: :param destination: :param relay_state: :param typ: Whether a Request, Response or Artifact :param sigalg: Which algorithm the signature function will use to sign the message :param signer: A signing function that can be used to sign the message :return: dictionary """ if not isinstance(message, six.string_types): message = "%s" % (message, ) return http_redirect_message(message, destination, relay_state, typ, sigalg, signer)
def test(): srvs = sp.metadata.single_sign_on_service(idp.config.entityid, BINDING_HTTP_REDIRECT) destination = srvs[0]["location"] req = sp.create_authn_request(destination, id="id1") try: key = sp.sec.key except AttributeError: key = rsa_load(sp.sec.key_file) info = http_redirect_message(req, destination, relay_state="RS", typ="SAMLRequest", sigalg=RSA_SHA1, key=key) 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(_dict, cert): verified_ok = True assert verified_ok
def test(): 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") try: key = sp.sec.key except AttributeError: key = import_rsa_key_from_file(sp.sec.key_file) info = http_redirect_message(req, destination, relay_state="RS", typ="SAMLRequest", sigalg=RSA_SHA1, key=key) 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(_dict, cert): verified_ok = True assert verified_ok
def sp_initiated(idp_name): app.logger.debug('Space key: {}'.format("")) app.logger.debug('idp_name key: {}'.format(idp_name)) saml_client = saml_client_for(idp_name) reqCtx = requested_authn_context([config.get('authn_request_level')], comparison='exact') srvs = saml_client.metadata.single_sign_on_service( config.get('test_idp_url'), BINDING_HTTP_POST) reqid, req = saml_client.create_authn_request_spid( srvs[0]["location"], requested_authn_context=reqCtx, issuer=Issuer( name_qualifier=saml_client.config.getattr('organization').get( 'url'), format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity", text=config.get('hostname')), sign=False, allow_create=None, nsprefix={ "saml": saml.NAMESPACE, "samlp": samlp.NAMESPACE }) app.logger.debug('reqid: {}'.format(reqid)) app.logger.debug('req: {}'.format(req)) redirect_url = None # Select the IdP URL to send the AuthN request to signer = saml_client.sec.sec_backend.get_signer(SIG_RSA_SHA256) # signer = saml_client.sec.sec_backend.get_signer(SIG_RSA_SHA1) info = http_redirect_message(req, srvs[0]["location"], relay_state="user", typ="SAMLRequest", sigalg=SIG_RSA_SHA256, signer=signer) # info = http_redirect_message( # req, srvs[0]["location"], relay_state="RS", # typ="SAMLRequest") app.logger.debug('info: {}'.format(info)) for key, value in info['headers']: if key is 'Location': redirect_url = value response = redirect(redirect_url, code=302) response.headers['Cache-Control'] = 'no-cache, no-store' response.headers['Pragma'] = 'no-cache' return response
def use_http_get(self, message, destination, relay_state, typ="SAMLRequest", sign=False): """ Send a message using GET, this is the HTTP-Redirect case so no direct response is expected to this request. :param message: :param destination: :param relay_state: :param typ: Whether a Request, Response or Artifact :return: dictionary """ if not isinstance(message, basestring): message = "%s" % (message,) if sign: key = import_rsa_key_from_file(self.config.key_file) return http_redirect_message(message, destination, relay_state, typ, sigalg=RSA_SHA1, key=key) else: return http_redirect_message(message, destination, relay_state, typ)
def use_http_get(self, message, destination, relay_state): """ Send a message using GET, this is the HTTP-Redirect case so no direct response is expected to this request. :param request: :param destination: :param relay_state: :return: tuple (header, None) """ if not isinstance(message, basestring): request = "%s" % (message, ) return http_redirect_message(message, destination, relay_state)
def use_http_get(self, message, destination, relay_state): """ Send a message using GET, this is the HTTP-Redirect case so no direct response is expected to this request. :param request: :param destination: :param relay_state: :return: tuple (header, None) """ if not isinstance(message, basestring): request = "%s" % (message,) return http_redirect_message(message, destination, relay_state)
def use_http_get(message, destination, relay_state, typ="SAMLRequest"): """ Send a message using GET, this is the HTTP-Redirect case so no direct response is expected to this request. :param message: :param destination: :param relay_state: :param typ: Whether a Request, Response or Artifact :return: dictionary """ if not isinstance(message, str): message = "%s" % (message, ) return http_redirect_message(message, destination, relay_state, typ)
def use_http_get(self, message, destination, relay_state, typ="SAMLRequest"): """ Send a message using GET, this is the HTTP-Redirect case so no direct response is expected to this request. :param message: :param destination: :param relay_state: :param typ: Whether a Request, Response or Artifact :return: dictionary """ if not isinstance(message, basestring): message = "%s" % (message,) return http_redirect_message(message, destination, relay_state, typ)
def use_http_get(message, destination, relay_state, typ="SAMLRequest", sigalg="", key=None, **kwargs): """ Send a message using GET, this is the HTTP-Redirect case so no direct response is expected to this request. :param message: :param destination: :param relay_state: :param typ: Whether a Request, Response or Artifact :param sigalg: The signature algorithm to use. :param key: Key to use for signing :return: dictionary """ if not isinstance(message, six.string_types): message = "%s" % (message,) return http_redirect_message(message, destination, relay_state, typ, sigalg, key)
def use_http_get(message, destination, relay_state, typ="SAMLRequest", sigalg="", signer=None, **kwargs): """ Send a message using GET, this is the HTTP-Redirect case so no direct response is expected to this request. :param message: :param destination: :param relay_state: :param typ: Whether a Request, Response or Artifact :param sigalg: Which algorithm the signature function will use to sign the message :param signer: A signing function that can be used to sign the message :return: dictionary """ if not isinstance(message, six.string_types): message = "%s" % (message,) return http_redirect_message(message, destination, relay_state, typ, sigalg, signer)
def http_redirect_logout_request_check_session_index(self, get, session_index, log=None): """ Deal with a LogoutRequest received through HTTP redirect :param get: The request as a dictionary :param subject_id: the id of the current logged user :return: a tuple with a list of header tuples (presently only location) """ msg = {} try: saml_request = get['SAMLRequest'] except KeyError: return None if saml_request: xml = decode_base64_and_inflate(saml_request) logger.info('logout request: %s' % xml) request = samlp.logout_request_from_string(xml) logger.debug(request) if request.session_index[0].text == session_index: status = samlp.STATUS_SUCCESS else: status = samlp.STATUS_REQUEST_DENIED response, destination = self .make_logout_response( request.issuer.text, request.id, status) logger.info("RESPONSE: {0:>s}".format(response)) if 'RelayState' in get: rstate = get['RelayState'] else: rstate = "" msg = http_redirect_message(str(response), destination, rstate, 'SAMLResponse') return msg
def http_redirect_logout_request_check_session_index( self, get, session_index, log=None): """ Deal with a LogoutRequest received through HTTP redirect :param get: The request as a dictionary :param subject_id: the id of the current logged user :return: a tuple with a list of header tuples (presently only location) """ msg = {} try: saml_request = get['SAMLRequest'] except KeyError: return None if saml_request: xml = decode_base64_and_inflate(saml_request) logger.info('logout request: %s' % xml) request = samlp.logout_request_from_string(xml) logger.debug(request) if request.session_index[0].text == session_index: status = samlp.STATUS_SUCCESS else: status = samlp.STATUS_REQUEST_DENIED response, destination = self.make_logout_response( request.issuer.text, request.id, status) logger.info("RESPONSE: {0:>s}".format(response)) if 'RelayState' in get: rstate = get['RelayState'] else: rstate = "" msg = http_redirect_message(str(response), destination, rstate, 'SAMLResponse') return msg
def slo(self, request): """ generate a SAML2 logout request; reset session; return IDP URL """ session = request.SESSION session.set(self.session_auth_key, False) del session[self.session_user_properties] config = self._saml2_config() scl = Saml2Client(config) samluid = session.get(self.session_samluid_key, '') entityid = config.metadata.keys()[0] sp_url = self.saml2_sp_url actual_url = request.get("ACTUAL_URL", '') if not actual_url.startswith(sp_url): # the request was made from within a context we cannot handle return None session.set(self.session_storedurl_key, request.URL1) # we cannot simply call global_logout on the client since it doesn't know about our user... srvs = scl.metadata.single_logout_service(entityid, BINDING_HTTP_REDIRECT, "idpsso") destination = destinations(srvs)[0] samlrequest = scl.create_logout_request( destination, entityid, name_id=saml.NameID(text=samluid)) samlrequest.session_index = samlp.SessionIndex( session.get(self.session_samlsessionindex_key)) to_sign = [] samlrequest = signed_instance_factory(samlrequest, scl.sec, to_sign) logger.info('SSO logout request: %s' % samlrequest.to_string()) session_id = samlrequest.id rstate = scl._relay_state(session_id) msg = http_redirect_message(samlrequest, destination, rstate) headers = dict(msg['headers']) location = headers['Location'] logger.info( 'attempting to post: {loc}'.format(loc=headers['Location'])) return location
def _send(self, srv): _client = self.client loc = srv["location"] self.qargs["destination"] = loc self.response_args = {} use_artifact = getattr(self.oper, "use_artifact", False) try: req = self.oper.args["message"] except KeyError: req = self.qfunc(**self.qargs) req_id, self.request = self.oper.pre_processing(req, self.args) str_req = "%s" % self.request if use_artifact: saml_art = _client.use_artifact(str_req, self.args["entity_id"]) logger.info("SAML Artifact: %s" % saml_art) info_typ = "SAMLart" else: logger.info("SAML Request: %s" % str_req) info_typ = "SAMLRequest" # depending on binding send the query if self.args["request_binding"] is BINDING_SOAP: res = _client.send_using_soap(str_req, loc) if res.status_code >= 400: logger.info("Received a HTTP error (%d) '%s'" % ( res.status_code, res.text)) raise HTTPError(res.text) else: self.response_args["binding"] = BINDING_SOAP else: self.response_args["binding"] = self.args["response_binding"] if self.args["request_binding"] is BINDING_HTTP_REDIRECT: htargs = http_redirect_message(str_req, loc, self.relay_state, info_typ) self.response_args["outstanding"] = {self.request.id: "/"} # res = _client.send(htargs["headers"][0][1], "GET") elif self.args["request_binding"] is BINDING_HTTP_POST: htargs = http_form_post_message(str_req, loc, self.relay_state, info_typ) info = unpack_form(htargs["data"][3]) data = form_post(info) self.response_args["outstanding"] = {self.request.id: "/"} htargs["data"] = data htargs["headers"] = [("Content-type", 'application/x-www-form-urlencoded')] res = _client.send(loc, "POST", **htargs) elif self.args["request_binding"] == BINDING_URI: self.response_args["binding"] = BINDING_URI htargs = _client.use_http_uri(str_req, "SAMLRequest", loc) res = _client.send(htargs["url"], "GET") else: res = None if res is not None and res.status_code >= 400: logger.info("Received a HTTP error (%d) '%s'" % ( res.status_code, res.text)) raise HTTPError(res.text) self.last_response = res try: self.last_content = res.text except AttributeError: self.last_content = None return res
def _send(self, srv): _client = self.client loc = srv["location"] self.qargs["destination"] = loc self.response_args = {} use_artifact = getattr(self.oper, "use_artifact", False) try: req = self.oper.args["message"] except KeyError: req = self.qfunc(**self.qargs) req_id, self.request = self.oper.pre_processing(req, self.args) str_req = "%s" % self.request if use_artifact: saml_art = _client.use_artifact(str_req, self.args["entity_id"]) logger.info("SAML Artifact: %s", saml_art) info_typ = "SAMLart" else: logger.info("SAML Request: %s", str_req) info_typ = "SAMLRequest" # depending on binding send the query if self.args["request_binding"] is BINDING_SOAP: res = _client.send_using_soap(str_req, loc) if res.status_code >= 400: logger.info("Received a HTTP error (%d) '%s'", res.status_code, res.text) raise HTTPError(res.text) else: self.response_args["binding"] = BINDING_SOAP else: self.response_args["binding"] = self.args["response_binding"] if self.args["request_binding"] is BINDING_HTTP_REDIRECT: htargs = http_redirect_message(str_req, loc, self.relay_state, info_typ) self.response_args["outstanding"] = {self.request.id: "/"} # res = _client.send(htargs["headers"][0][1], "GET") elif self.args["request_binding"] is BINDING_HTTP_POST: htargs = http_form_post_message(str_req, loc, self.relay_state, info_typ) info = unpack_form(htargs["data"][3]) data = form_post(info) self.response_args["outstanding"] = {self.request.id: "/"} htargs["data"] = data htargs["headers"] = [("Content-type", 'application/x-www-form-urlencoded')] res = _client.send(loc, "POST", **htargs) elif self.args["request_binding"] == BINDING_URI: self.response_args["binding"] = BINDING_URI htargs = _client.use_http_uri(str_req, "SAMLRequest", loc) res = _client.send(htargs["url"], "GET") else: res = None if res is not None and res.status_code >= 400: logger.info("Received a HTTP error (%d) '%s'", res.status_code, res.text) raise HTTPError(res.text) self.last_response = res try: self.last_content = res.text except AttributeError: self.last_content = None return res