def test_jwt_pack_and_unpack_with_lifetime(): alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, lifetime=600) payload = {'sub': 'sub'} _jwt = alice.pack(payload=payload) bob = JWT(key_jar=BOB_KEY_JAR, iss=BOB) info = bob.unpack(_jwt) assert set(info.keys()) == {'iat', 'iss', 'sub', 'exp'}
def test_jwt_pack_encrypt(): alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE) payload = {'sub': 'sub', 'aud': BOB} _jwt = alice.pack(payload=payload, encrypt=True, recv=BOB) bob = JWT(key_jar=BOB_KEY_JAR, iss=BOB) info = bob.unpack(_jwt) assert set(info.keys()) == {'iat', 'iss', 'sub', 'aud'}
def test_jwt_pack_and_unpack(): alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, sign_alg='RS256') payload = {'sub': 'sub'} _jwt = alice.pack(payload=payload) bob = JWT(key_jar=BOB_KEY_JAR, iss=BOB, allowed_sign_algs=["RS256"]) info = bob.unpack(_jwt) assert set(info.keys()) == {'iat', 'iss', 'sub'}
def test_jwt_pack_encrypt(): alice = JWT(own_keys=ALICE_KEYS, iss=ALICE, rec_keys={BOB: BOB_PUB_KEYS}) payload = {'sub': 'sub', 'aud': BOB} _jwt = alice.pack(payload=payload, encrypt=True, recv=BOB) bob = JWT(own_keys=BOB_KEYS, iss=BOB, rec_keys={ALICE: ALICE_PUB_KEYS}) info = bob.unpack(_jwt) assert set(info.keys()) == {'iat', 'iss', 'sub', 'kid', 'aud'}
def test_jwt_pack_unpack_sym(): _sym_key = SYMKey(key='hemligt ord', use='sig') alice = JWT(own_keys=[_sym_key], iss=ALICE, sign_alg="HS256") payload = {'sub': 'sub2'} _jwt = alice.pack(payload=payload) bob = JWT(own_keys=None, iss=BOB, rec_keys={ALICE: [_sym_key]}) info = bob.unpack(_jwt) assert info
def test_jwt_pack_and_unpack_with_lifetime(): alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, lifetime=600) payload = {"sub": "sub"} _jwt = alice.pack(payload=payload) bob = JWT(key_jar=BOB_KEY_JAR, iss=BOB) info = bob.unpack(_jwt) assert set(info.keys()) == {"iat", "iss", "sub", "exp"}
def test_jwt_pack_and_unpack_with_alg(): alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, sign_alg="RS384") payload = {"sub": "sub"} _jwt = alice.pack(payload=payload) bob = JWT(BOB_KEY_JAR, sign_alg="RS384") info = bob.unpack(_jwt) assert set(info.keys()) == {"iat", "iss", "sub"}
def test_jwt_pack_encrypt(): alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE) payload = {"sub": "sub", "aud": BOB} _jwt = alice.pack(payload=payload, encrypt=True, recv=BOB) bob = JWT(key_jar=BOB_KEY_JAR, iss=BOB) info = bob.unpack(_jwt) assert set(info.keys()) == {"iat", "iss", "sub", "aud"}
def test_jwt_pack_and_unpack(): alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, sign_alg="RS256") payload = {"sub": "sub"} _jwt = alice.pack(payload=payload) bob = JWT(key_jar=BOB_KEY_JAR, iss=BOB, allowed_sign_algs=["RS256"]) info = bob.unpack(_jwt) assert set(info.keys()) == {"iat", "iss", "sub"}
def test_jwt_pack_and_unpack_unknown_issuer(): alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, sign_alg="RS256") payload = {"sub": "sub"} _jwt = alice.pack(payload=payload) kj = KeyJar() bob = JWT(key_jar=kj, iss=BOB, allowed_sign_algs=["RS256"]) with pytest.raises(IssuerNotFound): info = bob.unpack(_jwt)
def test_jwt_pack_and_unpack_with_lifetime(): alice = JWT(own_keys=ALICE_KEYS, iss=ALICE, lifetime=600) payload = {'sub': 'sub'} _jwt = alice.pack(payload=payload) bob = JWT(own_keys=BOB_KEYS, iss=BOB, rec_keys={ALICE: ALICE_PUB_KEYS}) info = bob.unpack(_jwt) assert set(info.keys()) == {'iat', 'iss', 'sub', 'kid', 'exp', 'aud'}
def test_jwt_pack_and_unpack_with_alg(): alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, sign_alg='RS384') payload = {'sub': 'sub'} _jwt = alice.pack(payload=payload) bob = JWT(BOB_KEY_JAR, sign_alg='RS384') info = bob.unpack(_jwt) assert set(info.keys()) == {'iat', 'iss', 'sub'}
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 test_jwt_pack_unpack_sym(): _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) _kj = KeyJar() _kj.add_symmetric(ALICE, 'hemligt ordsprak', usage=['sig']) bob = JWT(key_jar=_kj, iss=BOB, sign_alg="HS256") info = bob.unpack(_jwt) assert 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)
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_unpack_aggregated_response_missing_keys(self): claims = { "address": { "street_address": "1234 Hollywood Blvd.", "locality": "Los Angeles", "region": "CA", "postal_code": "90210", "country": "US" }, "phone_number": "+1 (555) 123-4567" } _keyjar = build_keyjar(KEYSPEC) srv = JWT(_keyjar, iss=ISS, sign_alg='ES256') _jwt = srv.pack(payload=claims) resp = OpenIDSchema(sub='diana', given_name='Diana', family_name='krall', _claim_names={ 'address': 'src1', 'phone_number': 'src1' }, _claim_sources={'src1': {'JWT': _jwt}}) _resp = self.service.parse_response(resp.to_json(), state='abcde') assert _resp
def test_private_key_jwt_reusage_other_endpoint(): # Own dynamic keys client_keyjar = build_keyjar(KEYDEFS) # The servers keys client_keyjar[conf["issuer"]] = KEYJAR.issuer_keys[""] _jwks = client_keyjar.export_jwks() endpoint_context.keyjar.import_jwks(_jwks, client_id) _jwt = JWT(client_keyjar, iss=client_id, sign_alg="RS256") _jwt.with_jti = True _assertion = _jwt.pack( {"aud": [endpoint_context.endpoint["token"].full_path]}) request = { "client_assertion": _assertion, "client_assertion_type": JWT_BEARER } # This should be OK PrivateKeyJWT(endpoint_context).verify(request, endpoint="token") # This should NOT be OK with pytest.raises(NotForMe): PrivateKeyJWT(endpoint_context).verify(request, endpoint="authorization") # This should NOT be OK with pytest.raises(MultipleUsage): PrivateKeyJWT(endpoint_context).verify(request, endpoint="token")
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 test_private_key_jwt_auth_endpoint(self): # Own dynamic keys client_keyjar = build_keyjar(KEYDEFS) # The servers keys client_keyjar.import_jwks(KEYJAR.export_jwks(private=True), CONF["issuer"]) _jwks = client_keyjar.export_jwks() self.method.server_get("endpoint_context").keyjar.import_jwks( _jwks, client_id) _jwt = JWT(client_keyjar, iss=client_id, sign_alg="RS256") _jwt.with_jti = True _assertion = _jwt.pack({ "aud": [self.method.server_get("endpoint", "authorization").full_path] }) request = { "client_assertion": _assertion, "client_assertion_type": JWT_BEARER } assert self.method.is_usable(request=request) authn_info = self.method.verify( request=request, endpoint=self.method.server_get("endpoint", "authorization"), ) assert authn_info["client_id"] == client_id assert "jwt" in authn_info
def test_verify_client_jws_authn_method(self): client_keyjar = KeyJar() client_keyjar.import_jwks(KEYJAR.export_jwks(private=True), CONF["issuer"]) # The only own key the client has a this point client_keyjar.add_symmetric("", client_secret, ["sig"]) _jwt = JWT(client_keyjar, iss=client_id, sign_alg="HS256") # Audience is OP issuer ID aud = "{}token".format(CONF["issuer"]) # aud == Token endpoint _assertion = _jwt.pack({"aud": [aud]}) request = { "client_assertion": _assertion, "client_assertion_type": JWT_BEARER } http_info = {"headers": {}} res = verify_client( self.endpoint_context, request, http_info=http_info, endpoint=self.server.server_get("endpoint", "token"), ) assert res["method"] == "client_secret_jwt" assert res["client_id"] == "client_id"
def verify(self, request, **kwargs): _jwt = JWT(self.endpoint_context.keyjar) try: ca_jwt = _jwt.unpack(request["client_assertion"]) except (Invalid, MissingKey, BadSignature) as err: logger.info("%s" % sanitize(err)) raise AuthnFailure("Could not verify client_assertion.") try: logger.debug("authntoken: %s" % sanitize(ca_jwt.to_dict())) except AttributeError: logger.debug("authntoken: %s" % sanitize(ca_jwt)) request[verified_claim_name("client_assertion")] = ca_jwt try: client_id = kwargs["client_id"] except KeyError: client_id = ca_jwt["iss"] # I should be among the audience # could be either my issuer id or the token endpoint if self.endpoint_context.issuer in ca_jwt["aud"]: pass elif self.endpoint_context.endpoint["token"].full_path in ca_jwt[ "aud"]: pass else: raise NotForMe("Not for me!") return {"client_id": client_id, "jwt": ca_jwt}
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 do_back_channel_logout(self, cinfo, sid): """ :param cinfo: Client information :param sid: The session ID :return: Tuple with logout URI and signed logout token """ _context = self.server_get("endpoint_context") try: back_channel_logout_uri = cinfo["backchannel_logout_uri"] except KeyError: return None # Create the logout token # always include sub and sid so I don't check for # backchannel_logout_session_required enc_msg = self._encrypt_sid(sid) payload = {"sid": enc_msg, "events": {BACK_CHANNEL_LOGOUT_EVENT: {}}} try: alg = cinfo["id_token_signed_response_alg"] except KeyError: alg = _context.provider_info["id_token_signing_alg_values_supported"][0] _jws = JWT(_context.keyjar, iss=_context.issuer, lifetime=86400, sign_alg=alg) _jws.with_jti = True _logout_token = _jws.pack(payload=payload, recv=cinfo["client_id"]) return back_channel_logout_uri, _logout_token
def make_openid_request(arq, keys, issuer, request_object_signing_alg, recv, with_jti=False, lifetime=0): """ Construct the JWT to be passed by value (the request parameter) or by reference (request_uri). The request will be signed :param arq: The Authorization request :param keys: Keys to use for signing/encrypting. A KeyJar instance :param issuer: Who is signing this JSON Web Token :param request_object_signing_alg: Which signing algorithm to use :param recv: The intended receiver of the request :param with_jti: Whether a JTI should be included in the JWT. :param lifetime: How long the JWT is expect to be live. :return: JWT encoded OpenID request """ _jwt = JWT(key_jar=keys, iss=issuer, sign_alg=request_object_signing_alg) if with_jti: _jwt.with_jti = True if lifetime: _jwt.lifetime = lifetime return _jwt.pack(arq.to_dict(), owner=issuer, recv=recv)
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_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_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_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_client_secret_jwt(self, client): _ci = client.client_info _ci.token_endpoint = "https://example.com/token" _ci.provider_info = { 'issuer': 'https://example.com/', 'token_endpoint': "https://example.com/token" } csj = ClientSecretJWT() request = AccessTokenRequest() csj.construct(request, cli_info=client.client_info, algorithm="HS256", authn_endpoint='userinfo') assert request["client_assertion_type"] == JWT_BEARER assert "client_assertion" in request cas = request["client_assertion"] _skey = [SYMKey(k=b64e(as_bytes(_ci.client_secret)), use='sig')] jso = JWT(rec_keys={client.client_id: _skey}).unpack(cas) assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"]) _rj = JWS() info = _rj.verify_compact( cas, [SYMKey(k=b64e(as_bytes(_ci.client_secret)))]) assert _eq(info.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"]) assert info['aud'] == [_ci.provider_info['issuer']]