def test_dump_issuer_keys(self): kb = keybundle_from_local_file("file://%s/jwk.json" % BASE_PATH, "jwks", ["sig"]) assert len(kb) == 1 kj = KeyJar() kj.issuer_keys[""] = [kb] _jwks_dict = kj.export_jwks() _info = _jwks_dict['keys'][0] assert _info == { 'use': 'sig', 'e': 'AQAB', 'kty': 'RSA', 'alg': 'RS256', 'n': 'pKybs0WaHU_y4cHxWbm8Wzj66HtcyFn7Fh3n' '-99qTXu5yNa30MRYIYfSDwe9JVc1JUoGw41yq2StdGBJ40HxichjE' '-Yopfu3B58Q' 'lgJvToUbWD4gmTDGgMGxQxtv1En2yedaynQ73sDpIK-12JJDY55pvf' '-PCiSQ9OjxZLiVGKlClDus44_uv2370b9IN2JiEOF-a7JB' 'qaTEYLPpXaoKWDSnJNonr79tL0T7iuJmO1l705oO3Y0TQ' '-INLY6jnKG_RpsvyvGNnwP9pMvcP1phKsWZ10ofuuhJGRp8IxQL9Rfz' 'T87OvF0RBSO1U73h09YP-corWDsnKIi6TbzRpN5YDw', 'kid': 'abc' }
def test_example_1(self): _symkey = KC_SYM_S.get(alg2keytype("HS256")) csr = CheckSessionRequest(id_token=IDTOKEN.to_jwt( key=_symkey, algorithm="HS256", lifetime=300)) keyjar = KeyJar() keyjar.add_kb(ISS, KC_SYM_S) assert csr.verify(keyjar=keyjar)
def __init__(self, state_db, ca_certs=None, client_authn_factory=None, keyjar=None, verify_ssl=True, config=None, client_cert=None, httplib=None, services=None, service_factory=None, jwks_uri='', module_dirs=None): """ :param ca_certs: Certificates used to verify HTTPS certificates :param client_authn_factory: Factory that this client can use to initiate a client authentication class. :param keyjar: A py:class:`oidcmsg.key_jar.KeyJar` instance :param verify_ssl: Whether the SSL certificate should be verified. :param config: Configuration information passed on to the :py:class:`oidcservice.service_context.ServiceContext` initialization :param client_cert: Certificate used by the HTTP client :param httplib: A HTTP client to use :param services: A list of service definitions :param service_factory: A factory to use when building the :py:class:`oidcservice.service.Service` instances :param jwks_uri: A jwks_uri :return: Client instance """ self.session_interface = StateInterface(state_db) self.http = httplib or HTTPLib( ca_certs=ca_certs, verify_ssl=verify_ssl, client_cert=client_cert) if not keyjar: keyjar = KeyJar() keyjar.verify_ssl = verify_ssl self.events = None self.service_context = ServiceContext(keyjar, config=config, jwks_uri=jwks_uri) if self.service_context.client_id: self.client_id = self.service_context.client_id _cam = client_authn_factory or ca_factory self.service_factory = service_factory or default_service_factory _srvs = services or DEFAULT_SERVICES if not module_dirs: module_dirs = ['oauth2'] self.service = build_services(_srvs, self.service_factory, module_dirs, self.service_context, state_db, _cam) self.service_context.service = self.service self.verify_ssl = verify_ssl
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_dump_issuer_keys(self): kb = keybundle_from_local_file("file://%s/jwk.json" % BASE_PATH, "jwks", ["sig"]) assert len(kb) == 1 kj = KeyJar() kj.add_kb("", kb) _jwks_dict = kj.export_jwks() _info = _jwks_dict["keys"][0] assert _info == { "use": "sig", "e": "AQAB", "kty": "RSA", "alg": "RS256", "n": "pKybs0WaHU_y4cHxWbm8Wzj66HtcyFn7Fh3n" "-99qTXu5yNa30MRYIYfSDwe9JVc1JUoGw41yq2StdGBJ40HxichjE" "-Yopfu3B58Q" "lgJvToUbWD4gmTDGgMGxQxtv1En2yedaynQ73sDpIK-12JJDY55pvf" "-PCiSQ9OjxZLiVGKlClDus44_uv2370b9IN2JiEOF-a7JB" "qaTEYLPpXaoKWDSnJNonr79tL0T7iuJmO1l705oO3Y0TQ" "-INLY6jnKG_RpsvyvGNnwP9pMvcP1phKsWZ10ofuuhJGRp8IxQL9Rfz" "T87OvF0RBSO1U73h09YP-corWDsnKIi6TbzRpN5YDw", "kid": "abc", }
def test_construct(self, entity): token_service = entity.client_get("service", 'accesstoken') kb_rsa = KeyBundle(source='file://{}'.format( os.path.join(BASE_PATH, "data/keys/rsa.key")), fileformat='der') for key in kb_rsa: key.add_kid() _context = token_service.client_get("service_context") _context.keyjar.add_kb('', kb_rsa) _context.provider_info = { 'issuer': 'https://example.com/', 'token_endpoint': "https://example.com/token" } _context.registration_response = { 'token_endpoint_auth_signing_alg': 'RS256' } token_service.endpoint = "https://example.com/token" request = AccessTokenRequest() pkj = PrivateKeyJWT() http_args = pkj.construct(request, service=token_service, authn_endpoint='token_endpoint') assert http_args == {} cas = request["client_assertion"] _kj = KeyJar() _kj.add_kb(_context.client_id, kb_rsa) jso = JWT(key_jar=_kj).unpack(cas) assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"]) # assert _jwt.headers == {'alg': 'RS256'} assert jso['aud'] == [_context.provider_info['token_endpoint']]
def test_update_keyjar(): _path = full_path('jwk_private_key.json') kb = KeyBundle(source='file://{}'.format(_path)) kj = KeyJar() kj.add_kb('Alice', kb) update_keyjar(kj)
def test_client_claims_with_default(self): session_info = { "authn_req": AREQN, "sub": "sub", "authn_event": { "authn_info": "loa2", "authn_time": time.time(), "uid": "diana" }, } self.endpoint_context.cdb["client_1"]['id_token_claims'] = { "address": None } self.endpoint_context.idtoken.kwargs['default_claims'] = { "nickname": { "essential": True } } self.endpoint_context.idtoken.enable_claims_per_client = True req = {"client_id": "client_1"} _token = self.endpoint_context.idtoken.make(req, session_info) assert _token 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 "address" in res assert "nickname" in res
def verify(self, **kwargs): """ Verifies that an instance of this class adheres to the given restrictions. :param kwargs: A set of keyword arguments :return: True if it verifies OK otherwise False. """ super(MetadataStatement, self).verify(**kwargs) if "signing_keys" in self: if 'signing_keys_uri' in self: raise VerificationError( 'You can only have one of "signing_keys" and ' '"signing_keys_uri" in a metadata statement') else: # signing_keys MUST be a JWKS kj = KeyJar() try: kj.import_jwks(self['signing_keys'], '') except Exception: raise VerificationError('"signing_keys" not a proper JWKS') if "metadata_statements" in self and "metadata_statement_uris" in self: s = set(self['metadata_statements'].keys()) t = set(self['metadata_statement_uris'].keys()) if s.intersection(t): raise VerificationError( 'You should not have the same key in "metadata_statements" ' 'and in "metadata_statement_uris"') return True
def test_str(): kj = KeyJar() kj.add_kb("Alice", KeyBundle(JWK0["keys"])) desc = "{}".format(kj) _cont = json.loads(desc) assert set(_cont.keys()) == {"Alice"}
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_construct(self, services): _service = services['accesstoken'] kb_rsa = KeyBundle(source='file://{}'.format( os.path.join(BASE_PATH, "data/keys/rsa.key")), fileformat='der') for key in kb_rsa: key.add_kid() _service.service_context.keyjar.add_kb('', kb_rsa) _service.service_context.set( 'provider_info', { 'issuer': 'https://example.com/', 'token_endpoint': "https://example.com/token" }) services['accesstoken'].endpoint = "https://example.com/token" request = AccessTokenRequest() pkj = PrivateKeyJWT() http_args = pkj.construct(request, service=_service, algorithm="RS256", authn_endpoint='token_endpoint') assert http_args == {} cas = request["client_assertion"] _kj = KeyJar() _kj.add_kb(_service.service_context.get('client_id'), kb_rsa) jso = JWT(key_jar=_kj).unpack(cas) assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"]) # assert _jwt.headers == {'alg': 'RS256'} assert jso['aud'] == [ _service.service_context.get('provider_info')['token_endpoint'] ]
def test_client_secret_jwt(self, services): _service_context = services['accesstoken'].service_context _service_context.token_endpoint = "https://example.com/token" _service_context.set( 'provider_info', { 'issuer': 'https://example.com/', 'token_endpoint': "https://example.com/token" }) csj = ClientSecretJWT() request = AccessTokenRequest() csj.construct(request, service=services['accesstoken'], algorithm="HS256", authn_endpoint='userinfo') assert request["client_assertion_type"] == JWT_BEARER assert "client_assertion" in request cas = request["client_assertion"] _kj = KeyJar() _kj.add_symmetric(_service_context.get('client_id'), _service_context.get('client_secret'), usage=['sig']) jso = JWT(key_jar=_kj, sign_alg='HS256').unpack(cas) assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"]) _rj = JWS(alg='HS256') info = _rj.verify_compact( cas, _kj.get_signing_key(issuer_id=_service_context.get('client_id'))) assert _eq(info.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"]) assert info['aud'] == [_service_context.get('provider_info')['issuer']]
def test_example(self): _symkey = KC_SYM_S.get(alg2keytype("HS256")) csr = CheckSessionRequest(id_token=IDTOKEN.to_jwt( key=_symkey, algorithm="HS256", lifetime=300)) keyjar = KeyJar() keyjar.add_kb('', KC_SYM_S) with pytest.raises(ValueError): assert csr.verify(keyjar=keyjar)
class KeyBundle(key_bundle.KeyBundle): """ Extended :py:class:`oidcmsg.key_bundle.KeyBundle` class that supports signed JWKS uris. """ def __init__(self, keys=None, source="", cache_time=300, verify_ssl=True, file_format="jwk", keytype="RSA", keyusage=None, verify_keys=None): super(KeyBundle, self).__init__(keys=keys, source=source, cache_time=cache_time, verify_ssl=verify_ssl, fileformat=file_format, keytype=keytype, keyusage=keyusage) if verify_keys is not None: if isinstance(verify_keys, KeyJar): self.verify_keys = verify_keys else: self.verify_keys = KeyJar() self.verify_keys.import_jwks(verify_keys, '') def _parse_remote_response(self, response): """ Parse simple JWKS or signed JWKS from the HTTP response. :param response: HTTP response from the 'jwks_uri' or 'signed_jwks_uri' endpoint :return: response parsed as JSON or None """ # Check if the content type is the right one. try: if response.headers["Content-Type"] == 'application/json': logger.debug("Loaded JWKS: %s from %s" % (response.text, self.source)) try: return json.loads(response.text) except ValueError: return None elif response.headers["Content-Type"] == 'application/jwt': logger.debug("Signed JWKS: %s from %s" % (response.text, self.source)) _jws = factory(response.text) _resp = _jws.verify_compact( response.text, keys=self.verify_keys.get_signing_key()) return _resp else: logger.error('Wrong content type: {}'.format( response.headers['Content-Type'])) raise ValueError('Content-type mismatch') except KeyError: pass
def test_repr(): kj = KeyJar() kj['Alice'] = [KeyBundle(JWK0['keys'])] kj['Bob'] = [KeyBundle(JWK1['keys'])] kj['C'] = [KeyBundle(JWK2['keys'])] txt = kj.__repr__() assert "<KeyJar(issuers=[" in txt _d = eval(txt[16:-2]) assert set(_d) == {'Alice', 'Bob', 'C'}
def test_similar(): ISSUER = "xyzzy" kj = KeyJar() kb = KeyBundle(JWK2) kj.add_kb(issuer=ISSUER, kb=kb) keys1 = kj.get_issuer_keys(ISSUER) keys2 = kj[ISSUER].all_keys() assert keys1 == keys2
def keyjar(cls): """ Key jar, the place where you store all the keys """ keyjar = KeyJar() keys = cls.keys() jwks = {'keys': [key.serialize(private=True) for key in keys]} keyjar.import_jwks(jwks, issuer=getattr(settings, 'JWTAUTH_ISSUER', "")) return keyjar
def test_jwt_pack_and_unpack_unknown_key(): alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, sign_alg="RS256") payload = {"sub": "sub"} _jwt = alice.pack(payload=payload) kj = KeyJar() kj.add_kb(ALICE, KeyBundle()) bob = JWT(key_jar=kj, iss=BOB, allowed_sign_algs=["RS256"]) with pytest.raises(NoSuitableSigningKeys): info = bob.unpack(_jwt)
def decode_token(txt, attr_name='access_token', verify_sign=True): issuer = oidcop_app.srv_config['issuer'] jwks_path = oidcop_app.srv_config.conf['keys']['private_path'] jwks = json.loads(open(jwks_path).read()) key_jar = KeyJar() key_jar.import_jwks(jwks, issuer=issuer) msg = Message().from_jwt(txt, keyjar=key_jar, verify=verify_sign) return msg
def test_match_owner(): kj = KeyJar() kj['Alice'] = [KeyBundle(JWK0['keys'])] kj['Bob'] = [KeyBundle(JWK1['keys'])] kj['https://delphi.example.com/path'] = [KeyBundle(JWK2['keys'])] a = kj.match_owner('https://delphi.example.com') assert a == 'https://delphi.example.com/path' with pytest.raises(KeyError): kj.match_owner('https://example.com')
def test_items(self): ks = KeyJar() ks.add_kb( "", KeyBundle( [ {"kty": "oct", "key": "abcdefghijklmnop", "use": "sig"}, {"kty": "oct", "key": "ABCDEFGHIJKLMNOP", "use": "enc"}, ] ), ) ks.add_kb( "http://www.example.org", KeyBundle( [ {"kty": "oct", "key": "0123456789012345", "use": "sig"}, {"kty": "oct", "key": "1234567890123456", "use": "enc"}, ] ), ) ks.add_kb( "http://www.example.org", keybundle_from_local_file(RSAKEY, "der", ["ver", "sig"]), ) assert len(ks.items()) == 2
def test_get_enc_not_mine(self): ks = KeyJar() ks.add_kb( "", KeyBundle( [ {"kty": "oct", "key": "a1b2c3d4e5f6g7h8", "use": "sig"}, {"kty": "oct", "key": "a1b2c3d4e5f6g7h8", "use": "enc"}, ] ), ) ks.add_kb( "http://www.example.org/", KeyBundle( [ {"kty": "oct", "key": "1a2b3c4d5e6f7g8h", "use": "sig"}, {"kty": "oct", "key": "1a2b3c4d5e6f7g8h", "use": "enc"}, ] ), ) ks.add_kb( "http://www.example.org/", keybundle_from_local_file(RSAKEY, "der", ["ver", "sig"]), ) assert ks.get("enc", "oct", "http://www.example.org/")
def test_issuer_extra_slash(self): ks = KeyJar() ks.add_kb( "", KeyBundle( [ {"kty": "oct", "key": "abcdefghijklmnop", "use": "sig"}, {"kty": "oct", "key": "ABCDEFGHIJKLMNOP", "use": "enc"}, ] ), ) ks.add_kb( "http://www.example.org", KeyBundle( [ {"kty": "oct", "key": "0123456789012345", "use": "sig"}, {"kty": "oct", "key": "1234567890123456", "use": "enc"}, ] ), ) ks.add_kb( "http://www.example.org", keybundle_from_local_file(RSAKEY, "der", ["ver", "sig"]), ) assert ks.get("sig", "RSA", "http://www.example.org/")
def test_dump_json(): kj = KeyJar() kj.add_kb("Alice", KeyBundle(JWK0["keys"])) kj.add_kb("Bob", KeyBundle(JWK1["keys"])) kj.add_kb("C", KeyBundle(JWK2["keys"])) res = kj.dump() assert json.dumps(res)
def test_key_summary(): kj = KeyJar() kj.add_kb("Alice", KeyBundle(JWK0["keys"])) kj.add_kb("Bob", KeyBundle(JWK1["keys"])) kj.add_kb("C", KeyBundle(JWK2["keys"])) out = kj.key_summary("Alice") assert out
def test_with_jti(): _kj = KeyJar() _kj.add_symmetric(ALICE, 'hemligt ordsprak', usage=['sig']) alice = JWT(key_jar=_kj, iss=ALICE, sign_alg="HS256") alice.with_jti = True payload = {'sub': 'sub2'} _jwt = alice.pack(payload=payload) bob = JWT(key_jar=_kj, iss=BOB, sign_alg="HS256") info = bob.unpack(_jwt) assert 'jti' in info
def set_client_secret(self, val): """Set client secret.""" if not val: self._c_secret = "" else: self._c_secret = val # client uses it for signing # Server might also use it for signing which means the # client uses it for verifying server signatures if self.keyjar is None: self.keyjar = KeyJar() self.keyjar.add_symmetric("", str(val))
def test_with_jti(): _kj = KeyJar() _kj.add_symmetric(ALICE, "hemligt ordsprak", usage=["sig"]) alice = JWT(key_jar=_kj, iss=ALICE, sign_alg="HS256") alice.with_jti = True payload = {"sub": "sub2"} _jwt = alice.pack(payload=payload) bob = JWT(key_jar=_kj, iss=BOB, sign_alg="HS256") info = bob.unpack(_jwt) assert "jti" in info
def test_msg_cls(): _kj = KeyJar() _kj.add_symmetric(ALICE, "hemligt ordsprak", usage=["sig"]) alice = JWT(key_jar=_kj, iss=ALICE, sign_alg="HS256") payload = {"sub": "sub2"} _jwt = alice.pack(payload=payload) bob = JWT(key_jar=_kj, iss=BOB, sign_alg="HS256") bob.msg_cls = DummyMsg info = bob.unpack(_jwt) assert isinstance(info, DummyMsg)