def run_sequence(self, sequence_info, session, conv, ots, trace, index): while index < len(sequence_info["sequence"]): 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 ret: return ret else: try: kwargs = setup(_kwa, conv) except NotSupported: return self.opresult(conv, session) except Exception as err: return self.err_response(session, "function()", err) 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 self.err_response(session, "pre-test", err) conv.request_spec = req conv.trace.info("------------ %s ------------" % req_c.request) if req_c in [OIDCDiscover, UMADiscover]: # 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 if conv.last_response.status >= 400: return self.err_response(session, "discover", conv.last_response.text) resp_c.post_process(conv, _r[2], kwargs) 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: 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: url = req.discover(**kwargs) 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(MODULE2FACTORY) # 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_exta", err) else: try: kwargs["request_args"].update(_extra) except KeyError: kwargs["request_args"] = _extra req.call_setup() req.request_txt = req.request if req.request: try: req.request = MODULE2FACTORY[req.module]( req.request) except AttributeError: pass except KeyError: try: req.request = MODULE2FACTORY['oic.oic.message']( req.request) except AttributeError: pass if isinstance(req, (self.test_class.ReadResourceSet, self.test_class.DeleteResourceSet, self.test_class.UpdateResourceSet)): req.kw_args["endpoint"] += "/" + kwargs["rsid"] 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_txt == "AuthorizationRequest": session["response_type"] = kwargs["request_args"][ "response_type"] LOGGER.info("redirect.url: %s" % url) LOGGER.info("redirect.header: %s" % ht_args) 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: try: _method = kwargs["method"] except KeyError: _method = req.method try: _ctype = kwargs["ctype"] except KeyError: if resp_c: _ctype = resp_c.ctype else: _ctype = "" response = None if resp_c: if resp_c.module: _mod = resp_c.module else: _mod = "oic.oic.message" try: _msg_factory = MODULE2FACTORY[_mod] except AttributeError: pass else: try: _resp = _msg_factory(resp_c.response) except Exception as err: pass else: response = request_and_return( conv, url, trace, _resp, _method, body, _ctype, **_kwargs) if response is None: response = ots.client.get_info(url, trace, _method, req, body) 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) if resp_c and response is None: # bail out return self.err_response(session, "request_and_return", None) trace.response(response) try: LOGGER.info(response.to_dict()) except AttributeError: # Not a Message instance LOGGER.info(response) try: _ = resp_c.response except AttributeError: pass else: if response: resp_c.post_process(conv, response, kwargs) 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) 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 flow", "")) conv.test_sequence(sequence_info["tests"]) except KeyError: pass except Exception as err: return self.err_response(session, "post_test", err) _tid = session["testid"] self.dump_log(session, _tid) session["test_info"][_tid] = {"trace": conv.trace, "test_output": conv.test_output} session["node"].complete = True inst, grp, spec = _tid.split("-", 2) resp = Redirect("%sopresult#%s" % (CONF.BASE, grp)) return resp(self.environ, self.start_response)
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) if __name__ == '__main__':
def run_sequence(self, sequence_info, session, conv, ots, trace, index): while index < len(sequence_info["sequence"]): 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 ret: return ret else: try: kwargs = setup(_kwa, conv) except NotSupported: return self.opresult(conv, session) except Exception as err: return self.err_response(session, "function()", err) 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 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 _r = req.discover( ots.client, issuer=ots.config.CLIENT["srv_discovery_url"]) 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: 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: url = req.discover(**kwargs) 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(), "nonce": rndstr()}) if "acr_values" not in kwargs["request_args"]: kwargs["request_args"][ "acr_values"] = ots.config.CLIENT[ "behaviour"]["default_acr_values"] try: kwargs["request_args"] = run_func( kwargs["filter"], conv, kwargs["request_args"]) except KeyError: pass 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(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() req.request_txt = req.request if req.request: try: req.request = factory(req.request) except AttributeError: pass if req.request_txt == "ResourceSetDescription": req.kw_args["endpoint"] += "/" + kwargs["rsid"] 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_txt == "AuthorizationRequest": session["response_type"] = kwargs["request_args"][ "response_type"] LOGGER.info("redirect.url: %s" % url) LOGGER.info("redirect.header: %s" % ht_args) 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: try: _method = kwargs["method"] except KeyError: _method = req.method try: _ctype = kwargs["ctype"] except KeyError: _ctype = resp_c.ctype response = request_and_return( conv, url, trace, factory(resp_c.response), _method, body, _ctype, **_kwargs) 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) if response is None: # bail out return self.err_response(session, "request_and_return", None) trace.response(response) LOGGER.info(response.to_dict()) if resp_c.response in ["ClientInfoResponse", "RegistrationResponse"]: if isinstance(response, RegistrationResponse): ots.client.oidc_registration_info = response ots.client.store_registration_info(response) elif isinstance(response, ClientInfoResponse): ots.client.uma_registration_info = response ots.client.store_registration_info(response) 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) 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 flow", "")) conv.test_sequence(sequence_info["tests"]) except KeyError: pass except Exception as err: return self.err_response(session, "post_test", err) _tid = session["testid"] self.dump_log(session, _tid) 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(self.environ, self.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 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)