def parse_request(self, request, http_info=None, **kwargs): """ :param request: :param auth: :param kwargs: :return: """ if not request: request = {} # Verify that the client is allowed to do this try: auth_info = self.client_authentication(request, http_info, **kwargs) except UnknownOrNoAuthnMethod: pass else: if not auth_info: pass elif isinstance(auth_info, ResponseMessage): return auth_info else: request["client_id"] = auth_info["client_id"] request["access_token"] = auth_info["token"] if isinstance(request, dict): _context = self.server_get("endpoint_context") request = self.request_cls(**request) if not request.verify(keyjar=_context.keyjar, sigalg=""): raise InvalidRequest("Request didn't verify") # id_token_signing_alg_values_supported try: _ith = request[verified_claim_name("id_token_hint")] except KeyError: pass else: if ( _ith.jws_header["alg"] not in _context.provider_info["id_token_signing_alg_values_supported"] ): raise JWSException("Unsupported signing algorithm") return request
def parse_request(self, request, auth=None, **kwargs): """ :param request: :param auth: :param kwargs: :return: """ if not request: request = {} # Verify that the client is allowed to do this try: auth_info = self.client_authentication(request, auth, **kwargs) except UnknownOrNoAuthnMethod: pass else: if isinstance(auth_info, ResponseMessage): return auth_info else: request['client_id'] = auth_info['client_id'] request['access_token'] = auth_info['token'] if isinstance(request, dict): request = self.request_cls(**request) if not request.verify(keyjar=self.endpoint_context.keyjar, sigalg=''): raise InvalidRequest("Didn't verify") # id_token_signing_alg_values_supported _ith = request[verified_claim_name("id_token_hint")] if _ith.jws_header['alg'] not in \ self.endpoint_context.provider_info[ 'id_token_signing_alg_values_supported']: raise JWSException('Unsupported signing algorithm') return request
def verify(self, **kwargs): """Authorization Request parameters that are OPTIONAL in the OAuth 2.0 specification MAY be included in the OpenID Request Object without also passing them as OAuth 2.0 Authorization Request parameters, with one exception: The scope parameter MUST always be present in OAuth 2.0 Authorization Request parameters. All parameter values that are present both in the OAuth 2.0 Authorization Request and in the OpenID Request Object MUST exactly match.""" super(AuthorizationRequest, self).verify(**kwargs) clear_verified_claims(self) args = {} for arg in ["keyjar", "opponent_id", "sender", "alg", "encalg", "encenc"]: try: args[arg] = kwargs[arg] except KeyError: pass if "opponent_id" not in kwargs: args["opponent_id"] = self["client_id"] if "request" in self: if isinstance(self["request"], str): # Try to decode the JWT, checks the signature oidr = OpenIDRequest().from_jwt(str(self["request"]), **args) # check if something is change in the original message for key, val in oidr.items(): if key in self: if self[key] != val: # log but otherwise ignore logger.warning("{} != {}".format(self[key], val)) # remove all claims _keys = list(self.keys()) for key in _keys: if key not in oidr: del self[key] self.update(oidr) # replace the JWT with the parsed and verified instance self[verified_claim_name("request")] = oidr if "id_token_hint" in self: if isinstance(self["id_token_hint"], str): idt = IdToken().from_jwt(str(self["id_token_hint"]), **args) self["verified_id_token_hint"] = idt if "response_type" not in self: raise MissingRequiredAttribute("response_type missing", self) _rt = self["response_type"] if "id_token" in _rt: if "nonce" not in self: raise MissingRequiredAttribute("Nonce missing", self) else: try: if self["nonce"] != kwargs["nonce"]: raise ValueError("Nonce in id_token not matching nonce in authz " "request") except KeyError: pass if "openid" not in self.get("scope", []): raise MissingRequiredValue("openid not in scope", self) if "offline_access" in self.get("scope", []): if "prompt" not in self or "consent" not in self["prompt"]: raise MissingRequiredValue("consent in prompt", self) if "prompt" in self: if "none" in self["prompt"] and len(self["prompt"]) > 1: raise InvalidRequest("prompt none combined with other value", self) return True
def process_request(self, request=None, cookie=None, **kwargs): """ Perform user logout :param request: :param cookie: :param kwargs: :return: """ _cntx = self.endpoint_context _sdb = _cntx.sdb if "post_logout_redirect_uri" in request: if "id_token_hint" not in request: raise InvalidRequest( "If post_logout_redirect_uri then id_token_hint is a MUST") _cookie_name = self.endpoint_context.cookie_name["session"] try: part = self.endpoint_context.cookie_dealer.get_cookie_value( cookie, cookie_name=_cookie_name) except IndexError: raise InvalidRequest("Cookie error") except KeyError: part = None if part: # value is a base64 encoded JSON document _cookie_info = json.loads(as_unicode(b64d(as_bytes(part[0])))) logger.debug("Cookie info: {}".format(_cookie_info)) _sid = _cookie_info["sid"] else: logger.debug("No relevant cookie") _sid = "" _cookie_info = {} if "id_token_hint" in request: logger.debug("ID token hint: {}".format( request[verified_claim_name("id_token_hint")])) auds = request[verified_claim_name("id_token_hint")]["aud"] _ith_sid = "" _sids = _sdb.sso_db.get_sids_by_sub( request[verified_claim_name("id_token_hint")]["sub"]) if _sids is None: raise ValueError("Unknown subject identifier") for _isid in _sids: if _sdb[_isid]["authn_req"]["client_id"] in auds: _ith_sid = _isid break if not _ith_sid: raise ValueError("Unknown subject") if _sid: if _ith_sid != _sid: # someone's messing with me raise ValueError("Wrong ID Token hint") else: _sid = _ith_sid else: auds = [] try: session = _sdb[_sid] except KeyError: raise ValueError("Can't find any corresponding session") client_id = session["authn_req"]["client_id"] # Does this match what's in the cookie ? if _cookie_info: if client_id != _cookie_info["client_id"]: logger.warning( "Client ID in authz request and in cookie does not match") raise ValueError("Wrong Client") if auds: if client_id not in auds: raise ValueError("Incorrect ID Token hint") _cinfo = _cntx.cdb[client_id] # verify that the post_logout_redirect_uri if present are among the ones # registered try: _uri = request["post_logout_redirect_uri"] except KeyError: if _cntx.issuer.endswith("/"): _uri = "{}{}".format(_cntx.issuer, self.kwargs["post_logout_uri_path"]) else: _uri = "{}/{}".format(_cntx.issuer, self.kwargs["post_logout_uri_path"]) plur = False else: plur = True verify_uri(_cntx, request, "post_logout_redirect_uri", client_id=client_id) payload = { "sid": _sid, "client_id": client_id, "user": session["authn_event"]["uid"], } # redirect user to OP logout verification page if plur and "state" in request: _uri = "{}?{}".format(_uri, urlencode({"state": request["state"]})) payload["state"] = request["state"] payload["redirect_uri"] = _uri logger.debug("JWS payload: {}".format(payload)) # From me to me _jws = JWT( _cntx.keyjar, iss=_cntx.issuer, lifetime=86400, sign_alg=self.kwargs["signing_alg"], ) sjwt = _jws.pack(payload=payload, recv=_cntx.issuer) location = "{}?{}".format(self.kwargs["logout_verify_url"], urlencode({"sjwt": sjwt})) return {"redirect_location": location}
def process_request(self, request=None, cookie=None, **kwargs): """ Perform user logout :param request: :param cookie: :param kwargs: :return: """ _sdb = self.endpoint_context.sdb try: part = self.endpoint_context.cookie_dealer.get_cookie_value( cookie, cookie_name='oidc_op') except IndexError: raise InvalidRequest('Cookie error') if part: # value is a base64 encoded JSON document _cookie_info = json.loads(as_unicode(b64d(as_bytes(part[0])))) _sid = _cookie_info['sid'] else: _sid = '' if 'id_token_hint' in request: _ith_sid = _sdb.sso_db.get_sids_by_sub( request[verified_claim_name("id_token_hint")]['sub'])[0] if _ith_sid != _sid: # someone's messing with me raise ValueError('Wrong ID Token hint') session = _sdb[_sid] client_id = session['authn_req']['client_id'] _cinfo = self.endpoint_context.cdb[client_id] # verify that the post_logout_redirect_uri if present are among the ones # registered try: _url_q = splitquery(request['post_logout_redirect_uri']) except KeyError: pass else: if not _url_q in _cinfo['post_logout_redirect_uris']: raise ValueError('Unregistered post_logout_redirect_uri') # Kill the session _sdb.revoke_session(sid=_sid) if 'post_logout_redirect_uri' in request: _ruri = request["post_logout_redirect_uri"] if 'state' in request: _ruri = '{}?{}'.format(_ruri, urlencode({'state': request['state']})) else: # To my own logout-done page try: _ruri = self.endpoint_context.conf['post_logout_page'] except KeyError: _ruri = self.endpoint_context.issuer return {'response_args': _ruri}
def process_request( self, request: Optional[Union[Message, dict]] = None, http_info: Optional[dict] = None, **kwargs ): """ Perform user logout :param request: :param http_info: :param kwargs: :return: """ _context = self.server_get("endpoint_context") _mngr = _context.session_manager if "post_logout_redirect_uri" in request: if "id_token_hint" not in request: raise InvalidRequest("If post_logout_redirect_uri then id_token_hint is a MUST") _cookies = http_info.get("cookie") _session_info = None if _cookies: _cookie_name = _context.cookie_handler.name["session"] try: _cookie_infos = _context.cookie_handler.parse_cookie( cookies=_cookies, name=_cookie_name ) except VerificationError: raise InvalidRequest("Cookie error") if _cookie_infos: # value is a JSON document _cookie_info = json.loads(_cookie_infos[0]["value"]) logger.debug("Cookie info: {}".format(_cookie_info)) try: _session_info = _mngr.get_session_info(_cookie_info["sid"], grant=True) except KeyError: raise ValueError("Can't find any corresponding session") if _session_info is None: logger.debug("No relevant cookie") raise ValueError("Missing cookie") if "id_token_hint" in request and _session_info: _id_token = request[verified_claim_name("id_token_hint")] logger.debug("ID token hint: {}".format(_id_token)) _aud = _id_token["aud"] if _session_info["client_id"] not in _aud: raise ValueError("Client ID doesn't match") if _id_token["sub"] != _session_info["grant"].sub: raise ValueError("Sub doesn't match") else: _aud = [] # _context.cdb[_session_info["client_id"]] # verify that the post_logout_redirect_uri if present are among the ones # registered try: _uri = request["post_logout_redirect_uri"] except KeyError: if _context.issuer.endswith("/"): _uri = "{}{}".format(_context.issuer, self.kwargs["post_logout_uri_path"]) else: _uri = "{}/{}".format(_context.issuer, self.kwargs["post_logout_uri_path"]) plur = False else: plur = True verify_uri( _context, request, "post_logout_redirect_uri", client_id=_session_info["client_id"], ) payload = { "sid": _session_info["session_id"], } # redirect user to OP logout verification page if plur and "state" in request: _uri = "{}?{}".format(_uri, urlencode({"state": request["state"]})) payload["state"] = request["state"] payload["redirect_uri"] = _uri logger.debug("JWS payload: {}".format(payload)) # From me to me _jws = JWT( _context.keyjar, iss=_context.issuer, lifetime=86400, sign_alg=self.kwargs["signing_alg"], ) sjwt = _jws.pack(payload=payload, recv=_context.issuer) location = "{}?{}".format(self.kwargs["logout_verify_url"], urlencode({"sjwt": sjwt})) return {"redirect_location": location}