Exemple #1
0
def request_and_return(conv, url, trace, response_type=None, method="GET",
                       body=None, body_type="json", state="", http_args=None,
                       **kwargs):
    """
    :param url: The URL to which the request should be sent
    :param response_type: Response type
    :param method: Which HTTP method to use
    :param body: A message body if any
    :param body_type: The format of the body of the return message
    :param http_args: Arguments for the HTTP client
    :return: A cls or ErrorResponse instance or the HTTP response
        instance if no response body was expected.
    """

    if http_args is None:
        http_args = {}

    logger.debug("request.headers: %s" % http_args)
    logger.debug("request.body: %s" % body)
    logger.debug("request.url: %s" % url)
    logger.debug("request.method: %s" % method)

    _cli = conv.client
    try:
        _resp = _cli.http_request(url, method, data=body, **http_args)
    except Exception:
        raise

    conv.timestamp.append((url, utc_time_sans_frac()))

    return do_response(_resp, conv, url, trace, _cli, body_type, response_type,
                       state, **kwargs)
Exemple #2
0
def request_and_return(conv,
                       url,
                       trace,
                       response_type=None,
                       method="GET",
                       body=None,
                       body_type="json",
                       state="",
                       http_args=None,
                       **kwargs):
    """
    :param url: The URL to which the request should be sent
    :param response_type: Response type
    :param method: Which HTTP method to use
    :param body: A message body if any
    :param body_type: The format of the body of the return message
    :param http_args: Arguments for the HTTP client
    :return: A cls or ErrorResponse instance or the HTTP response
        instance if no response body was expected.
    """

    if http_args is None:
        http_args = {}

    logger.debug("request.headers: %s" % http_args)
    logger.debug("request.body: %s" % body)
    logger.debug("request.url: %s" % url)
    logger.debug("request.method: %s" % method)

    _cli = conv.client
    try:
        _resp = _cli.http_request(url, method, data=body, **http_args)
    except Exception:
        raise

    conv.timestamp.append((url, utc_time_sans_frac()))

    return do_response(_resp, conv, url, trace, _cli, body_type, response_type,
                       state, **kwargs)
Exemple #3
0
    def run_sequence(self, sequence_info, session, conv, ots, trace, index):
        while index < len(sequence_info["sequence"]):
            logger.info("###{i}### {f} ###{i}###".format(f=session["testid"],
                                                         i=index))
            session["index"] = index
            try:
                (req_c, resp_c), _kwa = sequence_info["sequence"][index]
            except (ValueError, TypeError):  # Not a tuple
                ret = self.none_request_response(sequence_info, index, session,
                                                 conv)
                self.dump_log(session)
                if isinstance(ret, basestring):
                    session["ckey"] = ret
                elif ret:
                    return ret
            else:
                if conv.protocol_response:
                    # If last response was an error response, bail out.
                    inst, txt = conv.protocol_response[-1]
                    try:
                        session["expect_error"]
                    except KeyError:
                        if isinstance(inst, ErrorResponse):
                            return self.err_response(session, "", inst)
                try:
                    kwargs = setup(_kwa, conv)
                except NotSupported:
                    self.store_test_info(session)
                    return self.opresult(conv, session)
                except Exception as err:
                    return self.err_response(session, "function()", err)

                try:
                    expect_error = _kwa["expect_error"]
                except KeyError:
                    expect_error = None
                else:
                    del _kwa["expect_error"]

                req = req_c(conv)
                try:
                    _pt = req.tests["pre"]
                except KeyError:
                    pass
                else:
                    if _pt:
                        try:
                            conv.test_output.append((req.request, "pre"))
                            conv.test_sequence(_pt)
                        except Exception as err:
                            return self.err_response(session, "pre-test", err)

                conv.request_spec = req

                conv.trace.info("------------ %s ------------" % req_c.request)
                if req_c == Discover:
                    # Special since it's just a GET on a URL
                    try:
                        _r = req.discover(
                            ots.client,
                            issuer=ots.config.CLIENT["srv_discovery_url"])
                    except ConnectionError:
                        self.log_fault(session, "Connection Error",
                                       "discover_request", ERROR)
                        conv.trace.info(END_TAG)
                        return self.fini(session, conv)

                    conv.position, conv.last_response, conv.last_content = _r

                    if conv.last_response.status >= 400:
                        return self.err_response(session, "discover",
                                                 conv.last_response.text)

                    for x in ots.client.keyjar[
                            ots.client.provider_info["issuer"]]:
                        try:
                            resp = ots.client.http_request(x.source)
                        except Exception as err:
                            return self.err_response(session, "jwks_fetch",
                                                     str(err))
                        else:
                            conv.last_response = resp
                            conv.last_content = resp.content
                            if resp.status_code < 300:
                                trace.info("JWKS: %s" %
                                           pprint_json(resp.content))
                            else:
                                return self.err_response(
                                    session, "jwks_fetch", resp.content)
                elif req_c == Webfinger:
                    try:
                        url = req.discover(**kwargs)
                    except ConnectionError:
                        self.log_fault(session, "Connection Error",
                                       "WebFinger_request", ERROR)
                        conv.trace.info(END_TAG)
                        return self.fini(session, conv)

                    if url:
                        conv.trace.request(url)
                        conv.test_output.append({
                            "id":
                            "-",
                            "status":
                            OK,
                            "message":
                            "Found discovery URL: %s" % url
                        })
                    else:
                        conv.test_output.append({
                            "id":
                            "-",
                            "status":
                            ERROR,
                            "message":
                            "Failed to find discovery URL"
                        })
                else:
                    try:
                        endp = req.endpoint
                    except AttributeError:
                        pass
                    else:
                        if not endpoint_support(conv.client, endp):
                            conv.test_output.append({
                                "id":
                                "-",
                                "status":
                                ERROR,
                                "message":
                                "%s not supported" % req.endpoint
                            })
                            return self.opresult(conv, session)

                    logger.info("request: %s" % req.request)
                    if req.request == "AuthorizationRequest":
                        # New state for each request
                        kwargs["request_args"].update({"state": rndstr()})
                        if not ots.client.provider_info:
                            return self.err_response(session, req.request,
                                                     "No provider info")
                    elif req.request in [
                            "AccessTokenRequest", "UserInfoRequest",
                            "RefreshAccessTokenRequest"
                    ]:
                        kwargs.update(
                            {"state": conv.AuthorizationRequest["state"]})
                        if not ots.client.provider_info:
                            return self.err_response(session, req.request,
                                                     "No provider info")

                    req.rm_nonstandard_args(message_factory)

                    # Extra arguments outside the OIDC spec
                    try:
                        _extra = ots.config.CLIENT["extra"][req.request]
                    except KeyError:
                        pass
                    except Exception as err:
                        return self.err_response(session, "config_extra", err)
                    else:
                        try:
                            kwargs["request_args"].update(_extra)
                        except KeyError:
                            kwargs["request_args"] = _extra

                    req.call_setup()

                    try:
                        url, body, ht_args = req.construct_request(
                            ots.client, **kwargs)
                    except PyoidcError as err:  # A OIDC specific error
                        return self.err_response(session, "construct_request",
                                                 err)

                    if req.request == "AuthorizationRequest":
                        session["response_type"] = kwargs["request_args"][
                            "response_type"]
                        logger.info("redirect.url: %s" % url)
                        logger.info("redirect.header: %s" % ht_args)
                        conv.timestamp.append((url, utc_time_sans_frac()))
                        resp = Redirect(str(url))
                        return resp(self.environ, self.start_response)
                    else:
                        _kwargs = {"http_args": ht_args}

                        if conv.AuthorizationRequest:
                            _kwargs["state"] = conv.AuthorizationRequest[
                                "state"]

                        try:
                            _method = kwargs["method"]
                        except KeyError:
                            _method = req.method
                        try:
                            _ctype = kwargs["ctype"]
                        except KeyError:
                            _ctype = resp_c.ctype

                        self.dump_log(session, session["testid"])

                        try:
                            response = request_and_return(
                                conv, url, trace,
                                message_factory(resp_c.response), _method,
                                body, _ctype, **_kwargs)
                        except MissingErrorResponse:
                            self.log_fault(session, "Missing Error Response",
                                           "request_response",
                                           self.get_err_type(session))
                            conv.trace.info(END_TAG)
                            return self.fini(session, conv)

                        except PyoidcError as err:
                            return self.err_response(session,
                                                     "request_and_return", err)
                        except JWKESTException as err:
                            return self.err_response(session,
                                                     "request_and_return", err)
                        except ConnectionError:
                            self.log_fault(session,
                                           "Connection Error", "request",
                                           self.get_err_type(session))
                            conv.trace.info(END_TAG)
                            return self.fini(session, conv)

                        if response is None:  # bail out
                            self.log_fault(session, "Empty response",
                                           "request_response",
                                           self.get_err_type(session))
                            conv.trace.info(END_TAG)
                            return self.fini(session, conv)

                        trace.response(response)
                        logger.info(response.to_dict())

                        if expect_error:
                            session["expect_error"] = True
                            if isinstance(response, ErrorResponse):
                                if expect_error["stop"]:
                                    index = len(sequence_info["sequence"])
                                    session["index"] = index
                                    continue
                            else:
                                trace.error("Expected error, didn't get it")
                                return self.err_response(
                                    session, "expected error", None)
                        else:
                            if resp_c.response == "RegistrationResponse":
                                if isinstance(response, RegistrationResponse):
                                    ots.client.store_registration_info(
                                        response)
                            elif resp_c.response == "AccessTokenResponse":
                                if "error" not in response:
                                    areq = conv.AuthorizationRequest.to_dict()
                                    try:
                                        del areq["acr_values"]
                                    except KeyError:
                                        pass

                try:
                    post_tests(conv, req_c, resp_c)
                except Exception as err:
                    return self.err_response(session, "post_test", err)

            index += 1
            _tid = session["testid"]
            self.dump_log(session, _tid)
            self.store_test_info(session)

        # wrap it up
        # Any after the fact tests ?
        try:
            if sequence_info["tests"]:
                conv.test_output.append(("After completing the test flow", ""))
                conv.test_sequence(sequence_info["tests"])
        except KeyError:
            pass
        except Exception as err:
            return self.err_response(session, "post_test", err)

        return self.fini(session, conv)
Exemple #4
0
    def run_sequence(self, sequence_info, session, conv, ots, trace, index):
        while index < len(sequence_info["sequence"]):
            logger.info("###{i}### {f} ###{i}###".format(
                f=session["testid"], i=index))
            session["index"] = index
            try:
                (req_c, resp_c), _kwa = sequence_info["sequence"][index]
            except (ValueError, TypeError):  # Not a tuple
                ret = self.none_request_response(sequence_info, index, session,
                                                 conv)
                self.dump_log(session)
                if isinstance(ret, basestring):
                    session["ckey"] = ret
                elif ret:
                    return ret
            else:
                if conv.protocol_response:
                    # If last response was an error response, bail out.
                    inst, txt = conv.protocol_response[-1]
                    try:
                        session["expect_error"]
                    except KeyError:
                        if isinstance(inst, ErrorResponse):
                            return self.err_response(session,"", inst)
                try:
                    kwargs = setup(_kwa, conv)
                except NotSupported:
                    self.store_test_info(session)
                    return self.opresult(conv, session)
                except Exception as err:
                    return self.err_response(session, "function()", err)

                try:
                    expect_error = _kwa["expect_error"]
                except KeyError:
                    expect_error = None
                else:
                    del _kwa["expect_error"]

                req = req_c(conv)
                try:
                    _pt = req.tests["pre"]
                except KeyError:
                    pass
                else:
                    if _pt:
                        try:
                            conv.test_output.append((req.request, "pre"))
                            conv.test_sequence(_pt)
                        except Exception as err:
                            return self.err_response(session, "pre-test", err)

                conv.request_spec = req

                conv.trace.info("------------ %s ------------" % req_c.request)
                if req_c == Discover:
                    # Special since it's just a GET on a URL
                    try:
                        _r = req.discover(
                            ots.client,
                            issuer=ots.config.CLIENT["srv_discovery_url"])
                    except ConnectionError:
                            self.log_fault(session, "Connection Error",
                                           "discover_request", ERROR)
                            conv.trace.info(END_TAG)
                            return self.fini(session, conv)

                    conv.position, conv.last_response, conv.last_content = _r

                    if conv.last_response.status >= 400:
                        return self.err_response(session, "discover",
                                                 conv.last_response.text)

                    for x in ots.client.keyjar[
                            ots.client.provider_info["issuer"]]:
                        try:
                            resp = ots.client.http_request(x.source)
                        except Exception as err:
                            return self.err_response(session, "jwks_fetch",
                                                     str(err))
                        else:
                            conv.last_response = resp
                            conv.last_content = resp.content
                            if resp.status_code < 300:
                                trace.info(
                                    "JWKS: %s" % pprint_json(resp.content))
                            else:
                                return self.err_response(session, "jwks_fetch",
                                                         resp.content)
                elif req_c == Webfinger:
                    try:
                        url = req.discover(**kwargs)
                    except ConnectionError:
                            self.log_fault(session, "Connection Error",
                                           "WebFinger_request", ERROR)
                            conv.trace.info(END_TAG)
                            return self.fini(session, conv)

                    if url:
                        conv.trace.request(url)
                        conv.test_output.append(
                            {"id": "-", "status": OK,
                             "message": "Found discovery URL: %s" % url})
                    else:
                        conv.test_output.append(
                            {"id": "-", "status": ERROR,
                             "message": "Failed to find discovery URL"})
                else:
                    try:
                        endp = req.endpoint
                    except AttributeError:
                        pass
                    else:
                        if not endpoint_support(conv.client, endp):
                            conv.test_output.append(
                                {"id": "-", "status": ERROR,
                                 "message": "%s not supported" % req.endpoint})
                            return self.opresult(conv, session)

                    logger.info("request: %s" % req.request)
                    if req.request == "AuthorizationRequest":
                        # New state for each request
                        kwargs["request_args"].update({"state": rndstr()})
                        if not ots.client.provider_info:
                            return self.err_response(session, req.request,
                                                     "No provider info")
                    elif req.request in ["AccessTokenRequest",
                                         "UserInfoRequest",
                                         "RefreshAccessTokenRequest"]:
                        kwargs.update(
                            {"state": conv.AuthorizationRequest["state"]})
                        if not ots.client.provider_info:
                            return self.err_response(session, req.request,
                                                     "No provider info")

                    req.rm_nonstandard_args(message_factory)

                    # Extra arguments outside the OIDC spec
                    try:
                        _extra = ots.config.CLIENT["extra"][req.request]
                    except KeyError:
                        pass
                    except Exception as err:
                        return self.err_response(session, "config_extra", err)
                    else:
                        try:
                            kwargs["request_args"].update(_extra)
                        except KeyError:
                            kwargs["request_args"] = _extra

                    req.call_setup()

                    try:
                        url, body, ht_args = req.construct_request(ots.client,
                                                                   **kwargs)
                    except PyoidcError as err:  # A OIDC specific error
                        return self.err_response(session, "construct_request",
                                                 err)

                    if req.request == "AuthorizationRequest":
                        session["response_type"] = kwargs["request_args"][
                            "response_type"]
                        logger.info("redirect.url: %s" % url)
                        logger.info("redirect.header: %s" % ht_args)
                        conv.timestamp.append((url, utc_time_sans_frac()))
                        resp = Redirect(str(url))
                        return resp(self.environ, self.start_response)
                    else:
                        _kwargs = {"http_args": ht_args}

                        if conv.AuthorizationRequest:
                            _kwargs["state"] = conv.AuthorizationRequest[
                                "state"]

                        try:
                            _method = kwargs["method"]
                        except KeyError:
                            _method = req.method
                        try:
                            _ctype = kwargs["ctype"]
                        except KeyError:
                            _ctype = resp_c.ctype

                        self.dump_log(session, session["testid"])

                        try:
                            response = request_and_return(
                                conv, url, trace, message_factory(
                                    resp_c.response), _method, body, _ctype,
                                **_kwargs)
                        except MissingErrorResponse:
                            self.log_fault(session, "Missing Error Response",
                                           "request_response",
                                           self.get_err_type(session))
                            conv.trace.info(END_TAG)
                            return self.fini(session, conv)

                        except PyoidcError as err:
                            return self.err_response(session,
                                                     "request_and_return", err)
                        except JWKESTException as err:
                            return self.err_response(session,
                                                     "request_and_return", err)
                        except ConnectionError:
                                self.log_fault(session, "Connection Error",
                                               "request",
                                               self.get_err_type(session))
                                conv.trace.info(END_TAG)
                                return self.fini(session, conv)

                        if response is None:  # bail out
                            self.log_fault(session, "Empty response",
                                           "request_response",
                                           self.get_err_type(session))
                            conv.trace.info(END_TAG)
                            return self.fini(session, conv)

                        trace.response(response)
                        logger.info(response.to_dict())

                        if expect_error:
                            session["expect_error"] = True
                            if isinstance(response, ErrorResponse):
                                if expect_error["stop"]:
                                    index = len(sequence_info["sequence"])
                                    session["index"] = index
                                    continue
                            else:
                                trace.error("Expected error, didn't get it")
                                return self.err_response(session,
                                                         "expected error", None)
                        else:
                            if resp_c.response == "RegistrationResponse":
                                if isinstance(response, RegistrationResponse):
                                    ots.client.store_registration_info(response)
                            elif resp_c.response == "AccessTokenResponse":
                                if "error" not in response:
                                    areq = conv.AuthorizationRequest.to_dict()
                                    try:
                                        del areq["acr_values"]
                                    except KeyError:
                                        pass

                try:
                    post_tests(conv, req_c, resp_c)
                except Exception as err:
                    return self.err_response(session, "post_test", err)

            index += 1
            _tid = session["testid"]
            self.dump_log(session, _tid)
            self.store_test_info(session)

        # wrap it up
        # Any after the fact tests ?
        try:
            if sequence_info["tests"]:
                conv.test_output.append(("After completing the test flow", ""))
                conv.test_sequence(sequence_info["tests"])
        except KeyError:
            pass
        except Exception as err:
            return self.err_response(session, "post_test", err)

        return self.fini(session, conv)