def __call__(self, sid='', ttype='', **kwargs): """ Return a token. :param ttype: Type of token :param prev: Previous token, if there is one to go from :param sid: Session id :return: """ if not ttype and self.type: ttype = self.type else: ttype = 'A' if self.lifetime >= 0: exp = str(time_sans_frac() + self.lifetime) else: exp = '-1' # Live for ever tmp = '' rnd = '' while rnd == tmp: # Don't use the same random value again rnd = rndstr(32) # Ultimate length multiple of 16 return base64.b64encode( self.crypt.encrypt(lv_pack(rnd, ttype, sid, exp).encode())).decode("utf-8")
def authz_part2(self, user, authn_event, request, **kwargs): """ After the authentication this is where you should end up :param user: :param request: The Authorization Request :param sid: Session key :param kwargs: possible other parameters :return: A redirect to the redirect_uri of the client """ sid = setup_session( self.endpoint_context, request, user, authn_event=authn_event ) try: resp_info = self.post_authentication(user, request, sid, **kwargs) except Exception as err: return self.error_response({}, "server_error", err) if "check_session_iframe" in self.endpoint_context.provider_info: ec = self.endpoint_context salt = rndstr() if ec.sdb.is_session_revoked(sid): pass else: authn_event = ec.sdb.get_authentication_event( sid ) # use the last session _state = json.dumps({"authn_time": authn_event["authn_time"]}) session_cookie = ec.cookie_dealer.create_cookie( json.dumps(_state), typ="session", cookie_name=ec.cookie_name["session_management"], ) opbs = session_cookie[ec.cookie_name["session_management"]] _session_state = compute_session_state( opbs.value, salt, request["client_id"], resp_info["return_uri"] ) if "cookie" in resp_info: if isinstance(resp_info["cookie"], list): resp_info["cookie"].append(session_cookie) else: append_cookie(resp_info["cookie"], session_cookie) else: resp_info["cookie"] = session_cookie resp_info["response_args"]["session_state"] = _session_state # Mix-Up mitigation resp_info["response_args"]["iss"] = self.endpoint_context.issuer resp_info["response_args"]["client_id"] = request["client_id"] return resp_info
def add_registration_api(self, cinfo, client_id, context): _rat = rndstr(32) cinfo["registration_access_token"] = _rat cinfo["registration_client_uri"] = "{}?client_id={}".format( self.endpoint_context.endpoint["registration_api"].full_path, client_id ) context.registration_access_token[_rat] = client_id
def assertion_jwt(cli, keys, audience, algorithm, lifetime=600): _now = utc_time_sans_frac() at = AuthnToken(iss=cli.client_id, sub=cli.client_id, aud=audience, jti=rndstr(32), exp=_now + lifetime, iat=_now) return at.to_jwt(key=keys, algorithm=algorithm)
def key(self, user="", areq=None): """ Return a key (the session id) :param user: User id :param areq: The authorization request :return: An ID """ csum = hashlib.new('sha224') csum.update(rndstr(32).encode('utf-8')) return csum.hexdigest() # 56 bytes long, 224 bits
def create_sdb(self): _sso_db = SSODb() passwd = rndstr(24) _th_args = { "code": { "lifetime": 600, "password": passwd }, "token": { "lifetime": 3600, "password": passwd }, "refresh": { "lifetime": 86400, "password": passwd }, } _token_handler = token_handler.factory(None, **_th_args) userinfo = UserInfo(db_file=full_path("users.json")) self.sdb = SessionDB(InMemoryDataBase(), _token_handler, _sso_db, userinfo)
def key(self, **kwargs): """ Return a key (the session id) """ return rndstr(32)
def client_registration_setup(self, request, new_id=True, set_secret=True): try: request.verify() except MessageException as err: if "type" not in request: return ResponseMessage(error="invalid_type", error_description="%s" % err) else: return ResponseMessage(error="invalid_configuration_parameter", error_description="%s" % err) request.rm_blanks() try: self.match_client_request(request) except CapabilitiesMisMatch as err: return ResponseMessage( error="invalid_request", error_description="Don't support proposed %s" % err) _context = self.endpoint_context if new_id: # create new id och secret client_id = rndstr(12) while client_id in _context.cdb: client_id = rndstr(12) else: try: client_id = request['client_id'] except KeyError: raise ValueError('Missing client_id') _rat = rndstr(32) _cinfo = { "client_id": client_id, "registration_access_token": _rat, "registration_client_uri": "%s?client_id=%s" % (self.endpoint_path, client_id), "client_salt": rndstr(8) } if new_id: _cinfo["client_id_issued_at"] = utc_time_sans_frac() if set_secret: client_secret = secret(_context.seed, client_id) _cinfo.update({ "client_secret": client_secret, "client_secret_expires_at": client_secret_expiration_time() }) else: client_secret = '' _context.cdb[client_id] = _cinfo _context.cdb[_rat] = client_id _cinfo = self.do_client_registration( request, client_id, ignore=["redirect_uris", "policy_uri", "logo_uri", "tos_uri"]) if isinstance(_cinfo, ResponseMessage): return _cinfo args = dict([(k, v) for k, v in _cinfo.items() if k in RegistrationResponse.c_param]) self.comb_uri(args) response = RegistrationResponse(**args) # Add the client_secret as a symmetric key to the key jar if client_secret: _context.keyjar.add_symmetric(client_id, str(client_secret)) _context.cdb[client_id] = _cinfo try: _context.cdb.sync() except AttributeError: # Not all databases can be sync'ed pass logger.info("registration_response: %s" % sanitize(response.to_dict())) return response
def __init__( self, conf, keyjar=None, client_db=None, session_db=None, cwd="", cookie_dealer=None, httpc=None, cookie_name=None, jwks_uri_path=None, ): self.conf = conf self.keyjar = keyjar or KeyJar() self.cwd = cwd # client database self.cdb = client_db or {} try: self.seed = bytes(conf["seed"], "utf-8") except KeyError: self.seed = bytes(rndstr(16), "utf-8") # Default values, to be changed below depending on configuration self.endpoint = {} self.issuer = "" self.httpc = httpc or requests self.verify_ssl = True self.jwks_uri = None self.sso_ttl = 14400 # 4h self.symkey = rndstr(24) self.id_token_schema = IdToken self.endpoint_to_authn_method = {} self.cookie_dealer = cookie_dealer self.login_hint_lookup = None if cookie_name: self.cookie_name = cookie_name elif "cookie_name" in conf: self.cookie_name = conf["cookie_name"] else: self.cookie_name = { "session": "oidcop", "register": "oidc_op_rp", "session_management": "sman", } for param in [ "verify_ssl", "issuer", "sso_ttl", "symkey", "client_authn", "id_token_schema", ]: try: setattr(self, param, conf[param]) except KeyError: pass try: self.template_handler = conf["template_handler"] except KeyError: try: loader = conf["template_loader"] except KeyError: template_dir = conf["template_dir"] loader = Environment(loader=FileSystemLoader(template_dir), autoescape=True) self.template_handler = Jinja2TemplateHandler(loader) self.setup = {} if not jwks_uri_path: try: jwks_uri_path = conf["jwks"]["uri_path"] except KeyError: pass try: if self.issuer.endswith("/"): self.jwks_uri = "{}{}".format(self.issuer, jwks_uri_path) else: self.jwks_uri = "{}/{}".format(self.issuer, jwks_uri_path) except KeyError: self.jwks_uri = "" if self.keyjar is None or self.keyjar.owners() == []: args = {k: v for k, v in conf["jwks"].items() if k != "uri_path"} self.keyjar = init_key_jar(**args) try: _conf = conf["cookie_dealer"] except KeyError: pass else: if self.cookie_dealer: # already defined raise ValueError("Cookie Dealer already defined") self.cookie_dealer = init_service(_conf) try: _conf = conf["sub_func"] except KeyError: sub_func = None else: sub_func = {} for key, args in _conf.items(): if "class" in args: sub_func[key] = init_service(args) elif "function" in args: if isinstance(args["function"], str): sub_func[key] = util.importer(args["function"]) else: sub_func[key] = args["function"] if session_db: self.sdb = session_db else: try: _th_args = conf["token_handler_args"] except KeyError: # create 3 keys keydef = [ { "type": "oct", "bytes": "24", "use": ["enc"], "kid": "code" }, { "type": "oct", "bytes": "24", "use": ["enc"], "kid": "token" }, { "type": "oct", "bytes": "24", "use": ["enc"], "kid": "refresh" }, ] jwks_def = { "private_path": "private/token_jwks.json", "key_defs": keydef, "read_only": False, } _th_args = {"jwks_def": jwks_def} for typ, tid in [("code", 600), ("token", 3600), ("refresh", 86400)]: _th_args[typ] = {"lifetime": tid} self.sdb = create_session_db(self, _th_args, db=None, sso_db=SSODb(), sub_func=sub_func) self.endpoint = build_endpoints( conf["endpoint"], endpoint_context=self, client_authn_method=CLIENT_AUTHN_METHOD, issuer=conf["issuer"], ) try: _cap = conf["capabilities"] except KeyError: _cap = {} for endpoint, endpoint_instance in self.endpoint.items(): if endpoint_instance.provider_info: _cap.update(endpoint_instance.provider_info) if endpoint in ["webfinger", "provider_info"]: continue _cap[endpoint_instance.endpoint_name] = "{}".format( endpoint_instance.endpoint_path) try: authz_spec = conf["authz"] except KeyError: self.authz = authz.Implicit(self) else: self.authz = init_service(authz_spec, self) try: _authn = conf["authentication"] except KeyError: self.authn_broker = None else: self.authn_broker = populate_authn_broker(_authn, self, self.template_handler) try: _conf = conf["id_token"] except KeyError: self.idtoken = IDToken(self) else: self.idtoken = init_service(_conf, self) try: _conf = conf["userinfo"] except KeyError: pass else: self.userinfo = init_user_info(_conf, self.cwd) self.sdb.userinfo = self.userinfo try: _conf = conf["login_hint_lookup"] except KeyError: pass else: self.login_hint_lookup = init_service(_conf) if self.userinfo: self.login_hint_lookup.user_info = self.userinfo try: _conf = conf["login_hint2acrs"] except KeyError: self.login_hint2acrs = None else: self.login_hint2acrs = init_service(_conf) self.provider_info = self.create_providerinfo(_cap) # which signing/encryption algorithms to use in what context self.jwx_def = {} # special type of logging self.events = None # client registration access tokens self.registration_access_token = {}
def client_registration_setup(self, request, new_id=True, set_secret=True): try: request.verify() except (MessageException, ValueError) as err: return ResponseMessage( error="invalid_configuration_request", error_description="%s" % err ) request.rm_blanks() try: self.match_client_request(request) except CapabilitiesMisMatch as err: return ResponseMessage( error="invalid_request", error_description="Don't support proposed %s" % err, ) _context = self.endpoint_context if new_id: # create new id och secret client_id = rndstr(12) while client_id in _context.cdb: client_id = rndstr(12) else: try: client_id = request["client_id"] except KeyError: raise ValueError("Missing client_id") _cinfo = {"client_id": client_id, "client_salt": rndstr(8)} if "registration_api" in self.endpoint_context.endpoint: self.add_registration_api(_cinfo, client_id, _context) if new_id: _cinfo["client_id_issued_at"] = utc_time_sans_frac() if set_secret: client_secret = self.add_client_secret(_cinfo, client_id, _context) else: client_secret = "" _context.cdb[client_id] = _cinfo _cinfo = self.do_client_registration( request, client_id, ignore=["redirect_uris", "policy_uri", "logo_uri", "tos_uri"], ) if isinstance(_cinfo, ResponseMessage): return _cinfo args = dict( [(k, v) for k, v in _cinfo.items() if k in RegistrationResponse.c_param] ) comb_uri(args) response = RegistrationResponse(**args) # Add the client_secret as a symmetric key to the key jar if client_secret: _context.keyjar.add_symmetric(client_id, str(client_secret)) _context.cdb[client_id] = _cinfo try: _context.cdb.sync() except AttributeError: # Not all databases can be sync'ed pass logger.info("registration_response: %s" % sanitize(response.to_dict())) return response
def __init__(self, conf, keyjar=None, client_db=None, session_db=None, cwd='', cookie_dealer=None): self.conf = conf self.keyjar = keyjar or KeyJar() self.cwd = cwd if session_db: self.sdb = session_db else: self.sdb = create_session_db( conf['password'], db=None, token_expires_in=conf['token_expires_in'], grant_expires_in=conf['grant_expires_in'], refresh_token_expires_in=conf['refresh_token_expires_in'], sso_db=SSODb()) # client database self.cdb = client_db or {} try: self.seed = bytes(conf['seed'], 'utf-8') except KeyError: self.seed = bytes(rndstr(16), 'utf-8') # Default values, to be changed below depending on configuration self.endpoint = {} self.issuer = '' self.verify_ssl = True self.jwks_uri = None self.sso_ttl = 14400 # 4h self.symkey = rndstr(24) self.id_token_schema = IdToken self.endpoint_to_authn_method = {} self.cookie_dealer = cookie_dealer for param in [ 'verify_ssl', 'issuer', 'sso_ttl', 'symkey', 'client_authn', 'id_token_schema' ]: try: setattr(self, param, conf[param]) except KeyError: pass template_dir = conf["template_dir"] jinja_env = Environment(loader=FileSystemLoader(template_dir)) self.setup = {} try: self.jwks_uri = '{}/{}'.format(self.issuer, conf['jwks']['public_path']) except KeyError: self.jwks_uri = '' self.endpoint = build_endpoints( conf['endpoint'], endpoint_context=self, client_authn_method=CLIENT_AUTHN_METHOD, issuer=conf['issuer']) try: _cap = conf['capabilities'] except KeyError: _cap = {} for endpoint in ['authorization', 'token', 'userinfo', 'registration']: try: endpoint_spec = self.endpoint[endpoint] except KeyError: pass else: _cap[endpoint_spec.endpoint_name] = '{}'.format( self.endpoint[endpoint].endpoint_path) try: authz_spec = conf['authz'] except KeyError: self.authz = authz.Implicit(self) else: if 'args' in authz_spec: self.authz = authz.factory(authz_spec['name'], **authz_spec['args']) else: self.authz = authz.factory(self, authz_spec['name']) try: _authn = conf['authentication'] except KeyError: self.authn_broker = None else: self.authn_broker = AuthnBroker() for authn_spec in _authn: try: _args = authn_spec['kwargs'] except KeyError: _args = {} if 'template' in _args: _args['template_env'] = jinja_env _args['endpoint_context'] = self authn_method = user.factory(authn_spec['name'], **_args) args = { k: authn_spec[k] for k in ['acr', 'level', 'authn_authority'] if k in authn_spec } self.authn_broker.add(method=authn_method, **args) self.endpoint_to_authn_method[ authn_method.url_endpoint] = authn_method try: _conf = conf['userinfo'] except KeyError: pass else: try: kwargs = _conf['kwargs'] except KeyError: kwargs = {} if 'db_file' in kwargs: kwargs['db_file'] = os.path.join(self.cwd, kwargs['db_file']) self.userinfo = _conf['class'](**kwargs) self.provider_info = self.create_providerinfo(_cap) # which signing/encryption algorithms to use in what context self.jwx_def = {} # special type of logging self.events = None
def __init__( self, conf, keyjar=None, client_db=None, session_db=None, sso_db=None, cwd="", cookie_dealer=None, httpc=None, cookie_name=None, jwks_uri_path=None, jti_db=None, ): self.conf = conf self.keyjar = keyjar or KeyJar() self.cwd = cwd if self.keyjar is None or self.keyjar.owners() == []: args = {k: v for k, v in conf["jwks"].items() if k != "uri_path"} self.keyjar = init_key_jar(**args) try: self.seed = bytes(conf["seed"], "utf-8") except KeyError: self.seed = bytes(rndstr(16), "utf-8") # Default values, to be changed below depending on configuration self.endpoint = {} self.issuer = "" self.httpc = httpc or requests self.jwks_uri = None self.sso_ttl = 14400 # 4h self.symkey = rndstr(24) self.id_token_schema = IdToken self.idtoken = None self.authn_broker = None self.authz = None self.endpoint_to_authn_method = {} self.cookie_dealer = cookie_dealer self.login_hint_lookup = None self.login_hint2acrs = None self.userinfo = None self.scope2claims = SCOPE2CLAIMS # arguments for endpoints add-ons self.args = {} self.par_db = {} self.dev_auth_db = {} for param in [ "issuer", "sso_ttl", "symkey", "client_authn", "id_token_schema", ]: try: setattr(self, param, conf[param]) except KeyError: pass self.th_args = get_token_handlers(conf) # client database self.set_client_db() # session db self._sub_func = {} self.do_sub_func() # set self.sdb if session_db: self.set_session_db(sso_db, db=session_db) else: self.set_session_db(sso_db) if jti_db: self.set_jti_db(db=jti_db) else: self.set_jti_db() if cookie_name: self.cookie_name = cookie_name elif "cookie_name" in conf: self.cookie_name = conf["cookie_name"] else: self.cookie_name = { "session": "oidcop", "register": "oidc_op_rp", "session_management": "sman", } try: self.template_handler = conf["template_handler"] except KeyError: try: loader = conf["template_loader"] except KeyError: template_dir = conf["template_dir"] loader = Environment(loader=FileSystemLoader(template_dir), autoescape=True) self.template_handler = Jinja2TemplateHandler(loader) self.setup = {} if not jwks_uri_path: try: jwks_uri_path = conf["jwks"]["uri_path"] except KeyError: pass try: if self.issuer.endswith("/"): self.jwks_uri = "{}{}".format(self.issuer, jwks_uri_path) else: self.jwks_uri = "{}/{}".format(self.issuer, jwks_uri_path) except KeyError: self.jwks_uri = "" for item in [ "cookie_dealer", "authz", "authentication", "id_token", "scope2claims", ]: _func = getattr(self, "do_{}".format(item), None) if _func: _func() _cap = self.do_endpoints() for item in [ "userinfo", "login_hint_lookup", "login_hint2acrs", "add_on" ]: _func = getattr(self, "do_{}".format(item), None) if _func: _func() self.provider_info = self.create_providerinfo(_cap) # which signing/encryption algorithms to use in what context self.jwx_def = {} # special type of logging self.events = None # client registration access tokens self.registration_access_token = {} # The HTTP clients request arguments _cnf = conf.get("http_params") if _cnf: self.httpc_params = get_http_params(_cnf) else: # Backward compatibility self.httpc_params = {"verify": conf.get("verify_ssl")}
def client_registration_setup(self, request, new_id=True, set_secret=True): try: request.verify() except (MessageException, ValueError) as err: return ResponseMessage(error="invalid_configuration_request", error_description="%s" % err) request.rm_blanks() try: self.match_client_request(request) except CapabilitiesMisMatch as err: return ResponseMessage( error="invalid_request", error_description="Don't support proposed %s" % err, ) _context = self.endpoint_context if new_id: # create new id och secret client_id = rndstr(12) # cdb client_id MUST be unique! while client_id in _context.cdb: client_id = rndstr(12) if "client_id" in request: del request["client_id"] else: client_id = request.get("client_id") if not client_id: raise ValueError("Missing client_id") _cinfo = {"client_id": client_id, "client_salt": rndstr(8)} if "registration_read" in self.endpoint_context.endpoint: self.add_registration_api(_cinfo, client_id, _context) if new_id: _cinfo["client_id_issued_at"] = utc_time_sans_frac() client_secret = "" if set_secret: client_secret = self.add_client_secret(_cinfo, client_id, _context) logger.debug( "Stored client info in CDB under cid={}".format(client_id)) _context.cdb[client_id] = _cinfo _cinfo = self.do_client_registration( request, client_id, ignore=["redirect_uris", "policy_uri", "logo_uri", "tos_uri"], ) if isinstance(_cinfo, ResponseMessage): return _cinfo args = dict([(k, v) for k, v in _cinfo.items() if k in RegistrationResponse.c_param]) comb_uri(args) response = RegistrationResponse(**args) # Add the client_secret as a symmetric key to the key jar if client_secret: _context.keyjar.add_symmetric(client_id, str(client_secret)) logger.debug( "Stored updated client info in CDB under cid={}".format(client_id)) logger.debug("ClientInfo: {}".format(_cinfo)) _context.cdb[client_id] = _cinfo # Not all databases can be sync'ed if hasattr(_context.cdb, "sync") and callable(_context.cdb.sync): _context.cdb.sync() msg = "registration_response: {}" logger.info(msg.format(sanitize(response.to_dict()))) return response