Example #1
0
    def parse_request_response(self,
                               reqresp,
                               response,
                               body_type,
                               state="",
                               verify=True,
                               **kwargs):

        if reqresp.status_code in SUCCESSFUL:
            body_type = verify_header(reqresp, body_type)
        elif reqresp.status_code in [302, 303]:  # redirect
            return reqresp
        elif reqresp.status_code == 500:
            logger.error("(%d) %s" %
                         (reqresp.status_code, sanitize(reqresp.text)))
            raise ParseError("ERROR: Something went wrong: %s" % reqresp.text)
        elif reqresp.status_code in [400, 401]:
            # expecting an error response
            if issubclass(response, ErrorResponse):
                pass
        else:
            logger.error("(%d) %s" %
                         (reqresp.status_code, sanitize(reqresp.text)))
            raise HttpError("HTTP ERROR: %s [%s] on %s" %
                            (reqresp.text, reqresp.status_code, reqresp.url))

        if response:
            if body_type == 'txt':
                # no meaning trying to parse unstructured text
                return reqresp.text
            if not verify:
                # AymRod: skip parsing
                return reqresp.text
            else:
                return self.parse_response(response, reqresp.text, body_type,
                                           state, **kwargs)

        # could be an error response
        if reqresp.status_code in [200, 400, 401]:
            if body_type == 'txt':
                body_type = 'urlencoded'
            try:
                err = ErrorResponse().deserialize(reqresp.message,
                                                  method=body_type)
                try:
                    err.verify()
                except PyoidcError:
                    pass
                else:
                    return err
            except Exception:
                pass

        return reqresp
Example #2
0
    def provider_config(
        self,
        issuer: str,
        keys: bool = True,
        endpoints: bool = True,
        serv_pattern: str = OIDCONF_PATTERN,
    ) -> ASConfigurationResponse:

        response_cls = self.message_factory.get_response_type("configuration_endpoint")
        if issuer.endswith("/"):
            _issuer = issuer[:-1]
        else:
            _issuer = issuer

        url = serv_pattern % _issuer

        pcr = None
        r = self.http_request(url, allow_redirects=True)
        if r.status_code == 200:
            try:
                pcr = response_cls().from_json(r.text)
            except Exception as e:
                # FIXME: This should catch specific exception from `from_json()`
                _err_txt = "Faulty provider config response: {}".format(e)
                logger.error(sanitize(_err_txt))
                raise ParseError(_err_txt)
        else:
            raise CommunicationError("Trying '%s', status %s" % (url, r.status_code))

        self.store_response(pcr, r.text)
        self.handle_provider_config(pcr, issuer, keys, endpoints)
        return pcr
Example #3
0
    def do_access_token_request(self, request=AccessTokenRequest,
                                scope="", state="", body_type="json",
                                method="POST", request_args=None,
                                extra_args=None, http_args=None,
                                response_cls=AccessTokenResponse,
                                authn_method="", **kwargs):

        kwargs['authn_endpoint'] = 'token'
        # method is default POST
        url, body, ht_args, csi = self.request_info(request, method=method,
                                                    request_args=request_args,
                                                    extra_args=extra_args,
                                                    scope=scope, state=state,
                                                    authn_method=authn_method,
                                                    **kwargs)

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(ht_args)

        if self.events is not None:
            self.events.store('request_url', url)
            self.events.store('request_http_args', http_args)
            self.events.store('Request', body)

        logger.debug("<do_access_token> URL: %s, Body: %s" % (url,
                                                              sanitize(body)))
        logger.debug("<do_access_token> response_cls: %s" % response_cls)

        return self.request_and_return(url, response_cls, method, body,
                                       body_type, state=state,
                                       http_args=http_args, **kwargs)
Example #4
0
    def do_access_token_request(self, request=AccessTokenRequest,
                                scope="", state="", body_type="json",
                                method="POST", request_args=None,
                                extra_args=None, http_args=None,
                                response_cls=AccessTokenResponse,
                                authn_method="", **kwargs):

        kwargs['authn_endpoint'] = 'token'
        # method is default POST
        url, body, ht_args, csi = self.request_info(request, method=method,
                                                    request_args=request_args,
                                                    extra_args=extra_args,
                                                    scope=scope, state=state,
                                                    authn_method=authn_method,
                                                    **kwargs)

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(ht_args)

        if self.events is not None:
            self.events.store('request_url', url)
            self.events.store('request_http_args', http_args)
            self.events.store('Request', body)

        logger.debug("<do_access_token> URL: %s, Body: %s" % (url,
                                                              sanitize(body)))
        logger.debug("<do_access_token> response_cls: %s" % response_cls)

        return self.request_and_return(url, response_cls, method, body,
                                       body_type, state=state,
                                       http_args=http_args, **kwargs)
Example #5
0
    def parse_request_response(self, reqresp, response, body_type, state="",
                               **kwargs):

        if reqresp.status_code in SUCCESSFUL:
            body_type = verify_header(reqresp, body_type)
        elif reqresp.status_code in [302, 303]:  # redirect
            return reqresp
        elif reqresp.status_code == 500:
            logger.error("(%d) %s" % (reqresp.status_code,
                                      sanitize(reqresp.text)))
            raise ParseError("ERROR: Something went wrong: %s" % reqresp.text)
        elif reqresp.status_code in [400, 401]:
            # expecting an error response
            if issubclass(response, ErrorResponse):
                pass
        else:
            logger.error("(%d) %s" % (reqresp.status_code,
                                      sanitize(reqresp.text)))
            raise HttpError("HTTP ERROR: %s [%s] on %s" % (
                reqresp.text, reqresp.status_code, reqresp.url))

        if response:
            if body_type == 'txt':
                # no meaning trying to parse unstructured text
                return reqresp.text
            return self.parse_response(response, reqresp.text, body_type,
                                       state, **kwargs)

        # could be an error response
        if reqresp.status_code in [200, 400, 401]:
            if body_type == 'txt':
                body_type = 'urlencoded'
            try:
                err = ErrorResponse().deserialize(reqresp.message,
                                                  method=body_type)
                try:
                    err.verify()
                except PyoidcError:
                    pass
                else:
                    return err
            except Exception:
                pass

        return reqresp
Example #6
0
    def do_access_token_request(
        self,
        scope: str = "",
        state: str = "",
        body_type: ENCODINGS = "json",
        method="POST",
        request_args=None,
        extra_args=None,
        http_args=None,
        authn_method="",
        **kwargs,
    ) -> AccessTokenResponse:

        request = self.message_factory.get_request_type("token_endpoint")
        response_cls = self.message_factory.get_response_type("token_endpoint")

        if extra_args is None:
            extra_args = {}
        kwargs["authn_endpoint"] = "token"
        if http_args is not None and "password" in http_args:
            extra_args["password"] = http_args.pop("password")

        # method is default POST
        url, body, ht_args, csi = self.request_info(
            request,
            method=method,
            request_args=request_args,
            extra_args=extra_args,
            scope=scope,
            state=state,
            authn_method=authn_method,
            **kwargs,
        )

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(ht_args)

        if self.events is not None:
            self.events.store("request_url", url)
            self.events.store("request_http_args", http_args)
            self.events.store("Request", body)

        logger.debug("<do_access_token> URL: %s, Body: %s" % (url, sanitize(body)))
        logger.debug("<do_access_token> response_cls: %s" % response_cls)

        return self.request_and_return(
            url,
            response_cls,
            method,
            body,
            body_type,
            state=state,
            http_args=http_args,
            **kwargs,
        )
Example #7
0
    def construct_request(self, request, request_args=None, extra_args=None):
        if request_args is None:
            request_args = {}

        kwargs = self._parse_args(request, **request_args)

        if extra_args:
            kwargs.update(extra_args)
        logger.debug("request: %s" % sanitize(request))
        return request(**kwargs)
Example #8
0
    def construct_request(self, request, request_args=None, extra_args=None):
        if request_args is None:
            request_args = {}

        kwargs = self._parse_args(request, **request_args)

        if extra_args:
            kwargs.update(extra_args)
        logger.debug("request: %s" % sanitize(request))
        return request(**kwargs)
Example #9
0
def error_response(error, descr=None, status="400 Bad Request"):
    logger.error("%s" % sanitize(error))
    response = ErrorResponse(error=error, error_description=descr)
    return Response(response.to_json(),
                    content="application/json",
                    status=status)
Example #10
0
    def parse_response(self,
                       response,
                       info="",
                       sformat="json",
                       state="",
                       **kwargs):
        """
        Parse a response

        :param response: Response type
        :param info: The response, can be either in a JSON or an urlencoded
            format
        :param sformat: Which serialization that was used
        :param state: The state
        :param kwargs: Extra key word arguments
        :return: The parsed and to some extend verified response
        """

        _r2e = self.response2error

        if sformat == "urlencoded":
            info = self.get_urlinfo(info)

        # if self.events:
        #    self.events.store('Response', info)
        resp = response().deserialize(info, sformat, **kwargs)
        msg = 'Initial response parsing => "{}"'
        logger.debug(msg.format(sanitize(resp.to_dict())))
        if self.events:
            self.events.store('Response', resp.to_dict())

        if "error" in resp and not isinstance(resp, ErrorResponse):
            resp = None
            try:
                errmsgs = _r2e[response.__name__]
            except KeyError:
                errmsgs = [ErrorResponse]

            try:
                for errmsg in errmsgs:
                    try:
                        resp = errmsg().deserialize(info, sformat)
                        resp.verify()
                        break
                    except Exception:
                        resp = None
            except KeyError:
                pass
        elif resp.only_extras():
            resp = None
        else:
            kwargs["client_id"] = self.client_id
            try:
                kwargs['iss'] = self.provider_info['issuer']
            except (KeyError, AttributeError):
                if self.issuer:
                    kwargs['iss'] = self.issuer

            if "key" not in kwargs and "keyjar" not in kwargs:
                kwargs["keyjar"] = self.keyjar

            logger.debug("Verify response with {}".format(sanitize(kwargs)))
            verf = resp.verify(**kwargs)

            if not verf:
                logger.error('Verification of the response failed')
                raise PyoidcError("Verification of the response failed")
            if resp.type() == "AuthorizationResponse" and "scope" not in resp:
                try:
                    resp["scope"] = kwargs["scope"]
                except KeyError:
                    pass

        if not resp:
            logger.error('Missing or faulty response')
            raise ResponseError("Missing or faulty response")

        self.store_response(resp, info)

        if resp.type() in ["AuthorizationResponse", "AccessTokenResponse"]:
            try:
                _state = resp["state"]
            except (AttributeError, KeyError):
                _state = ""

            if not _state:
                _state = state

            try:
                self.grant[_state].update(resp)
            except KeyError:
                self.grant[_state] = self.grant_class(resp=resp)

        return resp
Example #11
0
def error_response(error, descr=None, status_code=400):
    logger.error("%s" % sanitize(error))
    response = ErrorResponse(error=error, error_description=descr)
    return Response(response.to_json(), content="application/json", status_code=status_code)
Example #12
0
    def parse_response(self, response, info="", sformat="json", state="",
                       **kwargs):
        """
        Parse a response

        :param response: Response type
        :param info: The response, can be either in a JSON or an urlencoded
            format
        :param sformat: Which serialization that was used
        :param state: The state
        :param kwargs: Extra key word arguments
        :return: The parsed and to some extend verified response
        """

        _r2e = self.response2error

        if sformat == "urlencoded":
            info = self.get_urlinfo(info)

        resp = response().deserialize(info, sformat, **kwargs)
        msg = 'Initial response parsing => "{}"'
        logger.debug(msg.format(sanitize(resp.to_dict())))
        if self.events:
            self.events.store('Response', resp.to_dict())

        if "error" in resp and not isinstance(resp, ErrorResponse):
            resp = None
            try:
                errmsgs = _r2e[response.__name__]
            except KeyError:
                errmsgs = [ErrorResponse]

            try:
                for errmsg in errmsgs:
                    try:
                        resp = errmsg().deserialize(info, sformat)
                        resp.verify()
                        break
                    except Exception:
                        resp = None
            except KeyError:
                pass
        elif resp.only_extras():
            resp = None
        else:
            kwargs["client_id"] = self.client_id
            try:
                kwargs['iss'] = self.provider_info['issuer']
            except (KeyError, AttributeError):
                if self.issuer:
                    kwargs['iss'] = self.issuer

            if "key" not in kwargs and "keyjar" not in kwargs:
                kwargs["keyjar"] = self.keyjar

            logger.debug("Verify response with {}".format(sanitize(kwargs)))
            verf = resp.verify(**kwargs)

            if not verf:
                logger.error('Verification of the response failed')
                raise PyoidcError("Verification of the response failed")
            if resp.type() == "AuthorizationResponse" and "scope" not in resp:
                try:
                    resp["scope"] = kwargs["scope"]
                except KeyError:
                    pass

        if not resp:
            logger.error('Missing or faulty response')
            raise ResponseError("Missing or faulty response")

        self.store_response(resp, info)

        if resp.type() in ["AuthorizationResponse", "AccessTokenResponse"]:
            try:
                _state = resp["state"]
            except (AttributeError, KeyError):
                _state = ""

            if not _state:
                _state = state

            try:
                self.grant[_state].update(resp)
            except KeyError:
                self.grant[_state] = self.grant_class(resp=resp)

        return resp
Example #13
0
    def do_access_token_request(self,
                                request=None,
                                scope: str = "",
                                state: str = "",
                                body_type: ENCODINGS = "json",
                                method="POST",
                                request_args=None,
                                extra_args=None,
                                http_args=None,
                                response_cls=None,
                                authn_method="",
                                **kwargs) -> AccessTokenResponse:
        if request is not None:
            warnings.warn(
                "Passing `request` is deprecated. Please use `message_factory` instead.",
                DeprecationWarning,
                stacklevel=2,
            )
        else:
            # TODO: This can be moved to the call once we remove the kwarg
            request = self.message_factory.get_request_type("token_endpoint")
        if response_cls is not None:
            warnings.warn(
                "Passing `response_cls` is deprecated. Please use `message_factory` instead.",
                DeprecationWarning,
                stacklevel=2,
            )
        else:
            # TODO: This can be moved to the call once we remove the kwarg
            response_cls = self.message_factory.get_response_type(
                "token_endpoint")

        kwargs["authn_endpoint"] = "token"
        # method is default POST
        url, body, ht_args, csi = self.request_info(request,
                                                    method=method,
                                                    request_args=request_args,
                                                    extra_args=extra_args,
                                                    scope=scope,
                                                    state=state,
                                                    authn_method=authn_method,
                                                    **kwargs)

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(ht_args)

        if self.events is not None:
            self.events.store("request_url", url)
            self.events.store("request_http_args", http_args)
            self.events.store("Request", body)

        logger.debug("<do_access_token> URL: %s, Body: %s" %
                     (url, sanitize(body)))
        logger.debug("<do_access_token> response_cls: %s" % response_cls)

        return self.request_and_return(url,
                                       response_cls,
                                       method,
                                       body,
                                       body_type,
                                       state=state,
                                       http_args=http_args,
                                       **kwargs)