def password_grant_type(self, areq): """ Token authorization using Resource owner password credentials. RFC6749 section 4.3 """ # `Any` comparison tries a first broker, so we either hit an IndexError or get a method try: authn, authn_class_ref = self.pick_auth(areq, "any") except IndexError: err = TokenErrorResponse(error="invalid_grant") return Unauthorized(err.to_json(), content="application/json") identity, _ts = authn.authenticated_as( username=areq["username"], password=areq["password"] ) if identity is None: err = TokenErrorResponse(error="invalid_grant") return Unauthorized(err.to_json(), content="application/json") # We are returning a token areq["response_type"] = ["token"] authn_event = AuthnEvent( identity["uid"], identity.get("salt", ""), authn_info=authn_class_ref, time_stamp=_ts, ) sid = self.setup_session(areq, authn_event, self.cdb[areq["client_id"]]) _at = self.sdb.upgrade_to_token(self.sdb[sid]["code"], issue_refresh=True) atr_class = self.server.message_factory.get_response_type("token_endpoint") atr = atr_class(**by_schema(atr_class, **_at)) return Response( atr.to_json(), content="application/json", headers=OAUTH2_NOCACHE_HEADERS )
def verify(self, request, **kwargs): """ Verifies that the given totp 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. """ if isinstance(request, six.string_types): _dict = parse_qs(request) elif isinstance(request, dict): _dict = request else: raise ValueError("Wrong type of input") # verify totp try: # Do verification totp_generator = pyotp.TOTP(self.get_totp_secret_key(_dict["username"][0])) assert (True == totp_generator.verify(_dict["totp"][0])) except (AssertionError, KeyError): resp = Unauthorized("Wrong TOTP") ##resp = Unauthorized("Unknown user or wrong password") kwargs["request"] = request kwargs["form_action"] = kwargs["url"] argv = self.templ_arg_func(0, **kwargs) argv['wrong_value'] = 1 argv['form_action'] = kwargs["baseurl"] + "/totp_login" argv['username'] = _dict['username'][0] argv['acr'] = argv['form_action'] argv['title'] = 'TOTP verification' self.nerror = self.nerror + 1 if (self.nerror>=3): self.nerror = 0 argv['wrong_value'] = 4 mte = self.template_lookup.get_template('totp_form.mako') resp.message = mte.render(**argv).decode("utf-8") return resp, False else: # If I remove this header, authentication enters in a infinite loop. headers = [self.create_cookie(_dict["username"][0], "upm")] try: _qp = _dict["query"][0] except KeyError: _qp = self.get_multi_auth_cookie(kwargs['cookie']) try: return_to = self.generate_return_url(kwargs["return_to"], _qp) except KeyError: try: return_to = self.generate_return_url(self.return_to, _qp, kwargs["path"]) except KeyError: return_to = self.generate_return_url(self.return_to, _qp) return SeeOther(return_to, headers=headers), True
def client_info_endpoint(self, method="GET", **kwargs): """ Operations on this endpoint are switched through the use of different HTTP methods. :param method: HTTP method used for the request :param kwargs: keyword arguments :return: A Response instance """ _query = compact(parse_qs(kwargs["query"])) try: _id = _query["client_id"] except KeyError: return BadRequest("Missing query component") if _id not in self.cdb: return Unauthorized() # authenticated client try: self.verify_client( kwargs["environ"], kwargs["request"], "bearer_header", client_id=_id ) except (AuthnFailure, UnknownAssertionType): return Unauthorized() if method == "GET": return self.client_info(_id) elif method == "PUT": try: _request = self.server.message_factory.get_request_type( "update_endpoint" )().from_json(kwargs["request"]) except ValueError as err: return BadRequest(str(err)) try: _request.verify() except InvalidRedirectUri as err: msg = ClientRegistrationError( error="invalid_redirect_uri", error_description="%s" % err ) return BadRequest(msg.to_json(), content="application/json") except (MissingPage, VerificationError) as err: msg = ClientRegistrationError( error="invalid_client_metadata", error_description="%s" % err ) return BadRequest(msg.to_json(), content="application/json") try: self.client_info_update(_id, _request) return self.client_info(_id) except ModificationForbidden: return Forbidden() elif method == "DELETE": try: del self.cdb[_id] except KeyError: return Unauthorized() else: return NoContent()
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)" % sanitize(request)) if isinstance(request, six.string_types): _dict = compact(parse_qs(request)) elif isinstance(request, dict): _dict = request else: raise ValueError("Wrong type of input") logger.debug("dict: %s" % sanitize(_dict)) # verify username and password try: self._verify(_dict["password"], _dict["login"]) # dict origin except TypeError: try: self._verify(_dict["password"][0], _dict["login"][0]) except (AssertionError, KeyError) as err: logger.debug("Password verification failed: {}".format(err)) resp = Unauthorized("Unknown user or wrong password") return resp, False else: try: _qp = _dict["query"] except KeyError: _qp = self.get_multi_auth_cookie(kwargs['cookie']) except (AssertionError, KeyError) as err: logger.debug("Password verification failed: {}".format(err)) resp = Unauthorized("Unknown user or wrong password") return resp, False else: try: _qp = _dict["query"] except KeyError: _qp = self.get_multi_auth_cookie(kwargs['cookie']) logger.debug("Password verification succeeded.") # if "cookie" not in kwargs or self.srv.cookie_name not in kwargs["cookie"]: headers = [self.create_cookie(_dict["login"], "upm")] try: return_to = self.generate_return_url(kwargs["return_to"], _qp) except KeyError: try: return_to = self.generate_return_url(self.return_to, _qp, kwargs["path"]) except KeyError: return_to = self.generate_return_url(self.return_to, _qp) return SeeOther(return_to, headers=headers), True
def client_info_endpoint(self, request, environ, method="GET", query="", **kwargs): """ Operations on this endpoint are switched through the use of different HTTP methods :param request: The request :param authn: Client authentication information :param method: HTTP method used for the request :param query: The query part of the URL used, this is where the client_id is supposed to reside. :param kwargs: extra keyword arguments :return: A Response instance """ _query = urlparse.parse_qs(query) try: _id = _query["client_id"][0] except KeyError: return BadRequest("Missing query component") try: assert _id in self.cdb except AssertionError: return Unauthorized() # authenticated client try: _ = self.verify_client(environ, request, "bearer_header", client_id=_id) except (AuthnFailure, UnknownAssertionType): return Unauthorized() if method == "GET": return self.client_info(_id) elif method == "PUT": try: _request = ClientUpdateRequest().from_json(request) except ValueError: return BadRequest() try: _request.verify() except InvalidRedirectUri, err: msg = ClientRegistrationError(error="invalid_redirect_uri", error_description="%s" % err) return BadRequest(msg.to_json(), content="application/json") except (MissingPage, VerificationError), err: msg = ClientRegistrationError(error="invalid_client_metadata", error_description="%s" % err) return BadRequest(msg.to_json(), content="application/json")
def verify(self, request, cookie, **kwargs): """ Verify if the authentication was successful. :rtype : Response :param request: Contains the request parameters. :param cookie: Cookies sent with the request. :param kwargs: Any other parameters. :return: If the authentication was successful: a redirect to the return_to url. Otherwise a unauthorized response. :raise: ValueError """ logger.debug("verify(%s)" % request) if isinstance(request, str): _dict = parse_qs(request) elif isinstance(request, dict): _dict = request else: raise ValueError("Wrong type of input") try: cas_cookie, _ts, _typ = self.getCookieValue( cookie, self.CONST_CAS_COOKIE) data = json.loads(cas_cookie) nonce = base64.b64decode(data[self.CONST_NONCE]) if nonce != _dict[self.CONST_NONCE][0]: logger.warning( "Someone tried to login without a correct nonce!") return Unauthorized("You are not authorized!") acr = None try: acr = _dict["acr_values"][0] except KeyError: pass uid = self.handle_callback(_dict[self.CONST_TICKET], self.get_service_url(nonce, acr)) if uid is None or uid == "": logger.info("Someone tried to login, but was denied by CAS!") return Unauthorized("You are not authorized!") cookie = self.create_cookie(uid, "casm") return_to = self.generate_return_url(self.return_to, uid) if "?" in return_to: return_to += "&" else: return_to += "?" return_to += base64.b64decode(data[self.CONST_QUERY]) return SeeOther(return_to, headers=[cookie]) except Exception: # FIXME: This should catch specific exception thrown from methods in the block logger.critical( "Metod verify in user_cas.py had a fatal exception.", exc_info=True) return Unauthorized("You are not authorized!")
def code_grant_type(self, areq): # assert that the code is valid try: _info = self.sdb[areq["code"]] except KeyError: err = TokenErrorResponse(error="invalid_grant", error_description="Unknown access grant") return Response(err.to_json(), content="application/json", status="401 Unauthorized") authzreq = json.loads(_info['authzreq']) if 'code_verifier' in areq: try: _method = authzreq['code_challenge_method'] except KeyError: _method = 'S256' resp = self.verify_code_challenge(areq['code_verifier'], authzreq['code_challenge'], _method) if resp: return resp if 'state' in areq: if self.sdb[areq['code']]['state'] != areq['state']: err = TokenErrorResponse(error="unauthorized_client") return Unauthorized(err.to_json(), content="application/json") resp = self.token_scope_check(areq, _info) if resp: return resp # If redirect_uri was in the initial authorization request # verify that the one given here is the correct one. if "redirect_uri" in _info: assert areq["redirect_uri"] == _info["redirect_uri"] issue_refresh = False if 'scope' in authzreq and 'offline_access' in authzreq['scope']: if authzreq['response_type'] == 'code': issue_refresh = True try: _tinfo = self.sdb.upgrade_to_token(areq["code"], issue_refresh=issue_refresh) except AccessCodeUsed: err = TokenErrorResponse(error="invalid_grant", error_description="Access grant used") return Response(err.to_json(), content="application/json", status="401 Unauthorized") logger.debug("_tinfo: %s" % _tinfo) atr = AccessTokenResponse(**by_schema(AccessTokenResponse, **_tinfo)) logger.debug("AccessTokenResponse: %s" % atr) return Response(atr.to_json(), content="application/json")
def introspection_endpoint(self, request="", **kwargs): try: entity, client_id = client_authentication(self.sdb, kwargs["authn"]) except AuthnFailed: return Unauthorized() return self.introspection_endpoint_(request, entity, **kwargs)
def registration_endpoint(self, request, environ, **kwargs): """ :param request: The request :param authn: Client authentication information :param kwargs: extra keyword arguments :return: A Response instance """ _request = RegistrationRequest().deserialize(request, "json") try: _request.verify() except InvalidRedirectUri as err: msg = ClientRegistrationError(error="invalid_redirect_uri", error_description="%s" % err) return BadRequest(msg.to_json(), content="application/json") except (MissingPage, VerificationError) as err: msg = ClientRegistrationError(error="invalid_client_metadata", error_description="%s" % err) return BadRequest(msg.to_json(), content="application/json") # authenticated client if self.authn_at_registration: try: _ = self.verify_client(environ, _request, self.authn_at_registration) except (AuthnFailure, UnknownAssertionType): return Unauthorized() client_id = self.create_new_client(_request) return self.client_info(client_id)
def authn(environ, session): # verify the username+password if environ["REQUEST_METHOD"] == "POST": query = parse_qs(get_body(environ)) else: # Assume environ["REQUEST_METHOD"] == "GET" query = parse_qs(environ["QUERY_STRING"]) try: assert uma_as.PASSWD[query["login"][0]] == query["password"][0] except (KeyError, AssertionError): return Unauthorized(), {} #uid = uma_as.UID2EPPN[query["login"][0]] uid = query["login"][0] cval = {"user": uid, "authn": PASSWORD} headers = [ CookieHandler.create_cookie("%s" % (cval, ), "sso", COOKIE_NAME) ] session["user"] = uid try: op = query["operation"][0] if op == "chose_permissions": return chose_permissions(environ, session) elif op == "set_permission": return set_permission(environ, session) elif op == "manage": return manage(uid, headers) else: pass except KeyError: pass return Response(), {}
def safe(environ, start_response): _op = environ["oic.oas"] _srv = _op.server _log_info = _op.logger.info _log_info("- safe -") # _log_info("env: %s" % environ) # _log_info("handle: %s" % (handle,)) try: _authz = environ["HTTP_AUTHORIZATION"] (_typ, code) = _authz.split(" ") assert _typ == "Bearer" except KeyError: resp = BadRequest("Missing authorization information") return resp(environ, start_response) try: _sinfo = _srv.sdb[code] except KeyError: resp = Unauthorized("Not authorized") return resp(environ, start_response) _info = "'%s' secrets" % _sinfo["sub"] resp = Response(_info) return resp(environ, start_response)
def verify(self, request, cookie, path, requrl, **kwargs): """ Verifies if the authentication was successful. :rtype : Response :param request: Contains the request parameters. :param cookie: Cookies sent with the request. :param kwargs: Any other parameters. :return: If the authentication was successful: a redirect to the return_to url. Otherwise a unauthorized response. :raise: ValueError """ binding = None if path == "/" + self.sp_conf.ASCPOST: binding = BINDING_HTTP_POST if path == "/" + self.sp_conf.ASCREDIRECT: binding = BINDING_HTTP_REDIRECT saml_cookie, _ts, _typ = self.getCookieValue( cookie, self.CONST_SAML_COOKIE) data = json.loads(saml_cookie) if data[self.CONST_HASIDP] == 'False': (done, response) = self._pick_idp(request) if done == 0: entity_id = response # Do the AuthnRequest resp = self._redirect_to_auth( self.sp, entity_id, base64.b64decode(data[self.CONST_QUERY])) return resp return response if not request: logger.info("Missing Response") return Unauthorized("You are not authorized!") try: response = self.sp.parse_authn_request_response( request["SAMLResponse"][0], binding, self.cache_outstanding_queries) except UnknownPrincipal, excp: logger.error("UnknownPrincipal: %s" % (excp, )) return Unauthorized(self.not_authorized)
def token_endpoint(self, authn="", **kwargs): """ This is where clients come to get their access tokens """ _sdb = self.sdb logger.debug("- token -") body = kwargs["request"] logger.debug("body: %s" % sanitize(body)) areq = AccessTokenRequest().deserialize(body, "urlencoded") try: self.client_authn(self, areq, authn) except FailedAuthentication as err: logger.error(err) err = TokenErrorResponse(error="unauthorized_client", error_description="%s" % err) return Response(err.to_json(), content="application/json", status_code=401) logger.debug("AccessTokenRequest: %s" % sanitize(areq)) if areq["grant_type"] != "authorization_code": err = TokenErrorResponse(error="invalid_request", error_description="Wrong grant type") return Response(err.to_json(), content="application/json", status="401 Unauthorized") # assert that the code is valid _info = _sdb[areq["code"]] resp = self.token_scope_check(areq, _info) if resp: return resp # If redirect_uri was in the initial authorization request # verify that the one given here is the correct one. if "redirect_uri" in _info and areq["redirect_uri"] != _info["redirect_uri"]: logger.error('Redirect_uri mismatch') err = TokenErrorResponse(error="unauthorized_client") return Unauthorized(err.to_json(), content="application/json") try: _tinfo = _sdb.upgrade_to_token(areq["code"], issue_refresh=True) except AccessCodeUsed: err = TokenErrorResponse(error="invalid_grant", error_description="Access grant used") return Response(err.to_json(), content="application/json", status="401 Unauthorized") logger.debug("_tinfo: %s" % sanitize(_tinfo)) atr = AccessTokenResponse(**by_schema(AccessTokenResponse, **_tinfo)) logger.debug("AccessTokenResponse: %s" % sanitize(atr)) return Response(atr.to_json(), content="application/json", headers=OAUTH2_NOCACHE_HEADERS)
def rpt_endpoint(self, authn, **kwargs): """ :param authn: authentication information """ try: entity, client_id = client_authentication(self.sdb, authn) except AuthnFailed: return Unauthorized() return self.rpt_endpoint_(entity, client_id, **kwargs)
def permission_registration_endpoint(self, request="", authn="", **kwargs): try: entity, client_id = client_authentication(self.sdb, authn) except AuthnFailed: return Unauthorized() return self.permission_registration_endpoint_(owner=entity, request=request, client_id=client_id, **kwargs)
def registration_endpoint(self, **kwargs): """ Perform dynamic client registration. :param request: The request :param authn: Client authentication information :param kwargs: extra keyword arguments :return: A Response instance """ _request = self.server.message_factory.get_request_type( "registration_endpoint" )().deserialize(kwargs["request"], "json") try: _request.verify(keyjar=self.keyjar) except InvalidRedirectUri as err: msg = ClientRegistrationError( error="invalid_redirect_uri", error_description="%s" % err ) return BadRequest(msg.to_json(), content="application/json") except (MissingPage, VerificationError) as err: msg = ClientRegistrationError( error="invalid_client_metadata", error_description="%s" % err ) return BadRequest(msg.to_json(), content="application/json") # If authentication is necessary at registration if self.authn_at_registration: try: self.verify_client( kwargs["environ"], _request, self.authn_at_registration ) except (AuthnFailure, UnknownAssertionType): return Unauthorized() client_restrictions = {} # type: ignore if "parsed_software_statement" in _request: for ss in _request["parsed_software_statement"]: client_restrictions.update(self.consume_software_statement(ss)) del _request["software_statement"] del _request["parsed_software_statement"] try: client_id = self.create_new_client(_request, client_restrictions) except CapabilitiesMisMatch as err: msg = ClientRegistrationError( error="invalid_client_metadata", error_description="%s" % err ) return BadRequest(msg.to_json(), content="application/json") except RestrictionError as err: msg = ClientRegistrationError( error="invalid_client_metadata", error_description="%s" % err ) return BadRequest(msg.to_json(), content="application/json") return self.client_info(client_id)
def authenticated_call(sdb, func, authn, request=None, **kwargs): try: entity, client_id = client_authentication(sdb, authn) except AuthnFailed: return Unauthorized() else: kwargs["entity"] = entity kwargs["client_id"] = client_id if request: kwargs["request"] = request return func(**kwargs)
def resource_set_registration_endpoint(self, path, method, body="", if_match="", **kwargs): try: entity, client_id = client_authentication(self.sdb, kwargs["authn"]) except AuthnFailed: return Unauthorized() return self.resource_set_registration_endpoint_( entity, path, method, client_id, body, if_match, **kwargs)
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, basestring): _dict = parse_qs(request) elif isinstance(request, dict): _dict = request else: raise ValueError("Wrong type of input") logger.debug("dict: %s" % _dict) logger.debug("passwd: %s" % self.passwd) # verify username and password try: self._verify(_dict["password"][0], _dict["login"][0]) except (AssertionError, KeyError): resp = Unauthorized("Unknown user or wrong password") return resp, False else: cookie = self.create_cookie(_dict["login"][0], "upm") try: _qp = _dict["query"][0] except KeyError: _qp = self.get_multi_auth_cookie(kwargs['cookie']) try: return_to = self.generate_return_url(kwargs["return_to"], _qp) except KeyError: try: return_to = self.generate_return_url( self.return_to, _qp, kwargs["path"]) except KeyError: return_to = self.generate_return_url(self.return_to, _qp) return Redirect(return_to, headers=[cookie]), True
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") logger.debug("dict: %s" % _dict) logger.debug("passwd: %s" % self.passwd) # verify username and password try: assert _dict['login_parameter'][0] == 'logged_in' except (AssertionError, KeyError): resp = Unauthorized( "You are not authorized. Javascript not executed") return resp, False else: cookie = self.create_cookie("diana", "upm") try: _qp = _dict["query"][0] except KeyError: _qp = self.get_multi_auth_cookie(kwargs['cookie']) try: return_to = self.generate_return_url(kwargs["return_to"], _qp) except KeyError: return_to = self.generate_return_url(self.return_to, _qp) resp = SeeOther(return_to, headers=[cookie]) return resp, True
def code_grant_type(self, areq): """ Token authorization using Code Grant. RFC6749 section 4.1 """ try: _tinfo = self.sdb.upgrade_to_token(areq["code"], issue_refresh=True) except AccessCodeUsed: error = TokenErrorResponse(error="invalid_grant", error_description="Access grant used") return Unauthorized(error.to_json(), content="application/json") logger.debug("_tinfo: %s" % sanitize(_tinfo)) atr = AccessTokenResponse(**by_schema(AccessTokenResponse, **_tinfo)) logger.debug("AccessTokenResponse: %s" % sanitize(atr)) return Response(atr.to_json(), content="application/json", headers=OAUTH2_NOCACHE_HEADERS)
except InvalidRedirectUri, err: msg = ClientRegistrationError(error="invalid_redirect_uri", error_description="%s" % err) return BadRequest(msg.to_json(), content="application/json") except (MissingPage, VerificationError), err: msg = ClientRegistrationError(error="invalid_client_metadata", error_description="%s" % err) return BadRequest(msg.to_json(), content="application/json") # authenticated client if self.authn_at_registration: try: _ = self.verify_client(environ, _request, self.authn_at_registration) except (AuthnFailure, UnknownAssertionType): return Unauthorized() client_id = self.create_new_client(_request) return self.client_info(client_id) def client_info_endpoint(self, request, environ, method="GET", query="", **kwargs): """ Operations on this endpoint are switched through the use of different HTTP methods
def verify(self, request, cookie, path, requrl, end_point_index=None, **kwargs): """ Verifies if the authentication was successful. :rtype : Response :param request: Contains the request parameters. :param cookie: Cookies sent with the request. :param kwargs: Any other parameters. :return: If the authentication was successful: a redirect to the return_to url. Otherwise a unauthorized response. :raise: ValueError """ if isinstance(request, basestring): request = parse_qs(request) elif isinstance(request, dict): pass else: raise ValueError("Wrong type of input") acs = self.sp.config.getattr("endpoints", "sp")["assertion_consumer_service"] acs_endpoints = [(ep[0].rsplit("/", 1)[1], ep[1]) for ep in acs] binding = None path = path[1:] for endp in acs_endpoints: if path == endp[0]: binding = endp[1] break saml_cookie, _ts, _typ = self.getCookieValue( cookie, self.CONST_SAML_COOKIE) data = json.loads(saml_cookie) rp_query_cookie = self.get_multi_auth_cookie(cookie) query = rp_query_cookie if not query: query = base64.b64decode(data[self.CONST_QUERY]) if data[self.CONST_HASIDP] == 'False': (done, response) = self._pick_idp(request, end_point_index) if done == 0: entity_id = response # Do the AuthnRequest resp = self._redirect_to_auth(self.sp, entity_id, query, end_point_index) return resp, False return response, False if not request: logger.info("Missing Response") return Unauthorized("You are not authorized!"), False try: response = self.sp.parse_authn_request_response( request["SAMLResponse"][0], binding, self.cache_outstanding_queries) except UnknownPrincipal, excp: logger.error("UnknownPrincipal: %s" % (excp, )) return Unauthorized(self.not_authorized), False
if not request: logger.info("Missing Response") return Unauthorized("You are not authorized!") try: response = self.sp.parse_authn_request_response(request["SAMLResponse"][0], binding, self.cache_outstanding_queries) except UnknownPrincipal, excp: logger.error("UnknownPrincipal: %s" % (excp,)) return Unauthorized(self.not_authorized) except UnsupportedBinding, excp: logger.error("UnsupportedBinding: %s" % (excp,)) return Unauthorized(self.not_authorized) except VerificationError, err: logger.error("Verification error: %s" % (err,)) return Unauthorized(self.not_authorized) except Exception, err: logger.error("Other error: %s" % (err,)) return Unauthorized(self.not_authorized) if self.sp_conf.VALID_ATTRIBUTE_RESPONSE is not None: for k, v in self.sp_conf.VALID_ATTRIBUTE_RESPONSE.iteritems(): if k not in response.ava: return Unauthorized(self.not_authorized) else: allowed = False for allowed_attr_value in v: if allowed_attr_value == response.ava[k] or allowed_attr_value in response.ava[k]: allowed = True break if not allowed:
class SAMLAuthnMethod(UserAuthnMethod): CONST_QUERY = "query" CONST_SAML_COOKIE = "samlauthc" CONST_HASIDP = "hasidp" def __init__(self, srv, lookup, userdb, spconf, url, return_to, verification_endpoint="verify", cache=None, bindings=None): """ Constructor for the class. :param srv: Usually none, but otherwise the oic server. :param return_to: The URL to return to after a successful authentication. """ self.userdb = userdb if cache is None: self.cache_outstanding_queries = {} else: self.cache_outstanding_queries = cache UserAuthnMethod.__init__(self, srv) self.return_to = return_to self.idp_query_param = "IdpQuery" if bindings: self.bindings = bindings else: self.bindings = [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST, BINDING_HTTP_ARTIFACT] self.verification_endpoint = verification_endpoint #Configurations for the SP handler. (pyOpSamlProxy.client.sp.conf) self.sp_conf = importlib.import_module(spconf) #self.sp_conf.BASE = self.sp_conf.BASE % url ntf = NamedTemporaryFile(suffix="pyoidc.py", delete=True) ntf.write("CONFIG = " + str(self.sp_conf.CONFIG).replace("%s", url)) ntf.seek(0) self.sp = Saml2Client(config_file="%s" % ntf.name) mte = lookup.get_template("unauthorized.mako") argv = { "message": "You are not authorized!", } self.not_authorized = mte.render(**argv) def __call__(self, query, *args, **kwargs): (done, response) = self._pick_idp(query) if done == 0: entity_id = response # Do the AuthnRequest resp = self._redirect_to_auth(self.sp, entity_id, query) return resp return response def verify(self, request, cookie, path, requrl, **kwargs): """ Verifies if the authentication was successful. :rtype : Response :param request: Contains the request parameters. :param cookie: Cookies sent with the request. :param kwargs: Any other parameters. :return: If the authentication was successful: a redirect to the return_to url. Otherwise a unauthorized response. :raise: ValueError """ binding = None if path == "/" + self.sp_conf.ASCPOST: binding = BINDING_HTTP_POST if path == "/" + self.sp_conf.ASCREDIRECT: binding = BINDING_HTTP_REDIRECT saml_cookie, _ts, _typ = self.getCookieValue(cookie, self.CONST_SAML_COOKIE) data = json.loads(saml_cookie) if data[self.CONST_HASIDP] == 'False': (done, response) = self._pick_idp(request) if done == 0: entity_id = response # Do the AuthnRequest resp = self._redirect_to_auth(self.sp, entity_id, base64.b64decode(data[self.CONST_QUERY]) ) return resp return response if not request: logger.info("Missing Response") return Unauthorized("You are not authorized!") try: response = self.sp.parse_authn_request_response(request["SAMLResponse"][0], binding, self.cache_outstanding_queries) except UnknownPrincipal, excp: logger.error("UnknownPrincipal: %s" % (excp,)) return Unauthorized(self.not_authorized) except UnsupportedBinding, excp: logger.error("UnsupportedBinding: %s" % (excp,)) return Unauthorized(self.not_authorized)
def code_grant_type(self, areq): # assert that the code is valid try: _info = self.sdb[areq["code"]] except KeyError: err = TokenErrorResponse( error="invalid_grant", error_description="Unknown access grant" ) return Response( err.to_json(), content="application/json", status="401 Unauthorized" ) authzreq = json.loads(_info["authzreq"]) if "code_verifier" in areq: try: _method = authzreq["code_challenge_method"] except KeyError: _method = "S256" resp = self.verify_code_challenge( areq["code_verifier"], authzreq["code_challenge"], _method ) if resp: return resp if "state" in areq: if self.sdb[areq["code"]]["state"] != areq["state"]: logger.error("State value mismatch") err = TokenErrorResponse(error="unauthorized_client") return Unauthorized(err.to_json(), content="application/json") resp = self.token_scope_check(areq, _info) if resp: return resp # If redirect_uri was in the initial authorization request # verify that the one given here is the correct one. if "redirect_uri" in _info and areq["redirect_uri"] != _info["redirect_uri"]: logger.error("Redirect_uri mismatch") err = TokenErrorResponse(error="unauthorized_client") return Unauthorized(err.to_json(), content="application/json") issue_refresh = False if "scope" in authzreq and "offline_access" in authzreq["scope"]: if authzreq["response_type"] == "code": issue_refresh = True try: _tinfo = self.sdb.upgrade_to_token( areq["code"], issue_refresh=issue_refresh ) except AccessCodeUsed: err = TokenErrorResponse( error="invalid_grant", error_description="Access grant used" ) return Response( err.to_json(), content="application/json", status="401 Unauthorized" ) logger.debug("_tinfo: %s" % _tinfo) atr_class = self.server.message_factory.get_response_type("token_endpoint") atr = atr_class(**by_schema(atr_class, **_tinfo)) logger.debug("AccessTokenResponse: %s" % atr) return Response( atr.to_json(), content="application/json", headers=OAUTH2_NOCACHE_HEADERS )
logger.info("Missing Response") return Unauthorized("You are not authorized!"), False try: response = self.sp.parse_authn_request_response( request["SAMLResponse"][0], binding, self.cache_outstanding_queries) except UnknownPrincipal, excp: logger.error("UnknownPrincipal: %s" % (excp, )) return Unauthorized(self.not_authorized), False except UnsupportedBinding, excp: logger.error("UnsupportedBinding: %s" % (excp, )) return Unauthorized(self.not_authorized), False except VerificationError, err: logger.error("Verification error: %s" % (err, )) return Unauthorized(self.not_authorized), False except Exception, err: logger.error("Other error: %s" % (err, )) return Unauthorized(self.not_authorized), False if self.sp_conf.VALID_ATTRIBUTE_RESPONSE is not None: for k, v in self.sp_conf.VALID_ATTRIBUTE_RESPONSE.iteritems(): if k not in response.ava: return Unauthorized(self.not_authorized), False else: allowed = False for allowed_attr_value in v: if isinstance(response.ava[k], list): for resp_value in response.ava[k]: if allowed_attr_value in resp_value: allowed = True
def verify(self, request, cookie, path, requrl, end_point_index=None, **kwargs): """ Verifies if the authentication was successful. :rtype : Response :param request: Contains the request parameters. :param cookie: Cookies sent with the request. :param kwargs: Any other parameters. :return: If the authentication was successful: a redirect to the return_to url. Otherwise a unauthorized response. :raise: ValueError """ if isinstance(request, six.string_types): request = parse_qs(request) elif isinstance(request, dict): pass else: raise ValueError("Wrong type of input") acs = self.sp.config.getattr("endpoints", "sp")["assertion_consumer_service"] acs_endpoints = [(ep[0].rsplit("/", 1)[1], ep[1]) for ep in acs] binding = None path = path[1:] for endp in acs_endpoints: if path == endp[0]: binding = endp[1] break saml_cookie, _ts, _typ = self.getCookieValue(cookie, self.CONST_SAML_COOKIE) data = json.loads(saml_cookie) rp_query_cookie = self.get_multi_auth_cookie(cookie) query = rp_query_cookie if not query: query = base64.b64decode(data[self.CONST_QUERY]).decode("ascii") if data[self.CONST_HASIDP] == 'False': (done, response) = self._pick_idp(request, end_point_index) if done == 0: entity_id = response # Do the AuthnRequest resp = self._redirect_to_auth(self.sp, entity_id, query, end_point_index) return resp, False return response, False if not request: logger.info("Missing Response") return Unauthorized("You are not authorized!"), False try: response = self.sp.parse_authn_request_response( request["SAMLResponse"][0], binding, self.cache_outstanding_queries) except UnknownPrincipal as excp: logger.error("UnknownPrincipal: %s" % (excp, )) return Unauthorized(self.not_authorized), False except UnsupportedBinding as excp: logger.error("UnsupportedBinding: %s" % (excp, )) return Unauthorized(self.not_authorized), False except VerificationError as err: logger.error("Verification error: %s" % (err, )) return Unauthorized(self.not_authorized), False except Exception as err: logger.error("Other error: %s" % (err, )) return Unauthorized(self.not_authorized), False if self.sp_conf.VALID_ATTRIBUTE_RESPONSE is not None: for k, v in six.iteritems(self.sp_conf.VALID_ATTRIBUTE_RESPONSE): if k not in response.ava: return Unauthorized(self.not_authorized), False else: allowed = False for allowed_attr_value in v: if isinstance(response.ava[k], list): for resp_value in response.ava[k]: if allowed_attr_value in resp_value: allowed = True break elif allowed_attr_value in response.ava[k]: allowed = True break if not allowed: return Unauthorized(self.not_authorized), False # logger.info("parsed OK")' uid = response.assertion.subject.name_id.text if self.userinfo == "AA": if response.entity_id is not None and self.samlcache is not None: self.samlcache["AA_ENTITYID"] = response.entity_id self.setup_userdb(uid, response.ava) return_to = create_return_url(self.return_to, uid, **{self.query_param: "true"}) if '?' in return_to: return_to += "&" else: return_to += "?" return_to += query auth_cookie = self.create_cookie(uid, "samlm") resp = SeeOther(str(return_to), headers=[auth_cookie]) return resp, True
class SAMLAuthnMethod(UserAuthnMethod): CONST_QUERY = "query" CONST_SAML_COOKIE = "samlauthc" CONST_HASIDP = "hasidp" def __init__(self, srv, lookup, userdb, spconf, url, return_to, cache=None, bindings=None, userinfo=None, samlcache=None): """ Constructor for the class. :param srv: Usually none, but otherwise the oic server. :param return_to: The URL to return to after a successful authentication. """ self.userdb = userdb self.userinfo = userinfo if cache is None: self.cache_outstanding_queries = {} else: self.cache_outstanding_queries = cache UserAuthnMethod.__init__(self, srv) self.return_to = return_to self.idp_query_param = "IdpQuery" if bindings: self.bindings = bindings else: self.bindings = [ BINDING_HTTP_REDIRECT, BINDING_HTTP_POST, BINDING_HTTP_ARTIFACT ] # TODO Why does this exist? self.verification_endpoint = "" #Configurations for the SP handler. (pyOpSamlProxy.client.sp.conf) self.sp_conf = importlib.import_module(spconf) #self.sp_conf.BASE = self.sp_conf.BASE % url ntf = NamedTemporaryFile(suffix="pyoidc.py", delete=True) ntf.write("CONFIG = " + str(self.sp_conf.CONFIG).replace("%s", url)) ntf.seek(0) self.sp = Saml2Client(config_file="%s" % ntf.name) mte = lookup.get_template("unauthorized.mako") argv = { "message": "You are not authorized!", } self.not_authorized = mte.render(**argv) self.samlcache = self.sp_conf.SAML_CACHE def __call__(self, query="", end_point_index=None, *args, **kwargs): (done, response) = self._pick_idp(query, end_point_index) if done == 0: entity_id = response # Do the AuthnRequest resp = self._redirect_to_auth(self.sp, entity_id, query, end_point_index) return resp return response def verify(self, request, cookie, path, requrl, end_point_index=None, **kwargs): """ Verifies if the authentication was successful. :rtype : Response :param request: Contains the request parameters. :param cookie: Cookies sent with the request. :param kwargs: Any other parameters. :return: If the authentication was successful: a redirect to the return_to url. Otherwise a unauthorized response. :raise: ValueError """ if isinstance(request, basestring): request = parse_qs(request) elif isinstance(request, dict): pass else: raise ValueError("Wrong type of input") acs = self.sp.config.getattr("endpoints", "sp")["assertion_consumer_service"] acs_endpoints = [(ep[0].rsplit("/", 1)[1], ep[1]) for ep in acs] binding = None path = path[1:] for endp in acs_endpoints: if path == endp[0]: binding = endp[1] break saml_cookie, _ts, _typ = self.getCookieValue( cookie, self.CONST_SAML_COOKIE) data = json.loads(saml_cookie) rp_query_cookie = self.get_multi_auth_cookie(cookie) query = rp_query_cookie if not query: query = base64.b64decode(data[self.CONST_QUERY]) if data[self.CONST_HASIDP] == 'False': (done, response) = self._pick_idp(request, end_point_index) if done == 0: entity_id = response # Do the AuthnRequest resp = self._redirect_to_auth(self.sp, entity_id, query, end_point_index) return resp, False return response, False if not request: logger.info("Missing Response") return Unauthorized("You are not authorized!"), False try: response = self.sp.parse_authn_request_response( request["SAMLResponse"][0], binding, self.cache_outstanding_queries) except UnknownPrincipal, excp: logger.error("UnknownPrincipal: %s" % (excp, )) return Unauthorized(self.not_authorized), False except UnsupportedBinding, excp: logger.error("UnsupportedBinding: %s" % (excp, )) return Unauthorized(self.not_authorized), False
def token_endpoint(self, request="", authn="", dtype="urlencoded", **kwargs): """ Provide clients with access tokens. :param authn: Auhentication info, comes from HTTP header. :param request: The request. :param dtype: deserialization method for the request. """ logger.debug("- token -") logger.debug("token_request: %s" % sanitize(request)) areq = self.server.message_factory.get_request_type( "token_endpoint")().deserialize(request, dtype) # Verify client authentication try: client_id = self.client_authn(self, areq, authn) except (FailedAuthentication, AuthnFailure) as err: logger.error(err) error = TokenErrorResponse(error="unauthorized_client", error_description="%s" % err) return Unauthorized(error.to_json(), content="application/json") logger.debug("AccessTokenRequest: %s" % sanitize(areq)) # `code` is not mandatory for all requests if "code" in areq: try: _info = self.sdb[areq["code"]] except KeyError: logger.error("Code not present in SessionDB") error = TokenErrorResponse(error="unauthorized_client", error_description="Invalid code.") return Unauthorized(error.to_json(), content="application/json") resp = self.token_scope_check(areq, _info) if resp: return resp # If redirect_uri was in the initial authorization request verify that they match if ("redirect_uri" in _info and areq["redirect_uri"] != _info["redirect_uri"]): logger.error("Redirect_uri mismatch") error = TokenErrorResponse( error="unauthorized_client", error_description="Redirect_uris do not match.", ) return Unauthorized(error.to_json(), content="application/json") if "state" in areq: if _info["state"] != areq["state"]: logger.error("State value mismatch") error = TokenErrorResponse( error="unauthorized_client", error_description="State values do not match.", ) return Unauthorized(error.to_json(), content="application/json") # Propagate the client_id further areq.setdefault("client_id", client_id) grant_type = areq["grant_type"] if grant_type == "authorization_code": return self.code_grant_type(areq) elif grant_type == "refresh_token": return self.refresh_token_grant_type(areq) elif grant_type == "client_credentials": return self.client_credentials_grant_type(areq) elif grant_type == "password": return self.password_grant_type(areq) else: raise UnSupported("grant_type: {}".format(grant_type))