def test_sign_encrypt_id_token(self): client_info = RegistrationResponse( id_token_signed_response_alg="RS512", client_id="client_1") session_info = { "authn_req": AREQN, "sub": "sub", "authn_event": { "authn_info": "loa2", "authn_time": time.time() }, } self.endpoint_context.jwx_def["signing_alg"] = {"id_token": "RS384"} self.endpoint_context.cdb["client_1"] = client_info.to_dict() _token = self.endpoint_context.idtoken.sign_encrypt(session_info, "client_1", sign=True) assert _token _jws = jws.factory(_token) assert _jws.jwt.headers["alg"] == "RS512" client_keyjar = KeyJar() _jwks = self.endpoint_context.keyjar.export_jwks() client_keyjar.import_jwks(_jwks, self.endpoint_context.issuer) _jwt = JWT(key_jar=client_keyjar, iss="client_1") res = _jwt.unpack(_token) assert isinstance(res, dict) assert res["aud"] == ["client_1"]
def test_sign_encrypt_id_token(): client_info = RegistrationResponse(id_token_signed_response_alg='RS512', client_id='client_1') session_info = { 'authn_req': AREQN, 'sub': 'sub', 'authn_event': { "authn_info": 'loa2', "authn_time": time.time() } } ENDPOINT_CONTEXT.jwx_def["signing_alg"] = {'id_token': 'RS384'} ENDPOINT_CONTEXT.cdb['client_1'] = client_info.to_dict() _token = sign_encrypt_id_token(ENDPOINT_CONTEXT, session_info, 'client_1', sign=True) assert _token _jws = jws.factory(_token) assert _jws.jwt.headers['alg'] == 'RS512' client_keyjar = KeyJar() _jwks = KEYJAR.export_jwks() client_keyjar.import_jwks(_jwks, ENDPOINT_CONTEXT.issuer) _jwt = JWT(key_jar=client_keyjar, iss='client_1') res = _jwt.unpack(_token) assert isinstance(res, dict) assert res['aud'] == ['client_1']
def test_get_sign_algorithm_2(): client_info = RegistrationResponse(id_token_signed_response_alg='RS512') endpoint_context = EndpointContext(conf) algs = get_sign_and_encrypt_algorithms(endpoint_context, client_info, 'id_token', sign=True) # default signing alg assert algs == {'sign': True, 'encrypt': False, 'sign_alg': 'RS512'}
def test_no_default_encrypt_algorithms(): client_info = RegistrationResponse() endpoint_context = EndpointContext(conf) with pytest.raises(UnknownAlgorithm): get_sign_and_encrypt_algorithms(endpoint_context, client_info, 'id_token', sign=True, encrypt=True)
def test_get_sign_algorithm(self): client_info = RegistrationResponse() endpoint_context = EndpointContext(conf) algs = get_sign_and_encrypt_algorithms(endpoint_context, client_info, "id_token", sign=True) # default signing alg assert algs == {"sign": True, "encrypt": False, "sign_alg": "RS256"}
def process_request(self, request=None, **kwargs): _cli_info = self.server_get("endpoint_context").cdb[ request["client_id"]] args = { k: v for k, v in _cli_info.items() if k in RegistrationResponse.c_param } comb_uri(args) return {"response_args": RegistrationResponse(**args)}
def process_request(self, request=None, **kwargs): args = dict( [ (k, v) for k, v in self.endpoint_context.cdb[request["client_id"]].items() if k in RegistrationResponse.c_param ] ) comb_uri(args) return {"response_args": RegistrationResponse(**args)}
def test_get_sign_algorithm_3(): client_info = RegistrationResponse() endpoint_context = EndpointContext(conf) endpoint_context.jwx_def["signing_alg"] = {'id_token': 'RS384'} algs = get_sign_and_encrypt_algorithms(endpoint_context, client_info, 'id_token', sign=True) # default signing alg assert algs == {'sign': True, 'encrypt': False, 'sign_alg': 'RS384'}
def test_no_default_encrypt_algorithms(self): client_info = RegistrationResponse() endpoint_context = EndpointContext(conf) args = get_sign_and_encrypt_algorithms(endpoint_context, client_info, "id_token", sign=True, encrypt=True) assert args["sign_alg"] == "RS256" assert args["enc_enc"] == "A128CBC-HS256" assert args["enc_alg"] == "RSA1_5"
def test_get_sign_algorithm_4(self): client_info = RegistrationResponse( id_token_signed_response_alg="RS512") endpoint_context = EndpointContext(conf) endpoint_context.jwx_def["signing_alg"] = {"id_token": "RS384"} algs = get_sign_and_encrypt_algorithms(endpoint_context, client_info, "id_token", sign=True) # default signing alg assert algs == {"sign": True, "encrypt": False, "sign_alg": "RS512"}
def test_begin_2(self): ISS_ID = "https://op.example.org" OP_KEYS = build_keyjar(DEFAULT_KEY_DEFS) # The 4 steps of client_setup client = self.rph.init_client(ISS_ID) with responses.RequestsMock() as rsps: request_uri = '{}/.well-known/openid-configuration'.format(ISS_ID) _jws = ProviderConfigurationResponse( issuer=ISS_ID, authorization_endpoint='{}/authorization'.format(ISS_ID), jwks_uri='{}/jwks.json'.format(ISS_ID), response_types_supported=[ 'code', 'id_token', 'id_token token' ], subject_types_supported=['public'], id_token_signing_alg_values_supported=["RS256", "ES256"], token_endpoint='{}/token'.format(ISS_ID), registration_endpoint='{}/register'.format(ISS_ID)).to_json() rsps.add("GET", request_uri, body=_jws, status=200) rsps.add("GET", '{}/jwks.json'.format(ISS_ID), body=OP_KEYS.export_jwks_as_json(), status=200) issuer = self.rph.do_provider_info(client) # Calculating request so I can build a reasonable response self.rph.add_callbacks(client.service_context) # Publishing a JWKS instead of a JWKS_URI client.service_context.jwks_uri = '' client.service_context.jwks = client.service_context.keyjar.export_jwks( ) _req = client.service['registration'].construct_request() with responses.RequestsMock() as rsps: request_uri = client.service_context.get( 'provider_info')["registration_endpoint"] _jws = RegistrationResponse( client_id="client uno", client_secret="VerySecretAndLongEnough", **_req.to_dict()).to_json() rsps.add("POST", request_uri, body=_jws, status=200) self.rph.do_client_registration(client, ISS_ID) assert 'jwks' in client.service_context.get('registration_response')
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 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
# ============== 4.1.6 ================== print("-" * 20, "4.1.6", "-" * 20) fed_pol = open("4.1.6_fed_policy.json").read() mp_fed = MetadataPolicy().from_json(fed_pol) print("4.1.6_fed_policy.json", mp_fed.verify()) org_pol = open("4.1.6_org_policy.json").read() mp_org = MetadataPolicy().from_json(org_pol) print("4.1.6_org_policy.json", mp_org.verify()) comb_policy = MetadataPolicy(**combine_policy(mp_fed, mp_org)) print("comb", comb_policy.verify()) metadata = open("4.1.6_metadata.json").read() md = RegistrationResponse().from_json(metadata) print("4.1.6_metadata.json", mp_org.verify()) # apply policy res = apply_policy(md, comb_policy) res_md = RegistrationResponse(**res) print(json.dumps(res_md.to_dict(), indent=4, sort_keys=True)) print('=', md.to_dict() == res_md.to_dict()) # ============== 4.3.3 ================== print("-" * 20, "4.3.3", "-" * 20) for item in ['4.3.3_1.json', '4.3.3_2.json']: data = open(item).read()
def test_begin(self): ISS_ID = "https://op.example.org" OP_KEYS = build_keyjar(DEFAULT_KEY_DEFS) # The 4 steps of client_setup client = self.rph.init_client(ISS_ID) with responses.RequestsMock() as rsps: request_uri = '{}/.well-known/openid-configuration'.format(ISS_ID) _jws = ProviderConfigurationResponse( issuer=ISS_ID, authorization_endpoint='{}/authorization'.format(ISS_ID), jwks_uri='{}/jwks.json'.format(ISS_ID), response_types_supported=[ 'code', 'id_token', 'id_token token' ], subject_types_supported=['public'], id_token_signing_alg_values_supported=["RS256", "ES256"], token_endpoint='{}/token'.format(ISS_ID), registration_endpoint='{}/register'.format(ISS_ID)).to_json() rsps.add("GET", request_uri, body=_jws, status=200) rsps.add("GET", '{}/jwks.json'.format(ISS_ID), body=OP_KEYS.export_jwks_as_json(), status=200) issuer = self.rph.do_provider_info(client) # Calculating request so I can build a reasonable response self.rph.add_callbacks(client.service_context) _req = client.service['registration'].construct_request() with responses.RequestsMock() as rsps: request_uri = client.service_context.get( 'provider_info')["registration_endpoint"] _jws = RegistrationResponse( client_id="client uno", client_secret="VerySecretAndLongEnough", **_req.to_dict()).to_json() rsps.add("POST", request_uri, body=_jws, status=200) self.rph.do_client_registration(client, ISS_ID) self.rph.issuer2rp[issuer] = client assert set(client.service_context.get('behaviour').keys()) == { 'token_endpoint_auth_method', 'response_types', 'scope', 'application_type', 'application_name' } assert client.service_context.get('client_id') == "client uno" assert client.service_context.get( 'client_secret') == "VerySecretAndLongEnough" assert client.service_context.get('issuer') == ISS_ID res = self.rph.init_authorization(client) assert set(res.keys()) == {'url', 'state'} p = urlparse(res["url"]) assert p.hostname == 'op.example.org' assert p.path == "/authorization" qs = parse_qs(p.query) assert qs['state'] == [res['state']] # PKCE stuff assert 'code_challenge' in qs assert qs["code_challenge_method"] == ["S256"]
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