def _keyjar(self, keyjar=None, conf=None, entity_id=""): if keyjar is None: if "keys" in conf: keys_args = { k: v for k, v in conf["keys"].items() if k != "uri_path" } _keyjar = init_key_jar(**keys_args) elif "key_conf" in conf: keys_args = { k: v for k, v in conf["key_conf"].items() if k != "uri_path" } _keyjar = init_key_jar(**keys_args) else: _keyjar = KeyJar() if "jwks" in conf: _keyjar.import_jwks(conf["jwks"], "") if "" in _keyjar and entity_id: # make sure I have the keys under my own name too (if I know it) _keyjar.import_jwks_as_json( _keyjar.export_jwks_as_json(True, ""), entity_id) _httpc_params = conf.get("httpc_params") if _httpc_params: _keyjar.httpc_params = _httpc_params return _keyjar else: return keyjar
def test_init_key_jar_dump_private(): for _file in [PRIVATE_FILE, PUBLIC_FILE]: if os.path.isfile(_file): os.unlink(_file) # New set of keys, JWKSs with keys and public written to file _keyjar = init_key_jar(private_path=PRIVATE_FILE, key_defs=KEYSPEC, owner="https://example.com") assert list(_keyjar.owners()) == ["https://example.com"] # JWKS will be read from disc, not created new _keyjar2 = init_key_jar(private_path=PRIVATE_FILE, key_defs=KEYSPEC) assert list(_keyjar2.owners()) == [""]
def test_init_key_jar_dump_public(): for _file in [PRIVATE_FILE, PUBLIC_FILE]: if os.path.isfile(_file): os.unlink(_file) # JWKS with public keys written to file _keyjar = init_key_jar(public_path=PUBLIC_FILE, key_defs=KEYSPEC) assert list(_keyjar.owners()) == [''] # JWKS will be read from disc, not created new _keyjar2 = init_key_jar(public_path=PUBLIC_FILE, key_defs=KEYSPEC) assert list(_keyjar2.owners()) == ['']
def test_init_key_jar_update(): for _file in [PRIVATE_FILE, PUBLIC_FILE]: if os.path.isfile(_file): os.unlink(_file) # New set of keys, JWKSs with keys and public written to file _keyjar_1 = init_key_jar( private_path=PRIVATE_FILE, key_defs=KEYSPEC, issuer_id="https://example.com", public_path=PUBLIC_FILE, read_only=False, ) assert list(_keyjar_1.owners()) == ["https://example.com"] _keyjar_2 = init_key_jar(private_path=PRIVATE_FILE, key_defs=KEYSPEC_2, public_path=PUBLIC_FILE) # Both should contain the same RSA key rsa1 = _keyjar_1.get_signing_key("RSA", "https://example.com") rsa2 = _keyjar_2.get_signing_key("RSA", "") assert len(rsa1) == 1 assert len(rsa2) == 1 assert rsa1[0] == rsa2[0] # keyjar1 should only contain one EC key while keyjar2 should contain 2. ec1 = _keyjar_1.get_signing_key("EC", "https://example.com") ec2 = _keyjar_2.get_signing_key("EC", "") assert len(ec1) == 1 assert len(ec2) == 2 # The file on disc should not have changed _keyjar_3 = init_key_jar(private_path=PRIVATE_FILE) assert len(_keyjar_3.get_signing_key("RSA")) == 1 assert len(_keyjar_3.get_signing_key("EC")) == 1 _keyjar_4 = init_key_jar( private_path=PRIVATE_FILE, key_defs=KEYSPEC_2, public_path=PUBLIC_FILE, read_only=False, ) # Now it should _keyjar_5 = init_key_jar(private_path=PRIVATE_FILE) assert len(_keyjar_5.get_signing_key("RSA")) == 1 assert len(_keyjar_5.get_signing_key("EC")) == 2
def get_subject_conf(entity_type, id): if entity_type in ["openid_provider", "openid_relying_party"]: head, tail = os.path.split(dir_path) _path = os.path.join(head, entity_type, id) e_cnf = {"class": CNF_MAP[entity_type], "attr": ATTR_MAP[entity_type]} if entity_type == "openid_provider": e_cnf["path"] = ["op", "server_info"] _conf = create_from_config_file(Configuration, entity_conf=[e_cnf], filename=os.path.join( _path, "conf.json"), base_path=_path) ent_conf = _conf[ATTR_MAP[entity_type]] keys_args = { k: v for k, v in ent_conf["federation"]["keys"].items() if k != "uri_path" } _keyjar = init_key_jar(**keys_args) _entity_id = ent_conf["federation"].get("entity_id") if _entity_id.endswith("/{}"): # allow tenant ID _entity_id = _entity_id[:-3] d_path = os.path.join("authorities", i_am, entity_type, quote_plus(_entity_id)) if os.path.isdir(d_path): pass else: os.makedirs(d_path) file_path = os.path.join(d_path, "jwks.json") return file_path, _keyjar else: _path = os.path.join(dir_path, entity_type, id) _conf = create_from_config_file( FedEntityConfiguration, filename=os.path.join(_path, "conf.json"), file_attributes=DEFAULT_FED_FILE_ATTRIBUTE_NAMES, base_path=_path) keys_args = {k: v for k, v in _conf["keys"].items() if k != "uri_path"} _keyjar = init_key_jar(**keys_args) d_path = os.path.join("authorities", i_am, id) if os.path.isdir(d_path): pass else: os.makedirs(d_path) file_path = os.path.join(d_path, "jwks.json") return file_path, _keyjar
def __init__(self, base_path, entity_id_pattern="https://{}", federation_entities="", **kwargs): self.lifetime = kwargs["lifetime"] self.entity_id_pattern = create_regex(entity_id_pattern) self.signer = {} for iss in os.listdir(federation_entities): _signer = FetchEntityStatement(iss, entity_id_pattern) _signer.fe_base_path = os.path.join(base_path, federation_entities, iss) _signer.auth_base_path = os.path.join(base_path, kwargs["authorities"], iss) cargs = {k: kwargs[k] for k in ['domain', 'port'] if k in kwargs} _conf = create_from_config_file(FedEntityConfiguration, filename=os.path.join(_signer.fe_base_path, "conf.json"), file_attributes=DEFAULT_FED_FILE_ATTRIBUTE_NAMES, base_path=_signer.fe_base_path, **cargs) _conf.entity_type = "federation_entity" _signer.federation_api_endpoint = kwargs["federation_api_endpoint"].format( domain=kwargs["domain"], port=kwargs["port"]) _signer.conf = _conf keys_args = {k: v for k, v in _conf["keys"].items() if k != "uri_path"} keys_args["issuer_id"] = _signer.make_entity_id(iss) _signer.keyjar = init_key_jar(**keys_args) if 'url_prefix' in kwargs: self.url_prefix = kwargs['url_prefix'] self.signer[iss] = _signer
def init_oidc_rp_handler(config, dir_path): rp_keys_conf = config.keys _fed_conf = config.federation _httpc_params = config.httpc_params _path = rp_keys_conf['uri_path'] if _path.startswith('./'): _path = _path[2:] elif _path.startswith('/'): _path = _path[1:] args = {k: v for k, v in rp_keys_conf.items() if k != "uri_path"} rp_keyjar = init_key_jar(**args) rp_keyjar.httpc_params = _httpc_params rph = RPHandler(base_url=config.base_url, hash_seed=config.hash_seed, jwks_path=_path, client_configs=config.clients, keyjar=rp_keyjar, services=config.services, httpc_params=_httpc_params, federation_entity_config=_fed_conf) return rph
def init_oidc_op_endpoints(app): _config = app.srv_config.op _server_info_config = _config['server_info'] _kj_args = { k: v for k, v in _server_info_config['jwks'].items() if k != 'uri_path' } _kj = init_key_jar(**_kj_args) iss = _server_info_config['issuer'] # make sure I have a set of keys under my 'real' name _kj.import_jwks_as_json(_kj.export_jwks_as_json(True, ''), iss) endpoint_context = EndpointContext(_server_info_config, keyjar=_kj, cwd=folder) # sort of backward but work so... _kj.httpc_params = endpoint_context.httpc_params for endp in endpoint_context.endpoint.values(): p = urlparse(endp.endpoint_path) _vpath = p.path.split('/') if _vpath[0] == '': endp.vpath = _vpath[1:] else: endp.vpath = _vpath return endpoint_context
def factory( server_get, code: Optional[dict] = None, token: Optional[dict] = None, refresh: Optional[dict] = None, id_token: Optional[dict] = None, jwks_file: Optional[str] = "", **kwargs ) -> TokenHandler: """ Create a token handler :param code: :param token: :param refresh: :param jwks_file: :return: TokenHandler instance """ token_class_map = {"code": "authorization_code", "token": "access_token", "refresh": "refresh_token", 'idtoken': 'id_token'} key_defs = [] read_only = False cwd = server_get("endpoint_context").cwd if kwargs.get("jwks_def"): defs = kwargs["jwks_def"] if not jwks_file: jwks_file = defs.get("private_path", os.path.join(cwd, JWKS_FILE)) read_only = defs.get("read_only", read_only) key_defs = defs.get("key_defs", []) if not jwks_file: jwks_file = os.path.join(cwd, JWKS_FILE) if not key_defs: for kid, cnf in [("code", code), ("refresh", refresh), ("token", token)]: if cnf is not None: if default_token(cnf): key_defs.append({"type": "oct", "bytes": 24, "use": ["enc"], "kid": kid}) kj = init_key_jar(key_defs=key_defs, private_path=jwks_file, read_only=read_only) args = {} for cls, cnf, attr in [ ("code", code, "authorization_code"), ("token", token, "access_token"), ("refresh", refresh, "refresh_token"), ]: if cnf is not None: if default_token(cnf): _add_passwd(kj, cnf, cls) args[attr] = init_token_handler(server_get, cnf, token_class_map[cls]) if id_token is not None: args["id_token"] = init_token_handler(server_get, id_token, token_class="") return TokenHandler(**args)
def init_oidc_op_endpoints(app): _config = app.srv_config.op _server_info_config = _config['server_info'] _kj_args = { k: v for k, v in _server_info_config['jwks'].items() if k != 'uri_path' } _kj = init_key_jar(**_kj_args) iss = _server_info_config['issuer'] # make sure I have a set of keys under my 'real' name _kj.import_jwks_as_json(_kj.export_jwks_as_json(True, ''), iss) try: _kj.verify_ssl = _config['server_info']['verify_ssl'] except KeyError: pass endpoint_context = EndpointContext(_server_info_config, keyjar=_kj, cwd=folder) for endp in endpoint_context.endpoint.values(): p = urlparse(endp.endpoint_path) _vpath = p.path.split('/') if _vpath[0] == '': endp.vpath = _vpath[1:] else: endp.vpath = _vpath return endpoint_context
def _keyjar(self, keyjar=None, db_conf=None, conf=None, entity_id=''): if keyjar is None: _storage = None if db_conf: _cnf = get_storage_conf(db_conf, 'keyjar') if _cnf: _storage = storage_factory(_cnf) if 'keys' in conf: args = {k: v for k, v in conf["keys"].items() if k != "uri_path"} args.update({'storage': _storage}) _keyjar = init_key_jar(**args) else: _keyjar = KeyJar(storage=_storage) if 'jwks' in conf: _keyjar.import_jwks(conf['jwks'], '') if '' in _keyjar and entity_id: # make sure I have the keys under my own name too (if I know it) _keyjar.import_jwks_as_json(_keyjar.export_jwks_as_json(True, ''), entity_id) _httpc_params = conf.get('httpc_params') if _httpc_params: _keyjar.httpc_params = _httpc_params return _keyjar else: return keyjar
def factory(ec, code=None, token=None, refresh=None, jwks_def=None, **kwargs): """ Create a token handler :param code: :param token: :param refresh: :param jwks_def: :return: TokenHandler instance """ TTYPE = {"code": "A", "token": "T", "refresh": "R"} if jwks_def: kj = init_key_jar(**jwks_def) else: kj = None args = {} if code: _add_passwd(kj, code, "code") args["code_handler"] = init_token_handler(ec, code, TTYPE["code"]) if token: _add_passwd(kj, token, "token") args["access_token_handler"] = init_token_handler( ec, token, TTYPE["token"]) if refresh: _add_passwd(kj, refresh, "refresh") args["refresh_token_handler"] = init_token_handler( ec, refresh, TTYPE["refresh"]) return TokenHandler(**args)
def create_and_write_private_and_public_key_sets(entities, id, config): _dir = entities[id][0] _key_conf = config["keys"].copy() _key_conf["public_path"] = os.path.join(_dir, _key_conf["public_path"]) _key_conf["private_path"] = os.path.join(_dir, _key_conf["private_path"]) _keyjar = init_key_jar(**_key_conf) return _keyjar
def test_init_key_jar_create_directories(): # make sure the directories are gone for _dir in ['priv', 'public']: if os.path.isdir("{}/{}".format(BASEDIR, _dir)): shutil.rmtree("{}/{}".format(BASEDIR, _dir)) _keyjar = init_key_jar(**OIDC_KEYS) assert len(_keyjar.get_signing_key('RSA')) == 1 assert len(_keyjar.get_signing_key('EC')) == 1
def get_subject_info(ta): _path = os.path.join(dir_path, "signing_service", "federation_entity", ta) _conf = create_from_config_file( FedEntityConfiguration, filename=os.path.join(_path, "conf.json"), file_attributes=DEFAULT_FED_FILE_ATTRIBUTE_NAMES, base_path=_path) keys_args = {k: v for k, v in _conf["keys"].items() if k != "uri_path"} _keyjar = init_key_jar(**keys_args) return _keyjar
def create_keyjars(owners, keydefs, root_dir='.'): res = {} for entity in owners: _id = quote_plus(entity) conf = { 'private_path': '{}/private/{}'.format(root_dir, _id), 'key_defs': keydefs, 'public_path': '{}/public/{}'.format(root_dir, _id) } res[entity] = init_key_jar(**conf) return res
def make_internal_signing_service(config, entity_id): """ Given configuration initiate an InternalSigningService instance :param config: The signing service configuration :param entity_id: The entity identifier :return: A InternalSigningService instance """ _args = dict([(k, v) for k, v in config.items() if k in KJ_SPECS]) _kj = init_key_jar(**_args) return InternalSigningService(entity_id, _kj)
def make_jwks_bundle(config, eid): _args = dict([(k,v) for k,v in config.items() if k in KJ_SPECS]) _kj = init_key_jar(**_args) if 'dir' in config: jb = FSJWKSBundle(eid, _kj, config['dir'], key_conv={'to': quote_plus, 'from': unquote_plus}) else: jb = JWKSBundle(eid, _kj) if 'bundle' in config: jb.loads(open(config['bundle']).read()) elif 'signed_bundle' in config: _kj = jwks_to_keyjar(open(config['verification_keys']).read()) jb.upload_signed_bundle(open(config['signed_bundle']).read(), _kj) return jb
def init_oidc_rp_handler(app): _rp_conf = app.config if _rp_conf.get('rp_keys'): _kj = init_key_jar(**_rp_conf['rp_keys']) _path = _rp_conf['rp_keys']['public_path'] # removes ./ and / from the begin of the string _path = re.sub('^(.)/', '', _path) else: _kj = KeyJar() _path = '' _kj.httpc_params = _rp_conf['httpc_params'] hash_seed = app.config.get('hash_seed', "BabyHoldOn") rph = RPHandler(_rp_conf['base_url'], _rp_conf['clients'], services=_rp_conf['services'], hash_seed=hash_seed, keyjar=_kj, jwks_path=_path, httpc_params=_rp_conf['httpc_params']) #, verify_ssl=False) return rph
def init_oidc_rp_handler(app): _rp_conf = app.rp_config if _rp_conf.rp_keys: _kj = init_key_jar(**_rp_conf.rp_keys) _path = _rp_conf.rp_keys['public_path'] # removes ./ and / from the begin of the string _path = re.sub('^(.)/', '', _path) else: _kj = KeyJar() _path = '' _kj.httpc_params = _rp_conf.httpc_params rph = RPHandler(_rp_conf.base_url, _rp_conf.clients, services=_rp_conf.services, hash_seed=_rp_conf.hash_seed, keyjar=_kj, jwks_path=_path, httpc_params=_rp_conf.httpc_params) return rph
def factory(ec, code=None, token=None, refresh=None, jwks_def=None, **kwargs): """ Create a token handler :param code: :param token: :param refresh: :param jwks_def: :return: TokenHandler instance """ TTYPE = {"code": "A", "token": "T", "refresh": "R"} if jwks_def: kj = init_key_jar(**jwks_def) else: kj = None args = {} if code: if kj: _keys = kj.get_encrypt_key(key_type="oct", kid="code") if _keys: code["password"] = as_unicode(_keys[0].k) args["code_handler"] = init_token_handler(ec, code, TTYPE["code"]) if token: if kj: _keys = kj.get_encrypt_key(key_type="oct", kid="token") if _keys: token["password"] = as_unicode(_keys[0].k) args["access_token_handler"] = init_token_handler( ec, token, TTYPE["token"]) if refresh: if kj: _keys = kj.get_encrypt_key(key_type="oct", kid="refresh") if _keys: refresh["password"] = as_unicode(_keys[0].k) args["refresh_token_handler"] = init_token_handler( ec, refresh, TTYPE["refresh"]) return TokenHandler(**args)
def init_oidc_op_endpoints(app): _config = app.srv_config.op _server_info_config = _config['server_info'] _kj_args = { k: v for k, v in _server_info_config['jwks'].items() if k != 'uri_path' } _kj = init_key_jar(**_kj_args) iss = _server_info_config['issuer'] # make sure I have a set of keys under my 'real' name _kj.import_jwks_as_json(_kj.export_jwks_as_json(True, ''), iss) _kj.verify_ssl = _config['server_info'].get('verify_ssl', False) endpoint_context = EndpointContext(_server_info_config, keyjar=_kj, cwd=settings.BASE_DIR) return endpoint_context
def init_oidc_rp_handler(app): oidc_keys_conf = app.config.get('OIDC_KEYS') verify_ssl = app.config.get('VERIFY_SSL') _kj = init_key_jar(**oidc_keys_conf) _kj.verify_ssl = verify_ssl _path = oidc_keys_conf['public_path'] if _path.startswith('./'): _path = _path[2:] elif _path.startswith('/'): _path = _path[1:] rph = RPHandler(base_url=app.config.get('BASEURL'), hash_seed="BabyHoldOn", keyjar=_kj, jwks_path=_path, client_configs=app.config.get('CLIENTS'), services=app.config.get('SERVICES'), verify_ssl=verify_ssl) return rph
def init_oidc_rp_handler(app): rp_keys_conf = app.rp_config.rp_keys _fed_conf = app.rp_config.federation _httpc_params = app.rp_config.httpc_params _fed_conf['entity_id'] = _fed_conf['entity_id'].format( domain=app.rp_config.domain, port=app.rp_config.port) _fed_conf['web_cert_path'] = "{}/{}".format( dir_path, lower_or_upper(app.rp_config.web_conf, "server_cert")) _path = rp_keys_conf['uri_path'] if _path.startswith('./'): _path = _path[2:] elif _path.startswith('/'): _path = _path[1:] for client, _cnf in app.rp_config.clients.items(): for attr in ['client_id', 'entity_id']: _val = _cnf.get(attr) if _val: _cnf[attr] = _val.format(domain=app.rp_config.domain, port=app.rp_config.port) args = {k: v for k, v in rp_keys_conf.items() if k != "uri_path"} rp_keyjar = init_key_jar(**args) rp_keyjar.httpc_params = _httpc_params rph = RPHandler(base_url=app.rp_config.base_url, hash_seed=app.rp_config.hash_seed, jwks_path=_path, client_configs=app.rp_config.clients, keyjar=rp_keyjar, services=app.rp_config.services, httpc_params=_httpc_params, federation_entity_config=_fed_conf) return rph
def make_signing_service(config, entity_id): """ Given configuration initiate a SigningService instance :param config: The signing service configuration :param entity_id: The entity identifier :return: A SigningService instance """ _args = dict([(k, v) for k, v in config.items() if k in KJ_SPECS]) _kj = init_key_jar(**_args) if config['type'] == 'internal': signer = InternalSigningService(entity_id, _kj) elif config['type'] == 'web': _kj.issuer_keys[config['iss']] = _kj.issuer_keys[''] del _kj.issuer_keys[''] signer = WebSigningServiceClient(config['iss'], config['url'], entity_id, _kj) else: raise ValueError('Unknown signer type: {}'.format(config['type'])) return signer
'tools.staticdir.debug': True, 'tools.staticdir.on': True, 'tools.staticdir.content_types': { 'json': 'application/json', 'jwks': 'application/json', 'jose': 'application/jose' }, 'log.screen': True, 'cors.expose_public.on': True } } _server_info_config = config.CONFIG['server_info'] _jwks_config = _server_info_config['jwks'] _kj = init_key_jar(owner=_server_info_config['issuer'], **_jwks_config) if args.insecure: verify_ssl = False else: verify_ssl = True cookie_dealer = CookieDealer(**_server_info_config['cookie_dealer']) endpoint_context = EndpointContext(_server_info_config, keyjar=_kj, cwd=folder, httpcli=requests.request, verify_ssl=verify_ssl, cookie_dealer=cookie_dealer)
ISS = 'https://example.com' KEYSPEC = [ { "type": "RSA", "use": ["sig"] }, { "type": "EC", "crv": "P-256", "use": ["sig"] }, ] CLI_KEY = init_key_jar(public_path='{}/pub_client.jwks'.format(_dirname), private_path='{}/priv_client.jwks'.format(_dirname), key_defs=KEYSPEC, issuer_id='client_id') class TestPKCE256: @pytest.fixture(autouse=True) def create_client(self): config = { 'client_id': 'client_id', 'client_secret': 'a longesh password', 'redirect_uris': ['https://example.com/cli/authz_cb'], 'behaviour': { 'response_types': ['code'] }, 'add_ons': { "pkce": {
}, 'log.screen': True, 'cors.expose_public.on': True }} sys.path.insert(0, ".") config = importlib.import_module(args.config) cprp = importlib.import_module('cprp') if args.port: _base_url = "{}:{}".format(config.BASEURL, args.port) else: _base_url = config.BASEURL _kj = init_key_jar(private_path=config.PRIVATE_JWKS_PATH, key_defs=config.KEYDEFS, public_path=config.PUBLIC_JWKS_PATH) if args.insecure: verify_ssl = False else: verify_ssl = True rph = RPHandler(base_url=_base_url, hash_seed="BabyDriver", keyjar=_kj, jwks_path=config.PUBLIC_JWKS_PATH, client_configs=config.CLIENTS, service_factory=factory, services=config.SERVICES, client_cls=oidc.RP, verify_ssl=verify_ssl) cherrypy.tree.mount(cprp.Consumer(rph, 'html'), '/', provider_config)
'tools.staticdir.dir': os.path.join(folder, 'static'), 'tools.staticdir.debug': True, 'tools.staticdir.on': True, 'tools.staticdir.content_types': { 'json': 'application/json', 'jwks': 'application/json', 'jose': 'application/jose' }, 'log.screen': True, 'cors.expose_public.on': True } } _base_url = config.BASEURL _kj = init_key_jar(**config.RP_CONFIG['jwks']) if args.insecure: verify_ssl = False else: verify_ssl = True federation_entity = make_federation_entity( config.CLIENTS['']['federation'], httpcli=requests.request, verify_ssl=verify_ssl) rph = RPHandler(base_url=_base_url, hash_seed="BabyDriver", keyjar=_kj, jwks_path=config.RP_CONFIG['jwks_url_path'],
KEYDEFS = [ { "type": "RSA", "key": "", "use": ["sig"] }, { "type": "EC", "crv": "P-256", "use": ["sig"] }, ] ISSUER = "https://example.com/" KEYJAR = init_key_jar(key_defs=KEYDEFS, issuer_id=ISSUER) KEYJAR.import_jwks(KEYJAR.export_jwks(True, ISSUER), "") RESPONSE_TYPES_SUPPORTED = [ ["code"], ["token"], ["id_token"], ["code", "token"], ["code", "id_token"], ["id_token", "token"], ["code", "token", "id_token"], ["none"], ] CAPABILITIES = { "response_types_supported": [" ".join(x) for x in RESPONSE_TYPES_SUPPORTED], "token_endpoint_auth_methods_supported": [