def check_config(oper, args): """ Context: VerifyConfiguration Action: Example: "check_config": { "login_hint": null } :param args: Dictionary with parameters and values that MUST be in the tool configuration """ _cnf = oper.conv.tool_config for key, val in args.items(): if key in _cnf: if val and val != _cnf[key]: _msg = "{}={} not OK, should have been {}".format( key, val, _cnf[key]) oper.conv.events.store( EV_CONDITION, State("Check support", status=ERROR, message=_msg)) oper.unsupported = _msg else: _msg = "No {} in the configuration".format(key) oper.conv.events.store( EV_CONDITION, State("Check support", status=ERROR, message=_msg)) oper.unsupported = _msg
def webfinger(environ, events): query = parse_qs(environ["QUERY_STRING"]) _op = environ["oic.op"] try: if query["rel"] != [OIC_ISSUER]: events.store( EV_CONDITION, State('webfinger_parameters', ERROR, message='parameter rel wrong value: {}'.format( query['rel']))) return BadRequest('Parameter value error') else: resource = query["resource"][0] except KeyError as err: events.store( EV_CONDITION, State('webfinger_parameters', ERROR, message='parameter {} missing'.format(err))) resp = BadRequest("Missing parameter in request") else: wf = WebFinger() resp = Response(wf.response(subject=resource, base=_op.baseurl)) return resp
def session_change(self, **kwargs): try: _state = kwargs['state'] except KeyError: pass else: logger.debug('Session state: {}'.format(kwargs)) self.tester.conv.events.store( 'SessionState', 'Session check returned: {}'.format(_state)) if _state == 'changed': self.tester.conv.events.store(EV_CONDITION, State('Done', status=OK)) self.tester.store_result() self.opresult() else: # display after_logout.html again self.session_checks['changed'] += 1 logger.debug('{} session check'.format(self.session_checks[ 'changed'])) self.tester.conv.events.store( 'SessionState', 'Session check {} returned: {}'.format( self.session_checks['unchanged'], _state)) if self.session_checks['changed'] >= self.max_checks: self.tester.conv.events.store(EV_FAULT, 'Session state not changed') return self.main_page() else: _msg = self.tester.inut.pre_html['after_logout.html'] _csi = self.tester.conv.entity.provider_info[ 'check_session_iframe'] _mod_msg = _msg.replace("{check_session_iframe}", _csi) return as_bytes(_mod_msg)
def log_fault(self, session, err, where, err_type=0): if err_type == 0: err_type = self.get_err_type(session) if "conv" in session: if err: session["conv"].events.store(EV_CONDITION, State("Fault", status=ERROR, name=err_type, message="{}".format(err))) else: session["conv"].events.store( EV_CONDITION, State( "Fault", status=ERROR, name=err_type, message="Error in %s" % where))
def check_support(oper, args): """ Context: AsyncAuthn Action: Verify that the needed support is supported by the OP Args: A dictionary of dictionaries. {level: {item: value}} Example: "check_support": { WARNING: {"scopes_supported": ["phone"]} } "check_support": { ERROR: {"id_token_signing_alg_values_supported": null} } """ # args = { level : kwargs } for level, kwargs in list(args.items()): for key, val in list(kwargs.items()): # type of value: boolean, int, string, list, ... typ = oper.conv.entity.provider_info.__class__.c_param[key][0] try: pinfo = oper.conv.entity.provider_info[key] except KeyError: pass else: missing = [] if isinstance(val, list): for v in val: if isinstance(typ, list) and issubclass( typ[0], (six.string_types, basestring)): if v not in pinfo: missing.append(v) elif issubclass( typ, (bool, int, six.string_types, basestring)): if v != pinfo: missing.append(v) else: if isinstance(typ, list) and issubclass( typ[0], (six.string_types, basestring)): if val not in pinfo: missing = val elif issubclass(typ, (bool, int, six.string_types, basestring)): if val != pinfo: missing = val if missing: oper.conv.events.store( EV_CONDITION, State(status=STATUSCODE_TRANSL[level], test_id="Check support", message="No support for: {}={}".format( key, missing))) if level == 'ERROR': oper.fail = True
def check_endpoint(oper, args): try: _ = oper.conv.entity.provider_info[args] except KeyError: oper.conv.events.store( EV_CONDITION, State(test_id="check_endpoint", status=ERROR, message="{} not in provider configuration".format(args))) oper.skip = True
def do_next(self, req, filename, path='', **kwargs): sh = self.sh self.conv = sh['conv'] cls, funcs = self.get_cls_and_func(self.conv.index + 1) if cls.endpoint != path: if path == 'authorization': # Jumping the gun here areq = AuthorizationRequest().from_urlencoded(req) # send an error back to the redirect_uri msg = AuthorizationErrorResponse(error='access_denied', state=areq['state']) _entity = self.conv.entity redirect_uri = _entity.get_redirect_uri(areq) _req_loc = msg.request(redirect_uri) resp = _entity.server.http_request(_req_loc, 'GET') ret = Response('Client need to reregister') return ret self.handle_request(req, path=path) self.store_result() self.conv.index += 1 try: resp = self.run_item(self.conv.test_id, index=self.conv.index, **kwargs) except Exception as err: raise if isinstance(resp, Response): self.store_result() return resp _done = False for _cond in self.conv.events.get_data(EV_CONDITION): if _cond.test_id == 'Done' and _cond.status == OK: _done = True break if not _done: self.conv.events.store(EV_CONDITION, State('Done', OK), sender='do_next') if 'assert' in self.conv.flow: _ver = Verify(self.chk_factory, self.conv) _ver.test_sequence(self.conv.flow["assert"]) self.store_result() return self.inut.flow_list()
def post_op(self, oper, res, test_id): """ should be done as late as possible, so all processing has been :param oper: :return: """ try: oper.post_tests() except ConditionError: pass self.conv.events.store(EV_CONDITION, State('Done', OK)) self.store_result(res)
def check_support(oper, args): # args = { level : kwargs } for level, kwargs in list(args.items()): for key, val in list(kwargs.items()): typ = oper.conv.entity.provider_info.__class__.c_param[key][0] try: pinfo = oper.conv.entity.provider_info[key] except KeyError: pass else: missing = [] if isinstance(val, list): for v in val: if typ == bool or typ == basestring or typ == int: if v != pinfo: missing.append(v) elif typ == [basestring]: if v not in pinfo: missing.append(v) else: if typ == bool or typ == basestring or typ == int: if val != pinfo: missing = val elif typ == [basestring]: if val not in pinfo: missing = val if missing: oper.conv.events.store( EV_CONDITION, State(status=STATUSCODE_TRANSL[level], test_id="Check support", message="No support for: {}={}".format(key, missing))) if level == 'ERROR': oper.fail = True
def run_flow(self, test_id, index=0, profiles=None, **kwargs): logger.info("<=<=<=<=< %s >=>=>=>=>" % test_id) _ss = self.sh _ss.test_flows.complete[test_id] = False self.conv.test_id = test_id res = Result(self.sh, self.kwargs['profile_handler']) if index >= len(self.conv.sequence): return CRITICAL _oper = None for item in self.conv.sequence[index:]: if isinstance(item, tuple): cls, funcs = item else: cls = item funcs = {} logger.info("<--<-- {} --- {} -->-->".format(index, cls)) self.conv.events.store('operation', cls, sender='run_flow') try: _oper = cls(conv=self.conv, inut=self.inut, sh=self.sh, profile=self.profile, test_id=test_id, funcs=funcs, check_factory=self.check_factory, cache=self.cache) # self.conv.operation = _oper if profiles: profile_map = profiles.PROFILEMAP else: profile_map = None _oper.setup(profile_map) resp = _oper() except ConditionError: self.store_result(res) return ERROR except Exception as err: exception_trace('run_flow', err) self.conv.events.store(EV_FAULT, err) #self.sh["index"] = index self.store_result(res) return CRITICAL else: if isinstance(resp, self.response_cls): return resp if resp: if self.com_handler: resp = self.com_handler(resp) resp = _oper.handle_response(self.get_response(resp)) if resp: return self.inut.respond(resp) # should be done as late as possible, so all processing has been # done try: _oper.post_tests() except ConditionError: tinfo = self.store_result(res) return tinfo['state'] index += 1 _ss['index'] = self.conv.index = index try: if self.conv.flow["assert"]: _ver = Verify(self.check_factory, self.conv) _ver.test_sequence(self.conv.flow["assert"]) except KeyError: pass except Exception as err: logger.error(err) raise if isinstance(_oper, Done): self.conv.events.store(EV_CONDITION, State('Done', OK), sender='run_flow') tinfo = self.store_result(res) return tinfo['state']
def parse_response(self, path, inut, message_factory, response=None): _ctype = self.response_type _conv = self.conv if self.csi is None: url, body, ht_args, csi = _conv.entity.request_info( self.request, method=self.method, request_args=self.req_args, **self.op_args) self.csi = csi try: response_mode = self.csi["response_mode"] except KeyError: response_mode = None if self.request_cls == "AuthorizationRequest": try: _rt = self.csi["response_type"] except KeyError: response_where = "" else: if _rt == ["code"]: response_where = "url" elif _rt == [""]: response_where = "" else: response_where = "fragment" else: response_where = self.response_where # parse the response if response_mode == "form_post": info = response _ctype = "dict" elif response_where in ["url", ""]: info = response _ctype = "dict" elif response_where == "fragment": try: info = response["fragment"] except KeyError: return inut.sorry_response(inut.base_url, "missing fragment ?!") else: # resp_c.where == "body" info = response logger.info("Response: %s" % info) ev_index = _conv.events.store(EV_RESPONSE, info, sender=self.__class__.__name__) resp_cls = message_factory(self.response_cls) # algs = _conv.entity.sign_enc_algs("id_token") try: response = _conv.entity.parse_response( resp_cls, info, _ctype, self.csi["state"], keyjar=_conv.entity.keyjar # , algs=algs ) except ResponseError as err: _conv.events.store( EV_FAULT, State(_conv.test_id, ERROR, message=err, context='parse_response')) return inut.err_response("run_sequence", err) except (VerificationError, MissingRequiredAttribute) as err: self.conv.events.store(EV_FAULT, err) inut.err_response("run_sequence", err) return None except Exception as err: return inut.err_response("run_sequence", err) logger.info("Parsed response: %s" % response.to_dict()) _conv.events.store(EV_PROTOCOL_RESPONSE, response, ref=ev_index, sender=self.__class__.__name__) if "id_token" in response: try: self.conv.entity.smid2sid[response['id_token'] ['sid']] = response['state'] except KeyError: pass display_jwx_headers(response, _conv) if self.expect_error: self.expected_error_response(response) else: if isinstance(response, ErrorResponse): raise Break("Unexpected error response")
def run_flow(self, test_id, index=0, profiles=None, conf=None): logger.info("<=<=<=<=< %s >=>=>=>=>" % test_id) self.flows.complete[test_id] = False self.conv.test_id = test_id self.conv.conf = conf if index >= len(self.conv.sequence): return CRITICAL res = Result(self.sh, self.kwargs['profile_handler']) _oper = None for item in self.conv.sequence[index:]: self.sh["index"] = index if isinstance(item, tuple): cls, funcs = item else: cls = item funcs = {} _name = cls.__name__ _line = "<--<-- {} --- {} -->-->".format(index, _name) logger.info(_line) self.conv.events.store(EV_OPERATION, _line) try: _oper = cls(conv=self.conv, inut=self.inut, sh=self.sh, profile=self.sh.profile, test_id=test_id, conf=conf, funcs=funcs, check_factory=self.check_factory, cache=self.cache, tool_conf=self.kwargs['tool_conf']) self.conv.operation = _oper _oper.setup(self.profiles.PROFILEMAP) if _oper.fail: break resp = _oper() except Break: break except cherrypy.HTTPError: raise except Exception as err: self.conv.events.store( EV_CONDITION, State(test_id=test_id, status=ERROR, message=err, context=cls.__name__)) _trace = exception_trace(cls.__name__, err, logger) self.sh["index"] = index self.store_result(res) return {'exception_trace': _trace} else: rsp = self.handle_response(resp, index) if rsp: self.store_result(res) return self.inut.respond(rsp) index += 1 if index == len(self.conv.sequence): break if isinstance(_oper, Done): try: if self.conv.flow["assert"]: _ver = Verify(self.check_factory, self.conv) _ver.test_sequence(self.conv.flow["assert"]) except (KeyError, Break): self.conv.events.store(EV_CONDITION, State('Done', status=OK)) except ConditionError: pass except Exception as err: raise else: self.conv.events.store(EV_CONDITION, State('Done', status=OK)) tinfo = self.store_result(res) return tinfo['state']