def parse_response(self, environ): try: self.response_spec = resp = self.cresp() except TypeError: self.response_spec = None return True self.info = None self.response_message = None self.response_type = resp.response resp_type = resp.ctype _info = "" if resp.where == "url": try: if environ: _info = environ["QUERY_STRING"] self.trace.reply("RESPONSE: %s" % _info) else: _info = self.last_response resp_type = "urlencoded" except KeyError: try: _check = getattr(self.creq, "interaction_check", None) except AttributeError: _check = None if _check: self.err_check("interaction-check") else: self.do_check("missing-redirect") else: self.do_check("check_content_type_header") if environ: _info = get_body(environ) self.trace.reply("RESPONSE: %s" % _info) else: _info = self.last_content if isinstance(resp.response, basestring): response = message_factory(resp.response) else: response = resp.response #self.response_type = response.__name__ try: _cli = self.client if _cli.provider_info: kwargs = {"opponent_id": _cli.provider_info["issuer"]} else: kwargs = {} _qresp = _cli.parse_response( response, _info, resp_type, _cli.state, keyjar=_cli.keyjar, client_id=_cli.client_id, scope="openid", **kwargs) if _qresp: self.trace.info("[%s]: %s" % (_qresp.type(), _qresp.to_dict())) if _qresp.extra(): self.trace.info("### extra claims: %s" % _qresp.extra()) self.response_message = _qresp self.protocol_response.append((_qresp, self.info)) else: self.response_message = None err = None _errtxt = "" except Exception, err: _errtxt = "%s" % err self.trace.error(_errtxt) self.exception = _errtxt
def run_sequence(sequence_info, session, conv, ots, environ, start_response, trace, index): while index < len(sequence_info["sequence"]): session["index"] = index try: req_c, resp_c = sequence_info["sequence"][index] except (ValueError, TypeError): # Not a tuple ret = none_request_response(sequence_info, index, session, conv, environ, start_response) if ret: return ret else: req = req_c(conv) try: if req.tests["pre"]: conv.test_output.append((req.request, "pre")) conv.test_sequence(req.tests["pre"]) except KeyError: pass except Exception as err: return err_response(environ, start_response, session, "pre-test", err) conv.request_spec = req if req_c == TEST_FLOWS.Discover: # Special since it's just a GET on a URL _r = req.discover( ots.client, issuer=ots.config.CLIENT["srv_discovery_url"]) conv.position, conv.last_response, conv.last_content = _r logging.debug("Provider info: %s" % conv.last_content._dict) verify_support(conv, ots, session["graph"]) else: LOGGER.info("request: %s" % req.request) if req.request == "AuthorizationRequest": # New state for each request kwargs = {"request_args": {"state": rndstr()}} elif req.request in [ "AccessTokenRequest", "UserInfoRequest", "RefreshAccessTokenRequest" ]: kwargs = {"state": conv.AuthorizationRequest["state"]} else: kwargs = {} # Extra arguments outside the OIDC spec try: _extra = ots.config.CLIENT["extra"][req.request] except KeyError: pass except Exception as err: return err_response(environ, start_response, session, "config_exta", 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 err_response(environ, start_response, session, "construct_request", err) if req.request == "AuthorizationRequest": session["response_type"] = req.request_args[ "response_type"] LOGGER.info("redirect.url: %s" % url) LOGGER.info("redirect.header: %s" % ht_args) resp = Redirect(str(url)) return resp(environ, start_response) else: _kwargs = {"http_args": ht_args} try: _kwargs["state"] = conv.AuthorizationRequest["state"] except AttributeError: pass try: response = request_and_return( conv, url, message_factory(resp_c.response), req.method, body, resp_c.ctype, **_kwargs) except PyoidcError as err: return err_response(environ, start_response, session, "request_and_return", err) trace.info(response.to_dict()) LOGGER.info(response.to_dict()) if resp_c.response == "RegistrationResponse" and \ isinstance(response, RegistrationResponse): ots.client.store_registration_info(response) else: # must be an ErrorResponse conv.test_output.append({ 'status': 4, "id": "*", 'message': 'Error response: %s' % (response.to_dict(), ) }) return opresult(environ, start_response, conv, session) try: post_tests(conv, req_c, resp_c) except Exception as err: return err_response(environ, start_response, session, "post_test", err) index += 1 _tid = session["testid"] session["test_info"][_tid] = { "trace": conv.trace, "test_output": conv.test_output } # wrap it up # Any after the fact tests ? try: if sequence_info["tests"]: conv.test_output.append(("After completing the test", "")) conv.test_sequence(sequence_info["tests"]) except KeyError: pass except Exception as err: return err_response(environ, start_response, session, "post_test", err) _tid = session["testid"] session["test_info"][_tid] = { "trace": conv.trace, "test_output": conv.test_output } session["node"].complete = True resp = Redirect("%sopresult#%s" % (CONF.BASE, _tid[3])) return resp(environ, start_response)
def parse_response(self, environ): try: self.response_spec = resp = self.cresp() except TypeError: self.response_spec = None return True self.info = None self.response_message = None self.response_type = resp.response resp_type = resp.ctype _info = "" if resp.where == "url": try: if environ: _info = environ["QUERY_STRING"] self.trace.reply("RESPONSE: %s" % _info) else: _info = self.last_response resp_type = "urlencoded" except KeyError: try: _check = getattr(self.creq, "interaction_check", None) except AttributeError: _check = None if _check: self.err_check("interaction-check") else: self.do_check("missing-redirect") else: self.do_check("check_content_type_header") if environ: _info = get_body(environ) self.trace.reply("RESPONSE: %s" % _info) else: _info = self.last_content if isinstance(resp.response, basestring): response = message_factory(resp.response) else: response = resp.response #self.response_type = response.__name__ try: _cli = self.client if _cli.provider_info: kwargs = {"opponent_id": _cli.provider_info["issuer"]} else: kwargs = {} _qresp = _cli.parse_response(response, _info, resp_type, _cli.state, keyjar=_cli.keyjar, client_id=_cli.client_id, scope="openid", **kwargs) if _qresp: self.trace.info("[%s]: %s" % (_qresp.type(), _qresp.to_dict())) if _qresp.extra(): self.trace.info("### extra claims: %s" % _qresp.extra()) self.response_message = _qresp self.protocol_response.append((_qresp, self.info)) else: self.response_message = None err = None _errtxt = "" except Exception, err: _errtxt = "%s" % err self.trace.error(_errtxt) self.exception = _errtxt
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)
if resp_c: # None in cases where no OIDC response is expected _ctype = resp_c.ctype # parse the response if path == "authz_post": query = parse_qs(get_post(environ)) info = query["fragment"][0] _ctype = "urlencoded" elif resp_c.where == "url": info = environ["QUERY_STRING"] _ctype = "urlencoded" else: # resp_c.where == "body" info = get_post(environ) LOGGER.info("Response: %s" % info) resp_cls = message_factory(resp_c.response) try: response = ots.client.parse_response( resp_cls, info, _ctype, conv.AuthorizationRequest["state"], keyjar=ots.client.keyjar) except ResponseError as err: return err_response(environ, start_response, session, "run_sequence", err) except Exception as err: return err_response(environ, start_response, session, "run_sequence", err) LOGGER.info("Parsed response: %s" % response.to_dict())
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 application(environ, start_response): LOGGER.info("Connection from: %s" % environ["REMOTE_ADDR"]) session = environ['beaker.session'] path = environ.get('PATH_INFO', '').lstrip('/') LOGGER.info("path: %s" % path) oprp = OPRP(**RP_ARGS) oprp.environ = environ oprp.start_response = start_response if path == "robots.txt": return oprp.static("static/robots.txt") elif path == "favicon.ico": return oprp.static("static/favicon.ico") elif path.startswith("static/"): return oprp.static(path) elif path.startswith("export/"): return oprp.static(path) if path == "": # list try: if oprp.session_init(session): return oprp.flow_list(session) else: try: resp = Redirect("%sopresult#%s" % (oprp.conf.BASE, session["testid"][0])) except KeyError: return oprp.flow_list(session) else: return resp(environ, start_response) except Exception as err: return oprp.err_response(session, "session_setup", err) elif path == "logs": return oprp.display_log("log", issuer="", profile="", testid="") elif path.startswith("log"): if path == "log" or path == "log/": _cc = oprp.conf.CLIENT try: _iss = _cc["srv_discovery_url"] except KeyError: _iss = _cc["provider_info"]["issuer"] parts = [quote_plus(_iss)] else: parts = [] while path != "log": head, tail = os.path.split(path) # tail = tail.replace(":", "%3A") # if tail.endswith("%2F"): # tail = tail[:-3] parts.insert(0, tail) path = head return oprp.display_log("log", *parts) elif path.startswith("tar"): path = path.replace(":", "%3A") return oprp.static(path) elif "flow_names" not in session: oprp.session_init(session) if path == "reset": oprp.reset_session(session) return oprp.flow_list(session) elif path == "pedit": try: return oprp.profile_edit(session) except Exception as err: return oprp.err_response(session, "pedit", err) elif path == "profile": info = parse_qs(get_post(environ)) try: cp = session["profile"].split(".") cp[0] = info["rtype"][0] crsu = [] for name, cs in list(CRYPTSUPPORT.items()): try: if info[name] == ["on"]: crsu.append(cs) except KeyError: pass if len(cp) == 3: if len(crsu) == 3: pass else: cp.append("".join(crsu)) else: # len >= 4 cp[3] = "".join(crsu) try: if info["extra"] == ['on']: if len(cp) == 3: cp.extend(["", "+"]) elif len(cp) == 4: cp.append("+") elif len(cp) == 5: cp[4] = "+" else: if len(cp) == 5: cp = cp[:-1] except KeyError: if len(cp) == 5: cp = cp[:-1] # reset all test flows RP_ARGS["test_profile"] = ".".join(cp) oprp.reset_session(session, ".".join(cp)) return oprp.flow_list(session) except Exception as err: return oprp.err_response(session, "profile", err) elif path.startswith("test_info"): p = path.split("/") try: return oprp.test_info(p[1], session) except KeyError: return oprp.not_found() elif path == "continue": try: sequence_info = session["seq_info"] except KeyError: # Cookie delete broke session query = parse_qs(environ["QUERY_STRING"]) path = query["path"][0] index = int(query["index"][0]) conv, sequence_info, ots, trace, index = oprp.session_setup( session, path, index) try: conv = RP_ARGS["cache"][query["ckey"][0]] except KeyError: pass else: ots.client = conv.client session["conv"] = conv except Exception as err: return oprp.err_response(session, "session_setup", err) else: index = session["index"] ots = session["ots"] conv = session["conv"] index += 1 try: return oprp.run_sequence(sequence_info, session, conv, ots, conv.trace, index) except Exception as err: return oprp.err_response(session, "run_sequence", err) elif path == "opresult": try: conv = session["conv"] except KeyError as err: homepage = "" return oprp.sorry_response(homepage, err) return oprp.opresult(conv, session) # expected path format: /<testid>[/<endpoint>] elif path in session["flow_names"]: LOGGER.info("<=<=<=<=< %s >=>=>=>=>" % path) conv, sequence_info, ots, trace, index = oprp.session_setup( session, path) session["node"].complete = False try: return oprp.run_sequence(sequence_info, session, conv, ots, trace, index) except Exception as err: return oprp.err_response(session, "run_sequence", err) elif path in ["authz_cb", "authz_post"]: try: sequence_info = session["seq_info"] index = session["index"] ots = session["ots"] conv = session["conv"] except KeyError as err: # Todo: find out which port I'm listening on return oprp.sorry_response(oprp.conf.BASE, err) (req_c, resp_c), _ = sequence_info["sequence"][index] try: response_mode = conv.AuthorizationRequest["response_mode"] except KeyError: response_mode = None if path == "authz_cb": if response_mode == "form_post": pass elif session["response_type"] and not \ session["response_type"] == ["code"]: # but what if it's all returned as a query ? try: qs = environ["QUERY_STRING"] except KeyError: pass else: session["conv"].trace.response("QUERY_STRING:%s" % qs) session["conv"].query_component = qs return oprp.opresult_fragment() if resp_c: # None in cases where no OIDC response is expected _ctype = resp_c.ctype # parse the response if response_mode == "form_post": info = parse_qs(get_post(environ)) _ctype = "dict" elif path == "authz_post": query = parse_qs(get_post(environ)) try: info = query["fragment"][0] except KeyError: return oprp.sorry_response(oprp.conf.BASE, "missing fragment ?!") _ctype = "urlencoded" elif resp_c.where == "url": info = environ["QUERY_STRING"] _ctype = "urlencoded" else: # resp_c.where == "body" info = get_post(environ) LOGGER.info("Response: %s" % info) conv.trace.reply(info) resp_cls = message_factory(resp_c.response) kwargs = { "algs": ots.client.sign_enc_algs("id_token"), "keyjar": ots.client.keyjar } if "issuer_mismatch" in ots.client.allow: kwargs["sender"] = ots.client.provider_info["issuer"] try: response = ots.client.parse_response( resp_cls, info, _ctype, conv.AuthorizationRequest["state"], **kwargs) except ResponseError as err: return oprp.err_response(session, "run_sequence", err) except Exception as err: return oprp.err_response(session, "run_sequence", err) LOGGER.info("Parsed response: %s" % response.to_dict()) conv.protocol_response.append((response, info)) conv.trace.response(response) try: post_tests(conv, req_c, resp_c) except Exception as err: return oprp.err_response(session, "post_test", err) index += 1 try: return oprp.run_sequence(sequence_info, session, conv, ots, conv.trace, index) except Exception as err: return oprp.err_response(session, "run_sequence", err) else: resp = BadRequest() return resp(environ, start_response)
def application(environ, start_response): LOGGER.info("Connection from: %s" % environ["REMOTE_ADDR"]) session = environ['beaker.session'] path = environ.get('PATH_INFO', '').lstrip('/') LOGGER.info("path: %s" % path) oprp = OPRP(**RP_ARGS) oprp.environ = environ oprp.start_response = start_response if path == "robots.txt": return oprp.static("static/robots.txt") elif path == "favicon.ico": return oprp.static("static/favicon.ico") elif path.startswith("static/"): return oprp.static(path) elif path.startswith("export/"): return oprp.static(path) if path == "": # list try: if oprp.session_init(session): return oprp.flow_list(session) else: try: resp = Redirect("%sopresult#%s" % ( oprp.conf.BASE, session["testid"][0])) except KeyError: return oprp.flow_list(session) else: return resp(environ, start_response) except Exception as err: return oprp.err_response(session, "session_setup", err) elif path == "logs": return oprp.display_log("log", issuer="", profile="", testid="") elif path.startswith("log"): if path == "log" or path == "log/": _cc = oprp.conf.CLIENT try: _iss = _cc["srv_discovery_url"] except KeyError: _iss = _cc["provider_info"]["issuer"] parts = [quote_plus(_iss)] else: parts = [] while path != "log": head, tail = os.path.split(path) # tail = tail.replace(":", "%3A") # if tail.endswith("%2F"): # tail = tail[:-3] parts.insert(0, tail) path = head return oprp.display_log("log", *parts) elif path.startswith("tar"): path = path.replace(":", "%3A") return oprp.static(path) elif "flow_names" not in session: oprp.session_init(session) if path == "reset": oprp.reset_session(session) return oprp.flow_list(session) elif path == "pedit": try: return oprp.profile_edit(session) except Exception as err: return oprp.err_response(session, "pedit", err) elif path == "profile": info = parse_qs(get_post(environ)) try: cp = session["profile"].split(".") cp[0] = info["rtype"][0] crsu = [] for name, cs in list(CRYPTSUPPORT.items()): try: if info[name] == ["on"]: crsu.append(cs) except KeyError: pass if len(cp) == 3: if len(crsu) == 3: pass else: cp.append("".join(crsu)) else: # len >= 4 cp[3] = "".join(crsu) try: if info["extra"] == ['on']: if len(cp) == 3: cp.extend(["", "+"]) elif len(cp) == 4: cp.append("+") elif len(cp) == 5: cp[4] = "+" else: if len(cp) == 5: cp = cp[:-1] except KeyError: if len(cp) == 5: cp = cp[:-1] # reset all test flows oprp.reset_session(session, ".".join(cp)) return oprp.flow_list(session) except Exception as err: return oprp.err_response(session, "profile", err) elif path.startswith("test_info"): p = path.split("/") try: return oprp.test_info(p[1], session) except KeyError: return oprp.not_found() elif path == "continue": try: sequence_info = session["seq_info"] except KeyError: # Cookie delete broke session query = parse_qs(environ["QUERY_STRING"]) path = query["path"][0] index = int(query["index"][0]) conv, sequence_info, ots, trace, index = oprp.session_setup( session, path, index) try: conv = RP_ARGS["cache"][query["ckey"][0]] except KeyError: pass else: ots.client = conv.client session["conv"] = conv except Exception as err: return oprp.err_response(session, "session_setup", err) else: index = session["index"] ots = session["ots"] conv = session["conv"] index += 1 try: return oprp.run_sequence(sequence_info, session, conv, ots, conv.trace, index) except Exception as err: return oprp.err_response(session, "run_sequence", err) elif path == "opresult": try: conv = session["conv"] except KeyError as err: homepage = "" return oprp.sorry_response(homepage, err) return oprp.opresult(conv, session) # expected path format: /<testid>[/<endpoint>] elif path in session["flow_names"]: LOGGER.info("<=<=<=<=< %s >=>=>=>=>" % path) conv, sequence_info, ots, trace, index = oprp.session_setup(session, path) session["node"].complete = False try: return oprp.run_sequence(sequence_info, session, conv, ots, trace, index) except Exception as err: return oprp.err_response(session, "run_sequence", err) elif path in ["authz_cb", "authz_post"]: try: sequence_info = session["seq_info"] index = session["index"] ots = session["ots"] conv = session["conv"] except KeyError as err: # Todo: find out which port I'm listening on return oprp.sorry_response(oprp.conf.BASE, err) (req_c, resp_c), _ = sequence_info["sequence"][index] try: response_mode = conv.AuthorizationRequest["response_mode"] except KeyError: response_mode = None if path == "authz_cb": if response_mode == "form_post": pass elif session["response_type"] and not \ session["response_type"] == ["code"]: # but what if it's all returned as a query ? try: qs = environ["QUERY_STRING"] except KeyError: pass else: session["conv"].trace.response("QUERY_STRING:%s" % qs) session["conv"].query_component = qs return oprp.opresult_fragment() if resp_c: # None in cases where no OIDC response is expected _ctype = resp_c.ctype # parse the response if response_mode == "form_post": info = parse_qs(get_post(environ)) _ctype = "dict" elif path == "authz_post": query = parse_qs(get_post(environ)) try: info = query["fragment"][0] except KeyError: return oprp.sorry_response(oprp.conf.BASE, "missing fragment ?!") _ctype = "urlencoded" elif resp_c.where == "url": info = environ["QUERY_STRING"] _ctype = "urlencoded" else: # resp_c.where == "body" info = get_post(environ) LOGGER.info("Response: %s" % info) conv.trace.reply(info) resp_cls = message_factory(resp_c.response) algs = ots.client.sign_enc_algs("id_token") try: response = ots.client.parse_response( resp_cls, info, _ctype, conv.AuthorizationRequest["state"], keyjar=ots.client.keyjar, algs=algs) except ResponseError as err: return oprp.err_response(session, "run_sequence", err) except Exception as err: return oprp.err_response(session, "run_sequence", err) LOGGER.info("Parsed response: %s" % response.to_dict()) conv.protocol_response.append((response, info)) conv.trace.response(response) try: post_tests(conv, req_c, resp_c) except Exception as err: return oprp.err_response(session, "post_test", err) index += 1 try: return oprp.run_sequence(sequence_info, session, conv, ots, conv.trace, index) except Exception as err: return oprp.err_response(session, "run_sequence", err) else: resp = BadRequest() return resp(environ, start_response)
def run_sequence(sequence_info, session, conv, ots, environ, start_response, trace, index): while index < len(sequence_info["sequence"]): session["index"] = index try: req_c, resp_c = sequence_info["sequence"][index] except (ValueError, TypeError): # Not a tuple ret = none_request_response(sequence_info, index, session, conv, environ, start_response) if ret: return ret else: req = req_c(conv) try: if req.tests["pre"]: conv.test_output.append((req.request, "pre")) conv.test_sequence(req.tests["pre"]) except KeyError: pass except Exception as err: return err_response(environ, start_response, session, "pre-test", err) conv.request_spec = req if req_c == TEST_FLOWS.Discover: # Special since it's just a GET on a URL _r = req.discover( ots.client, issuer=ots.config.CLIENT["srv_discovery_url"]) conv.position, conv.last_response, conv.last_content = _r logging.debug("Provider info: %s" % conv.last_content._dict) verify_support(conv, ots, session["graph"]) else: LOGGER.info("request: %s" % req.request) if req.request == "AuthorizationRequest": # New state for each request kwargs = {"request_args": {"state": rndstr()}} elif req.request in ["AccessTokenRequest", "UserInfoRequest", "RefreshAccessTokenRequest"]: kwargs = {"state": conv.AuthorizationRequest["state"]} else: kwargs = {} # Extra arguments outside the OIDC spec try: _extra = ots.config.CLIENT["extra"][req.request] except KeyError: pass except Exception as err: return err_response(environ, start_response, session, "config_exta", 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 err_response(environ, start_response, session, "construct_request", err) if req.request == "AuthorizationRequest": session["response_type"] = req.request_args["response_type"] LOGGER.info("redirect.url: %s" % url) LOGGER.info("redirect.header: %s" % ht_args) resp = Redirect(str(url)) return resp(environ, start_response) else: _kwargs = {"http_args": ht_args} try: _kwargs["state"] = conv.AuthorizationRequest["state"] except AttributeError: pass try: response = request_and_return( conv, url, message_factory(resp_c.response), req.method, body, resp_c.ctype, **_kwargs) except PyoidcError as err: return err_response(environ, start_response, session, "request_and_return", err) trace.info(response.to_dict()) LOGGER.info(response.to_dict()) if resp_c.response == "RegistrationResponse" and \ isinstance(response, RegistrationResponse): ots.client.store_registration_info(response) else: # must be an ErrorResponse conv.test_output.append( {'status': 4, "id": "*", 'message': 'Error response: %s' % (response.to_dict(),)}) return opresult(environ, start_response, conv, session) try: post_tests(conv, req_c, resp_c) except Exception as err: return err_response(environ, start_response, session, "post_test", err) index += 1 _tid = session["testid"] session["test_info"][_tid] = {"trace": conv.trace, "test_output": conv.test_output} # wrap it up # Any after the fact tests ? try: if sequence_info["tests"]: conv.test_output.append(("After completing the test", "")) conv.test_sequence(sequence_info["tests"]) except KeyError: pass except Exception as err: return err_response(environ, start_response, session, "post_test", err) _tid = session["testid"] session["test_info"][_tid] = {"trace": conv.trace, "test_output": conv.test_output} session["node"].complete = True resp = Redirect("%sopresult#%s" % (CONF.BASE, _tid[3])) return resp(environ, start_response)
if resp_c: # None in cases where no OIDC response is expected _ctype = resp_c.ctype # parse the response if path == "authz_post": query = parse_qs(get_post(environ)) info = query["fragment"][0] _ctype = "urlencoded" elif resp_c.where == "url": info = environ["QUERY_STRING"] _ctype = "urlencoded" else: # resp_c.where == "body" info = get_post(environ) LOGGER.info("Response: %s" % info) resp_cls = message_factory(resp_c.response) try: response = ots.client.parse_response( resp_cls, info, _ctype, conv.AuthorizationRequest["state"], keyjar=ots.client.keyjar) except ResponseError as err: return err_response(environ, start_response, session, "run_sequence", err) except Exception as err: return err_response(environ, start_response, session, "run_sequence", err) LOGGER.info("Parsed response: %s" % response.to_dict()) conv.protocol_response.append((response, info))