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)
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)
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)