Example #1
0
    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
Example #2
0
    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
Example #3
0
    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
Example #4
0
    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}
Example #5
0
    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}
Example #6
0
    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}