def ecp(self): # The ECP interface logger.info("--- ECP SSO ---") resp = None try: authz_info = self.environ["HTTP_AUTHORIZATION"] if authz_info.startswith("Basic "): _info = base64.b64decode(authz_info[6:]) logger.debug("Authz_info: %s" % _info) try: (user, passwd) = _info.split(":") #TODO USE THE SAME AUTHORIZATION MODULE AS FOR SIMPLE USERNAME/PASSWORD #See password.py #if PASSWD[user] != passwd: # resp = Unauthorized() self.user = user except ValueError: resp = Unauthorized() else: resp = Unauthorized() except KeyError: resp = Unauthorized() if resp: return resp(self.environ, self.start_response) _dict = self.unpack_soap() self.response_bindings = [BINDING_PAOS] # Basic auth ?! return self.operation(_dict, BINDING_SOAP)
def ecp(self): # The ECP interface logger.info("--- ECP SSO ---") resp = None try: authz_info = self.environ["HTTP_AUTHORIZATION"] if authz_info.startswith("Basic "): try: _info = base64.b64decode(authz_info[6:]) except TypeError: resp = Unauthorized() else: logger.debug("Authz_info: %s", _info) try: (user, passwd) = _info.split(":") if is_equal(PASSWD[user], passwd): resp = Unauthorized() self.user = user except (ValueError, TypeError): resp = Unauthorized() else: resp = Unauthorized() except KeyError: resp = Unauthorized() if resp: return resp(self.environ, self.start_response) _dict = self.unpack_soap() self.response_bindings = [BINDING_PAOS] # Basic auth ?! return self.operation(_dict, BINDING_SOAP)
def ecp(self): # The ECP interface logger.info("--- ECP SSO ---") resp = None try: authz_info = self.environ["HTTP_AUTHORIZATION"] if authz_info.startswith("Basic "): _info = base64.b64decode(authz_info[6:]) logger.debug("Authz_info: %s" % _info) try: (user, passwd) = _info.split(":") if PASSWD[user] != passwd: resp = Unauthorized() self.user = user self.environ[ "idp.authn"] = AUTHN_BROKER.get_authn_by_accr( PASSWORD) except ValueError: resp = Unauthorized() else: resp = Unauthorized() except KeyError: resp = Unauthorized() if resp: return resp(self.environ, self.start_response) _dict = self.unpack_soap() self.response_bindings = [BINDING_PAOS] # Basic auth ?! self.op_type = "ecp" return self.operation(_dict, BINDING_SOAP)
def authenticate(self, environ, start_response, reference, key, redirect_uri, **kwargs): session = Session(environ) params = HttpHandler.query_dictionary(environ) paramstr = None for tmpkey, value in params.items(): tmpparamstr = None if type(value) is list: for v in value: if tmpparamstr is None: tmpparamstr = "" else: tmpparamstr += "&" tmpparamstr = urllib.urlencode({tmpkey: v}) else: tmpparamstr = urllib.urlencode({tmpkey: value}) if paramstr is None: paramstr = "?" else: paramstr += "&" paramstr += tmpparamstr if self.MUTLIPLEAUTHENTICATIONCOUNTER not in session or session[self.MUTLIPLEAUTHENTICATIONCOUNTER] is None: session[self.MUTLIPLEAUTHENTICATIONCOUNTER] = 0 authn_method = session[self.MUTLIPLEAUTHENTICATIONCOUNTER] #query = Test how the url should be built up. The user should be redirected to this url as long #as all method is not tested. query = environ['PATH_INFO'] + paramstr session[self.MULTIPLEAUTHENTICATIONREDIRECT] = query if self.auth_list_lengt <= 0: resp = Unauthorized("No authentication method") return resp(environ, start_response) else: return self.auth_list[authn_method].authenticate(environ, start_response, reference, key, redirect_uri)
def run_server(self, environ, start_response, debug=False): path = environ.get('PATH_INFO', '').lstrip('/') if ".." in path: resp = Unauthorized() return resp(environ, start_response) context = Context() context.path = path # copy wsgi.input stream to allow it to be re-read later by satosa plugins # see: http://stackoverflow.com/questions/1783383/how-do-i-copy-wsgi-input-if-i-want-to-process-post-data-more-than-once content_length = int(environ.get('CONTENT_LENGTH', '0') or '0') body = io.BytesIO(environ['wsgi.input'].read(content_length)) environ['wsgi.input'] = body context.request = unpack_either(environ) environ['wsgi.input'].seek(0) context.wsgi_environ = environ context.cookie = environ.get("HTTP_COOKIE", "") try: resp = self.run(context) if isinstance(resp, Exception): raise resp return resp(environ, start_response) except SATOSANoBoundEndpointError: resp = NotFound("Couldn't find the side you asked for!") return resp(environ, start_response) except Exception as err: logger.exception("%s" % err) if debug: raise resp = ServiceError("%s" % err) return resp(environ, start_response)
def verify_request(self, query, binding): """ :param query: The SAML query, transport encoded :param binding: Which binding the query came in over """ if not query: logger.info("Missing QUERY") resp = Unauthorized('Unknown user') return resp(self.environ, self.start_response) if not self.req_info: self.req_info = IDP.parse_authn_request(query, binding) logger.info("parsed OK") _authn_req = self.req_info.message logger.debug("%s" % _authn_req) self.binding_out, self.destination = IDP.pick_binding( "assertion_consumer_service", bindings=self.response_bindings, entity_id=_authn_req.issuer.text) logger.debug("Binding: %s, destination: %s" % (self.binding_out, self.destination)) resp_args = {} try: resp_args = IDP.response_args(_authn_req) _resp = None except UnknownPrincipal, excp: _resp = IDP.create_error_response(_authn_req.id, self.destination, excp)
def authn_response(self, binding): """ :param binding: Which binding the query came in over :returns: Error response or a response constructed by the transfer function """ _authn_response = self.unpack(binding) if not _authn_response["SAMLResponse"]: logger.info("Missing Response") resp = Unauthorized('Unknown user') return resp(self.environ, self.start_response) binding = service.INV_BINDING_MAP[binding] try: _response = self.sp.parse_authn_request_response( _authn_response["SAMLResponse"], binding, self.cache) except UnknownPrincipal as excp: logger.error("UnknownPrincipal: %s" % (excp, )) resp = ServiceError("UnknownPrincipal: %s" % (excp, )) return resp(self.environ, self.start_response) except UnsupportedBinding as excp: logger.error("UnsupportedBinding: %s" % (excp, )) resp = ServiceError("UnsupportedBinding: %s" % (excp, )) return resp(self.environ, self.start_response) except VerificationError as err: resp = ServiceError("Verification error: %s" % (err, )) return resp(self.environ, self.start_response) except Exception as err: resp = ServiceError("Other error: %s" % (err, )) return resp(self.environ, self.start_response) return self.outgoing(_response, self)
def do_verify(environ, start_response, _): query = parse_qs(get_post(environ)) logger.debug("do_verify: %s", query) try: _ok, user = verify_username_and_password(query) except KeyError: _ok = False user = None if not _ok: resp = Unauthorized("Unknown user or wrong password") else: uid = rndstr(24) IDP.cache.uid2user[uid] = user IDP.cache.user2uid[user] = uid logger.debug("Register %s under '%s'", user, uid) kaka = set_cookie("idpauthn", "/", uid, query["authn_reference"][0]) lox = "%s?id=%s&key=%s" % (query["redirect_uri"][0], uid, query["key"][0]) logger.debug("Redirect => %s", lox) resp = Redirect(lox, headers=[kaka], content="text/html") return resp(environ, start_response)
def do(self, response, binding, relay_state="", mtype="response"): """ :param response: The SAML response, transport encoded :param binding: Which binding the query came in over """ #tmp_outstanding_queries = dict(self.outstanding_queries) if not response: logger.info("Missing Response") resp = Unauthorized('Unknown user') return resp(self.environ, self.start_response) try: self.response = self.sp.parse_authn_request_response( response, binding, self.outstanding_queries) except UnknownPrincipal as excp: logger.error("UnknownPrincipal: %s" % (excp,)) resp = ServiceError("UnknownPrincipal: %s" % (excp,)) return resp(self.environ, self.start_response) except UnsupportedBinding as excp: logger.error("UnsupportedBinding: %s" % (excp,)) resp = ServiceError("UnsupportedBinding: %s" % (excp,)) return resp(self.environ, self.start_response) except VerificationError as err: resp = ServiceError("Verification error: %s" % (err,)) return resp(self.environ, self.start_response) except Exception as err: resp = ServiceError("Other error: %s" % (err,)) return resp(self.environ, self.start_response) logger.info("AVA: %s" % self.response.ava) resp = Response(dict_to_table(self.response.ava)) return resp(self.environ, self.start_response)
def verify(self, request, **kwargs): """ Verifies that the given username and password was correct :param request: Either the query part of a URL a urlencoded body of a HTTP message or a parse such. :param kwargs: Catch whatever else is sent. :return: redirect back to where ever the base applications wants the user after authentication. """ #logger.debug("verify(%s)" % request) if isinstance(request, six.string_types): _dict = parse_qs(request) elif isinstance(request, dict): _dict = request else: raise ValueError("Wrong type of input") # verify username and password try: self._verify(_dict["password"][0], _dict["login"][0]) timestamp = str(int(time.mktime(time.gmtime()))) msg = "::".join([_dict["login"][0], timestamp]) info = self.symmetric.encrypt(msg.encode()) self.active[info] = timestamp cookie = make_cookie(self.cookie_name, info, self.srv.seed) return_to = create_return_url(self.return_to, _dict["query"][0], **{self.query_param: "true"}) resp = Redirect(return_to, headers=[cookie]) except (ValueError, KeyError): resp = Unauthorized("Unknown user or wrong password") return resp
def verify(self, environ, start_response): session = Session(environ) if self.MUTLIPLEAUTHENTICATIONCOUNTER in session: authn_method = session[self.MUTLIPLEAUTHENTICATIONCOUNTER] if authn_method > (self.auth_list_lengt - 1) or self.auth_list_lengt == 0: resp = Unauthorized("No authentication method") elif authn_method == (self.auth_list_lengt - 1): return self.auth_list[authn_method].verify(environ, start_response) else: _ok = self.auth_list[authn_method].verify_bool(environ, start_response) if _ok: session[self.MUTLIPLEAUTHENTICATIONCOUNTER] = authn_method + 1 resp = Redirect(session[self.MULTIPLEAUTHENTICATIONREDIRECT]) else: return self.auth_list[authn_method].verify(environ, start_response) else: resp = Unauthorized("No authentication method") return resp(environ, start_response)
def do_verify(self, environ, start_response, _): query = HttpHandler.query_dictionary(environ) authn_ref = self.authn_broker.pick()[0][0].get_authn_reference(query) if authn_ref is not None: authn = self.authn_broker[authn_ref] if authn: return authn["method"].verify(environ, start_response) resp = Unauthorized("") return resp(environ, start_response)
def verify(self, environ, start_response): request = HttpHandler.query_dictionary(environ) user = None valid = False query = {} try: valid, user, parameters = self.auth_helper.verify(request) query = self.decrypt_dict(parameters[self.QUERY_PARAM]) except KeyError: pass if not valid: resp = Unauthorized("Unknown user or wrong password") else: if len(query) != 3 and self.AUTHN_REFERENCE_PARAM not in query or "redirect_uri" not in query or \ "key" not in query: resp = Unauthorized("Unknown user or wrong password") else: resp = self.setup_idp(user, query[self.AUTHN_REFERENCE_PARAM], query["redirect_uri"], query["key"]) return resp(environ, start_response)
def verify(self, environ, start_response): _ok = self.verify_bool(environ, start_response) if not _ok: resp = Unauthorized("Unknown user or wrong password") else: session = Session(environ) user = session[SpHandler.SPHANDLERFORUID] query = HttpHandler.query_dictionary(environ) query = self.decrypt_dict(query["query"]) resp = self.setup_idp(user, query["authn_reference"], query["redirect_uri"], query["key"]) return resp(environ, start_response)
def do(self, response, binding, relay_state="", mtype="response"): """ :param response: The SAML response, transport encoded :param binding: Which binding the query came in over """ # tmp_outstanding_queries = dict(self.outstanding_queries) if not response: logger.info("Missing Response") resp = Unauthorized('Unknown user') return resp(self.environ, self.start_response) try: conv_info = { 'remote_addr': self.environ['REMOTE_ADDR'], 'request_uri': self.environ['REQUEST_URI'], 'entity_id': self.sp.config.entityid, 'endpoints': self.sp.config.getattr('endpoints', 'sp') } self.response = self.sp.parse_authn_request_response( response, binding, self.outstanding_queries, self.cache.outstanding_certs, conv_info=conv_info) except UnknownPrincipal as excp: logger.error("UnknownPrincipal: %s", excp) resp = ServiceError("UnknownPrincipal: %s" % (excp, )) return resp(self.environ, self.start_response) except UnsupportedBinding as excp: logger.error("UnsupportedBinding: %s", excp) resp = ServiceError("UnsupportedBinding: %s" % (excp, )) return resp(self.environ, self.start_response) except VerificationError as err: resp = ServiceError("Verification error: %s" % (err, )) return resp(self.environ, self.start_response) except SignatureError as err: resp = ServiceError("Signature error: %s" % (err, )) return resp(self.environ, self.start_response) except Exception as err: resp = ServiceError("Other error: %s" % (err, )) return resp(self.environ, self.start_response) logger.info("AVA: %s", self.response.ava) user = User(self.response.name_id, self.response.ava, self.response) cookie = self.cache.set_cookie(user) resp = Redirect("/", headers=[ cookie, ]) return resp(self.environ, self.start_response)
def sso_redirect_or_post(self, request, binding): assert type(request) == dict if "key" in request: msg = self.ticket[request["key"]] req = self.parse_authn_request(msg["SAMLRequest"], binding) del self.ticket[request["key"]] if req.message.force_authn is not None and req.message.force_authn.lower( ) == "true": key = self.store_request(msg) auth_info = self.authn_broker.pick(req.requested_authn_context) if len(auth_info) > 0: method, reference = auth_info[0] return method(key=key) else: log.debug("No authentication method found") return Unauthorized("No usable authentication method") return self.sso_operation(msg, binding, uid=request["pysaml"]) else: req_info = self.parse_authn_request(request["SAMLRequest"], binding) req = req_info.message key = self.store_request(request) auth_info = self.authn_broker.pick(req.requested_authn_context) if len(auth_info) > 0: method, reference = auth_info[0] log.debug("Authn chosen: " + str(method.acr)) return method(key=key) else: log.debug("No authentication method found") return Unauthorized("No authentication method found")
def verify(self, environ, start_response): request = HttpHandler.query_dictionary(environ) cookie = environ.get('HTTP_COOKIE') user = None valid = False query = {} try: valid, user, return_to_query = self.auth_helper.verify( request, cookie) query = dict((k, v if len(v) > 1 else v[0]) for k, v in parse_qs(return_to_query).iteritems()) except KeyError: pass if not valid: resp = Unauthorized("Unknown user or wrong password") else: if len( query ) != 3 and "authn_reference" not in query or "redirect_uri" not in query or "key" not in query: resp = Unauthorized("Unknown user or wrong password") else: resp = self.setup_idp(user, query["authn_reference"], query["redirect_uri"], query["key"]) return resp(environ, start_response)
def do_authentication(environ, start_response, authn_context, key, redirect_uri): """ Display the login form """ logger.debug("Do authentication") auth_info = AUTHN_BROKER.pick(authn_context) if len(auth_info): method, reference = auth_info[0] logger.debug("Authn chosen: %s (ref=%s)" % (method, reference)) return method(environ, start_response, reference, key, redirect_uri) else: resp = Unauthorized("No usable authentication method") return resp(environ, start_response)
def disco_response(self, *args): """ If I got a useful response from the discovery server, continue with the authentication request. :return: redirect containing the authentication request """ info = self.unpack_redirect() try: entity_id = info[self.idp_query_param] except KeyError: resp = Unauthorized("You must chose an IdP") return resp(self.environ, self.start_response) else: # should I check the state variable ? return self.authn_request(entity_id, info["state"])
def staticfile(environ, start_response): try: path = args.path[:] if path is None or len(path) == 0: path = os.path.dirname(os.path.abspath(__file__)) if path[-1] != "/": path += "/" path += environ.get('PATH_INFO', '').lstrip('/') path = os.path.realpath(path) if not path.startswith(args.path): resp = Unauthorized() return resp(environ, start_response) start_response('200 OK', [('Content-Type', "text/xml")]) return open(path, 'r').read() except Exception as ex: logger.error("An error occured while creating metadata:" + ex.message) return not_found(environ, start_response)
def do(self, response, binding, relay_state="", mtype="response"): """ :param response: The SAML response, transport encoded :param binding: Which binding the query came in over """ #tmp_outstanding_queries = dict(self.outstanding_queries) if not response: logger.info("Missing Response") resp = Unauthorized('Unknown user') return resp(self.environ, self.start_response) try: self.response = self.sp.parse_authn_request_response( response, binding, self.outstanding_queries) except UnknownPrincipal, excp: logger.error("UnknownPrincipal: %s" % (excp,)) resp = ServiceError("UnknownPrincipal: %s" % (excp,)) return resp(self.environ, self.start_response)
def verify_request(self, query, binding): """ :param query: The SAML query, transport encoded :param binding: Which binding the query came in over """ resp_args = {} if not query: logger.info("Missing QUERY") resp = Unauthorized("Unknown user") return resp_args, resp(self.environ, self.start_response) if not self.req_info: self.req_info = IDP.parse_authn_request(query, binding) logger.info("parsed OK") _authn_req = self.req_info.message logger.debug("%s", _authn_req) try: self.binding_out, self.destination = IDP.pick_binding( "assertion_consumer_service", bindings=self.response_bindings, entity_id=_authn_req.issuer.text, request=_authn_req, ) except Exception as err: logger.error("Couldn't find receiver endpoint: %s", err) raise logger.debug("Binding: %s, destination: %s", self.binding_out, self.destination) resp_args = {} try: resp_args = IDP.response_args(_authn_req) _resp = None except UnknownPrincipal as excp: _resp = IDP.create_error_response(_authn_req.id, self.destination, excp) except UnsupportedBinding as excp: _resp = IDP.create_error_response(_authn_req.id, self.destination, excp) return resp_args, _resp
def not_authn(self, key, requested_authn_context, cert_str=None, cert_key_str=None): redirect_uri = geturl(self.environ, query=False) self.logger.debug("Do authentication") auth_info = self.idphandler.authn_broker.pick(requested_authn_context) if len(auth_info): method, reference = auth_info[0] logger.debug("Authn chosen: %s (ref=%s)" % (method, reference)) return method.authenticate(self.environ, self.start_response, reference, key, redirect_uri, certificate_str=cert_str, certificate_key_str=cert_key_str) else: resp = Unauthorized("No usable authentication method") return resp(self.environ, self.start_response)
def slo(environ, start_response, user): """ Expects a HTTP-redirect logout request """ query = None if "QUERY_STRING" in environ: logger.info("Query string: %s" % environ["QUERY_STRING"]) query = parse_qs(environ["QUERY_STRING"]) if not query: resp = Unauthorized('Unknown user') return resp(environ, start_response) try: req_info = IDP.parse_logout_request(query["SAMLRequest"][0], BINDING_HTTP_REDIRECT) logger.info("LOGOUT request parsed OK") logger.info("REQ_INFO: %s" % req_info.message) except KeyError, exc: logger.info("logout request error: %s" % (exc, )) resp = BadRequest('Request parse error') return resp(environ, start_response)
def do(self, response, binding, relay_state="", mtype="response"): """ :param response: The SAML response, transport encoded :param binding: Which binding the query came in over """ #tmp_outstanding_queries = dict(self.outstanding_queries) if not response: logger.info("Missing Response") resp = Unauthorized('Unknown user') return resp(self.environ, self.start_response) try: self.response = self.sp.parse_authn_request_response( response, binding, self.outstanding_queries, self.cache.outstanding_certs) except UnknownPrincipal as excp: logger.error("UnknownPrincipal: %s" % (excp, )) resp = ServiceError("UnknownPrincipal: %s" % (excp, )) return resp(self.environ, self.start_response) except UnsupportedBinding as excp: logger.error("UnsupportedBinding: %s" % (excp, )) resp = ServiceError("UnsupportedBinding: %s" % (excp, )) return resp(self.environ, self.start_response) except VerificationError as err: resp = ServiceError("Verification error: %s" % (err, )) return resp(self.environ, self.start_response) except Exception as err: resp = ServiceError("Other error: %s" % (err, )) return resp(self.environ, self.start_response) logger.info("AVA: %s" % self.response.ava) user = User(self.response.name_id, self.response.ava) cookie = self.cache.set_cookie(user) resp = Redirect("/", headers=[ ("Location", "/"), cookie, ]) return resp(self.environ, self.start_response)
def run_server(self, environ, start_response): """ The main WSGI application. If nothing matches return NotFound. :param environ: The HTTP application environment :param start_response: The application to run when the handling of the request is done :return: The response as a list of lines """ path = environ.get('PATH_INFO', '').lstrip('/') if ".." in path: resp = Unauthorized() return resp(environ, start_response) for regex, spec in self.urls: match = re.search(regex, path) if match is not None: try: environ['oic.url_args'] = match.groups()[0] except IndexError: environ['oic.url_args'] = path try: return self.run_entity(spec, environ, start_response) except Exception as err: if not self.debug: print("%s" % err, file=sys.stderr) traceback.print_exc() logger.exception("%s" % err) resp = ServiceError("%s" % err) return resp(environ, start_response) else: raise logger.debug("unknown side: %s" % path) resp = NotFound("Couldn't find the side you asked for!") return resp(environ, start_response)
def application(environ, start_response): """ The main WSGI application. If nothing matches return NotFound. :param environ: The HTTP application environment :param start_response: The application to run when the handling of the request is done :return: The response as a list of lines """ path = environ.get('PATH_INFO', '').lstrip('/') if ".." in path: resp = Unauthorized() return resp(environ, start_response) if path == "robots.txt": return static(environ, start_response, "static/robots.txt") elif path.startswith("static/"): return static(environ, start_response, path) for regex, spec in URLS: match = re.search(regex, path) if match is not None: try: environ['oic.url_args'] = match.groups()[0] except IndexError: environ['oic.url_args'] = path try: return run(spec, environ, start_response) except Exception, err: print >> sys.stderr, "%s" % err message = traceback.format_exception(*sys.exc_info()) print >> sys.stderr, message LOGGER.exception("%s" % err) resp = ServiceError("%s" % err) return resp(environ, start_response)
def authn_response(self, binding): """ :param binding: Which binding the query came in over :returns: Error response or a response constructed by the transfer function """ binding = service.INV_BINDING_MAP[binding] _authn_response = self.unpack(binding) if not _authn_response["SAMLResponse"]: logger.info("Missing Response") resp = Unauthorized('Unknown user') return resp(self.environ, self.start_response) try: _response = self.sp.parse_authn_request_response( _authn_response["SAMLResponse"], binding, self.cache) except UnknownPrincipal, excp: logger.error("UnknownPrincipal: %s" % (excp, )) resp = ServiceError("UnknownPrincipal: %s" % (excp, )) return resp(self.environ, self.start_response)
def not_authn(environ, start_response): resp = Unauthorized('Unknown user') return resp(environ, start_response)
def not_authn(self): resp = Unauthorized("Unknown user") return resp(self.environ, self.start_response)