def test_verify_id_token_missing_c_hash(): code = 'AccessCode1' idt = IdToken(**{ "sub": "553df2bcf909104751cfd8b2", "aud": [ "5542958437706128204e0000", "554295ce3770612820620000" ], "auth_time": 1441364872, "azp": "554295ce3770612820620000", }) kj = KeyJar() kj.add_symmetric("", 'dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ', ['sig']) kj.add_symmetric("https://sso.qa.7pass.ctf.prosiebensat1.com", 'dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ', ['sig']) packer = JWT(kj, sign_alg='HS256', iss="https://sso.qa.7pass.ctf.prosiebensat1.com", lifetime=3600) _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(code=code, id_token=_jws) with pytest.raises(MissingRequiredAttribute): verify_id_token(msg, check_hash=True, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000")
def test_verify_id_token_at_hash_and_chash(): token = 'AccessTokenWhichCouldBeASignedJWT' at_hash = left_hash(token) code = 'AccessCode1' c_hash = left_hash(code) idt = IdToken(**{ "sub": "553df2bcf909104751cfd8b2", "aud": [ "5542958437706128204e0000", "554295ce3770612820620000" ], "auth_time": 1441364872, "azp": "554295ce3770612820620000", "at_hash": at_hash, 'c_hash': c_hash }) kj = KeyJar() kj.add_symmetric("", 'dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ', ['sig']) kj.add_symmetric("https://sso.qa.7pass.ctf.prosiebensat1.com", 'dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ', ['sig']) packer = JWT(kj, sign_alg='HS256', iss="https://sso.qa.7pass.ctf.prosiebensat1.com", lifetime=3600) _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(access_token=token, id_token=_jws, code=code) verify_id_token(msg, check_hash=True, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000")
def test_verify_id_token_at_hash_fail(): token = 'AccessTokenWhichCouldBeASignedJWT' token2 = 'ACompletelyOtherAccessToken' lhsh = left_hash(token) idt = IdToken(**{ "sub": "553df2bcf909104751cfd8b2", "aud": [ "5542958437706128204e0000", "554295ce3770612820620000" ], "auth_time": 1441364872, "azp": "554295ce3770612820620000", "at_hash": lhsh }) kj = KeyJar() kj.add_symmetric("", 'dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ', ['sig']) kj.add_symmetric("https://sso.qa.7pass.ctf.prosiebensat1.com", 'dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ', ['sig']) packer = JWT(kj, sign_alg='HS256', iss="https://sso.qa.7pass.ctf.prosiebensat1.com", lifetime=3600) _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(access_token=token2, id_token=_jws) with pytest.raises(AtHashError): verify_id_token(msg, check_hash=True, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000")
def create_access_token(self, key_thumbprint): # creating the access_token jwt_constructor = JWT(self.keyjar, iss=self.me) # Audience is myself return jwt_constructor.pack(kid="abc", cnf={"kid": key_thumbprint}, aud=self.me)
def test_jwt_pack_and_unpack(): srv = JWT(keyjar, iss=issuer) _jwt = srv.pack(sub="sub") info = srv.unpack(_jwt) assert _eq(info.keys(), ["jti", "iat", "exp", "iss", "sub", "kid"])
def __call__(self, req, **kwargs): """ :param req: Original metadata statement as a :py:class:`MetadataStatement` instance :param keyjar: KeyJar in which the necessary keys should reside :param iss: Issuer ID :param alg: Which signing algorithm to use :param kwargs: Additional metadata statement attribute values :return: A JWT """ iss = self.iss keyjar = self.signing_keys # Own copy _metadata = copy.deepcopy(req) if self.add_ons: _metadata.update(self.add_ons) _jwt = JWT(keyjar, iss=iss, msgtype=_metadata.__class__, lifetime=self.lifetime) _jwt.sign_alg = self.alg if iss in keyjar.issuer_keys: owner = iss else: owner = '' if kwargs: return _jwt.pack(cls_instance=_metadata, owner=owner, **kwargs) else: return _jwt.pack(cls_instance=_metadata, owner=owner)
def test_jwt_pack_and_unpack(): srv = JWT(keyjar, iss=issuer) _jwt = srv.pack(sub='sub') info = srv.unpack(_jwt) assert _eq(info.keys(), ['jti', 'iat', 'exp', 'iss', 'sub'])
def test_verify_token_encrypted_no_key(): idt = IdToken( sub="553df2bcf909104751cfd8b2", aud=["5542958437706128204e0000", "554295ce3770612820620000"], auth_time=1441364872, azp="554295ce3770612820620000", ) kj = KeyJar() kb = KeyBundle() kb.do_local_der( os.path.join(os.path.dirname(__file__), "data", "keys", "cert.key"), "some", ["enc", "sig"], ) kj.add_kb("", kb) kj.add_kb("https://sso.qa.7pass.ctf.prosiebensat1.com", kb) packer = JWT( kj, lifetime=3600, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", encrypt=True, ) _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(id_token=_jws) # Do not pass they keyjar with keys with pytest.raises(VerificationError): verify_id_token( msg, keyjar=KeyJar(), iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000", )
def test_verify_id_token_missing_c_hash(): code = "AccessCode1" idt = IdToken( **{ "sub": "553df2bcf909104751cfd8b2", "aud": ["5542958437706128204e0000", "554295ce3770612820620000"], "auth_time": 1441364872, "azp": "554295ce3770612820620000", }) kj = KeyJar() kj.add_symmetric("", "dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ", ["sig"]) kj.add_symmetric( "https://sso.qa.7pass.ctf.prosiebensat1.com", "dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ", ["sig"], ) packer = JWT( kj, sign_alg="HS256", iss="https://sso.qa.7pass.ctf.prosiebensat1.com", lifetime=3600, ) _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(code=code, id_token=_jws) with pytest.raises(MissingRequiredAttribute): verify_id_token( msg, check_hash=True, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000", )
def test_verify_id_token_at_hash(): token = "AccessTokenWhichCouldBeASignedJWT" lhsh = left_hash(token) idt = IdToken( **{ "sub": "553df2bcf909104751cfd8b2", "aud": ["5542958437706128204e0000", "554295ce3770612820620000"], "auth_time": 1441364872, "azp": "554295ce3770612820620000", "at_hash": lhsh, }) kj = KeyJar() kj.add_symmetric("", "dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ", ["sig"]) kj.add_symmetric( "https://sso.qa.7pass.ctf.prosiebensat1.com", "dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ", ["sig"], ) packer = JWT( kj, sign_alg="HS256", iss="https://sso.qa.7pass.ctf.prosiebensat1.com", lifetime=3600, ) _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(access_token=token, id_token=_jws) verify_id_token( msg, check_hash=True, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000", )
def test_verify_id_token_mismatch_aud_azp(): idt = IdToken( **{ "sub": "553df2bcf909104751cfd8b2", "aud": ["5542958437706128204e0000", "554295ce3770612820620000"], "auth_time": 1441364872, "azp": "aaaaaaaaaaaaaaaaaaaa", }) kj = KeyJar() kj.add_symmetric("", "dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ", ["sig"]) kj.add_symmetric( "https://sso.qa.7pass.ctf.prosiebensat1.com", "dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ", ["sig"], ) packer = JWT(kj, sign_alg="HS256", iss="https://example.com/as", lifetime=3600) _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(id_token=_jws) with pytest.raises(ValueError): verify_id_token( msg, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="aaaaaaaaaaaaaaaaaaaa", )
def test_verify_token_encrypted(): idt = IdToken( sub="553df2bcf909104751cfd8b2", aud=["5542958437706128204e0000", "554295ce3770612820620000"], auth_time=1441364872, azp="554295ce3770612820620000", ) kj = KeyJar() kb = KeyBundle() kb.do_local_der( os.path.join(os.path.dirname(__file__), "data", "keys", "cert.key"), "some", ["enc", "sig"], ) kj.add_kb("", kb) kj.add_kb("https://sso.qa.7pass.ctf.prosiebensat1.com", kb) packer = JWT( kj, lifetime=3600, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", encrypt=True, ) _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(id_token=_jws) vidt = verify_id_token( msg, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000", ) assert vidt assert vidt.jwe_header == {"enc": "A128CBC-HS256", "alg": "RSA1_5", "cty": "JWT"}
def pack_metadata_statement(self, metadata, keyjar=None, iss=None, alg='', **kwargs): """ :param metas: Original metadata statement as a MetadataStatement instance :param keyjar: KeyJar in which the necessary keys should reside :param alg: Which signing algorithm to use :param kwargs: Additional metadata statement attribute values :return: A JWT """ if iss is None: iss = self.iss if keyjar is None: keyjar = self.keyjar # Own copy _metadata = copy.deepcopy(metadata) _metadata.update(kwargs) _jwt = JWT(keyjar, iss=iss, msgtype=_metadata.__class__) if alg: _jwt.sign_alg = alg return _jwt.pack(cls_instance=_metadata)
def test_jwt_pack_and_unpack(): srv = JWT(keyjar, iss=issuer) _jwt = srv.pack(sub='sub') info = srv.unpack(_jwt) assert _eq(info.keys(), ['jti', 'iat', 'exp', 'iss', 'sub', 'kid'])
def token_introspection(self, token): jwt_constructor = JWT(self.keyjar, iss=self.me) res = jwt_constructor.unpack(token) tir = TokenIntrospectionResponse(active=True) tir["key"] = json.dumps(self.thumbprint2key[res["cnf"]["kid"]]) return tir
def token_introspection(self, token): jwt_constructor = JWT(self.keyjar, iss=self.me) res = jwt_constructor.unpack(token) tir = TokenIntrospectionResponse(active=True) tir['key'] = json.dumps(self.thumbprint2key[res['cnf']['kid']]) return tir
def __init__(self, typ, keyjar, lifetime, **kwargs): self.type = typ JWT.__init__(self, keyjar, lifetime=lifetime, msgtype=TokenAssertion, **kwargs) Token.__init__(self, typ, lifetime=lifetime, **kwargs) self.db = {} self.session_info = {} self.exp_args = ['sinfo']
def __init__(self, typ, keyjar, lt_pattern=None, **kwargs): self.type = typ JWT.__init__(self, keyjar, msgtype=TokenAssertion, **kwargs) Token.__init__(self, typ, **kwargs) self.lt_pattern = lt_pattern or {} self.db = {} self.session_info = {'': 600} self.exp_args = ['sinfo']
def __init__(self, typ, keyjar, lt_pattern=None, extra_claims=None, **kwargs): self.type = typ JWT.__init__(self, keyjar, msgtype=TokenAssertion, **kwargs) Token.__init__(self, typ, **kwargs) self.lt_pattern = lt_pattern or {} self.db = {} self.session_info = {"": 600} self.exp_args = ["sinfo"] self.extra_claims = extra_claims or {}
def create_signed_bundle(self, sign_alg='RS256', iss_list=None): """ Create a signed JWT containing a dictionary with Issuer IDs as keys and JWKSs as values :param sign_alg: Which algorithm to use when signing the JWT :return: A signed JWT """ data = json.dumps(self.dict(iss_list)) _jwt = JWT(self.sign_keys, iss=self.iss, sign_alg=sign_alg) return _jwt.pack(bundle=data)
def verify_signed_bundle(signed_bundle, ver_keys): """ :param signed_bundle: A signed JWT where the body is a JWKS bundle :param ver_keys: Keys that can be used to verify signatures of the signed_bundle as a KeyJar. :return: The bundle or None """ _jwt = JWT(ver_keys) return _jwt.unpack(signed_bundle)
def test_logout_with_sub(self): # Simulate an authorization sid, request_location = self.consumer.begin("openid", "code", path="https://example.com") resp = self.provider.authorization_endpoint(request=request_location) part = self.consumer.parse_authz(resp.message) assert isinstance(part, tuple) aresp = part[0] assert aresp assert self.consumer.sdb[sid]["issuer"] == self.provider.baseurl # Simulate an accesstoken request areq = AccessTokenRequest( code=aresp["code"], client_id=CLIENT_ID, redirect_uri="http://example.com/authz", client_secret=self.consumer.client_secret, grant_type="authorization_code", ) token_resp = self.provider.code_grant_type(areq) tresp = self.consumer.parse_response(AccessTokenResponse, token_resp.message, sformat="json") # Now, for the backchannel logout. This happens on the OP logout_info = { "sub": tresp["id_token"]["sub"], "events": { BACK_CHANNEL_LOGOUT_EVENT: {} }, } alg = "RS256" _jws = JWT( self.provider.keyjar, iss=self.provider.baseurl, lifetime=86400, sign_alg=alg, ) logout_token = _jws.pack(aud=CLIENT_ID, **logout_info) # The logout request that gets sent to the RP request = BackChannelLogoutRequest(logout_token=logout_token) # The RP evaluates the request. If everything is OK a session ID (== original state # value) is returned. _sid = self.consumer.backchannel_logout(request_args=request.to_dict()) assert _sid == sid # Test other coding _sid = self.consumer.backchannel_logout( request=request.to_urlencoded()) assert _sid == sid
def test_unpack_verify_key(self): srv = JWT(keyjar, iss=issuer) _jwt = srv.pack(sub="sub") # Remove the signing key from keyjar keyjar.remove_key("", "RSA", "") # And add it back as verify kb = keybundle_from_local_file(os.path.join(BASE_PATH, "cert.key"), "RSA", ["ver"]) # keybundle_from_local_file doesn'assign kid, so assign manually kb._keys[0].kid = kidd["sig"]["RSA"] keyjar.add_kb("", kb) info = srv.unpack(_jwt) assert info["sub"] == "sub"
def verify_signed_bundle(signed_bundle, ver_keys): """ Verify the signature of a signed JWT. :param signed_bundle: A signed JWT where the body is a JWKS bundle :param ver_keys: Keys that can be used to verify signatures of the signed_bundle. :type ver_keys: oic.utils.KeyJar instance :return: The bundle or None """ _jwt = JWT(ver_keys) return _jwt.unpack(signed_bundle)
def create_signed_bundle(self, sign_alg='RS256', iss_list=None): """ Create a signed JWT containing a dictionary with Issuer IDs as keys and JWKSs as values. If iss_list is empty all then all issuers are included. :param sign_alg: Which algorithm to use when signing the JWT :param iss_list: A list of issuer IDs who's keys should be included in the signed bundle. :return: A signed JWT """ data = self.dict(iss_list) _jwt = JWT(self.sign_keys, iss=self.iss, sign_alg=sign_alg) return _jwt.pack(bundle=data)
def pack_metadata_statement(self, metadata, keyjar=None, iss=None, alg='', jwt_args=None, lifetime=-1, **kwargs): """ Given a MetadataStatement instance create a signed JWT. :param metadata: Original metadata statement as a MetadataStatement instance :param keyjar: KeyJar in which the necessary signing keys should reside :param iss: Issuer ID :param alg: Which signing algorithm to use :param jwt_args: Additional JWT attribute values :param lifetime: Lifetime of the signed JWT :param kwargs: Additional metadata statement attribute values :return: A JWT """ if iss is None: iss = self.iss if keyjar is None: keyjar = self.keyjar if lifetime == -1: lifetime = self.lifetime # Own copy _metadata = copy.deepcopy(metadata) _metadata.update(kwargs) _jwt = JWT(keyjar, iss=iss, msgtype=_metadata.__class__, lifetime=lifetime) if alg: _jwt.sign_alg = alg if iss in keyjar.keys(): owner = iss else: owner = '' if jwt_args: return _jwt.pack(cls_instance=_metadata, owner=owner, **jwt_args) else: return _jwt.pack(cls_instance=_metadata, owner=owner)
def make_software_statement(keyjar, iss, **kwargs): params = list(inspect.signature(JWT.__init__).parameters.keys()) params.remove('self') args = {} for param in params: try: args[param] = kwargs[param] except KeyError: pass else: del kwargs[param] _jwt = JWT(keyjar, msgtype=SoftwareStatement, iss=iss, **args) return _jwt.pack(**kwargs)
def __init__(self, typ, keyjar, lt_pattern=None, extra_claims=None, **kwargs): self.type = typ Token.__init__(self, typ, **kwargs) kwargs.pop("token_storage", None) JWT.__init__(self, keyjar, msgtype=TokenAssertion, **kwargs) self.lt_pattern = lt_pattern or {} self.db = {} # type: Dict[str,str] self.session_info = {"": 600} self.exp_args = ["sinfo"] self.extra_claims = extra_claims or {}
def make_software_statement(keyjar, iss, **kwargs): params = list(inspect.signature(JWT.__init__).parameters.keys()) params.remove("self") args = {} for param in params: try: args[param] = kwargs[param] except KeyError: pass else: del kwargs[param] _jwt = JWT(keyjar, msgtype=SoftwareStatement, iss=iss, **args) return _jwt.pack(**kwargs)
def do_authentication(self, **kwargs) -> str: if not self._client: logger.debug('No OpenID Connect Client configured') raise AuthenticationFailed() token: str = kwargs.get('token', None) if not token: logger.debug('No JWT token provided') raise AuthenticationFailed() try: jwt = JWT(keyjar=self._client.keyjar).unpack(token) self._client.verify_id_token(jwt, authn_req={}) username = jwt['name'] except Exception as ex: logger.info(str(ex)) raise AuthenticationFailed() # # Assuming the token is valid, if we can't find the user, we # add them as an admin # with dbm.session() as session: if not AuthManager(session=session).get_principal(username): self._create_admin(session, username) return username
def pack_metadata_statement(metadata, keyjar, iss, alg='', **kwargs): """ :param metas: Original metadata statement as a MetadataStatement instance :param keyjar: KeyJar in which the necessary keys should reside :param alg: Which signing algorithm to use :param kwargs: Additional metadata statement attribute values :return: A JWT """ metadata.update(kwargs) _jwt = JWT(keyjar, iss=iss, msgtype=metadata.__class__) if alg: _jwt.sign_alg = alg return _jwt.pack(cls_instance=metadata)
def test_verify_token_encrypted_no_key(): idt = IdToken(sub='553df2bcf909104751cfd8b2', aud=['5542958437706128204e0000', '554295ce3770612820620000'], auth_time=1441364872, azp='554295ce3770612820620000') kj = KeyJar() kb = KeyBundle() kb.do_local_der(os.path.join(os.path.dirname(__file__), 'data', 'keys', 'cert.key'), 'some', ['enc', 'sig']) kj.add_kb('', kb) kj.add_kb('https://sso.qa.7pass.ctf.prosiebensat1.com', kb) packer = JWT(kj, lifetime=3600, iss='https://sso.qa.7pass.ctf.prosiebensat1.com', encrypt=True) _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(id_token=_jws) # Do not pass they keyjar with keys with pytest.raises(VerificationError): verify_id_token(msg, keyjar=KeyJar(), iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000")
def test_verify_token_encrypted(): idt = IdToken(sub='553df2bcf909104751cfd8b2', aud=['5542958437706128204e0000', '554295ce3770612820620000'], auth_time=1441364872, azp='554295ce3770612820620000') kj = KeyJar() kb = KeyBundle() kb.do_local_der(os.path.join(os.path.dirname(__file__), 'data', 'keys', 'cert.key'), 'some', ['enc', 'sig']) kj.add_kb('', kb) kj.add_kb('https://sso.qa.7pass.ctf.prosiebensat1.com', kb) packer = JWT(kj, lifetime=3600, iss='https://sso.qa.7pass.ctf.prosiebensat1.com', encrypt=True) _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(id_token=_jws) vidt = verify_id_token(msg, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000") assert vidt assert vidt.jwe_header == {'enc': 'A128CBC-HS256', 'alg': 'RSA1_5', 'cty': 'JWT'}
def test_not_for_me(self): _sub = "sub" logout_info = {"sub": _sub, "events": {BACK_CHANNEL_LOGOUT_EVENT: {}}} alg = "RS256" _jws = JWT( self.provider.keyjar, iss=self.provider.baseurl, lifetime=86400, sign_alg=alg, ) logout_token = _jws.pack(aud="someone", **logout_info) # The logout request that gets sent to the RP request = BackChannelLogoutRequest(logout_token=logout_token) with pytest.raises(MessageException): self.consumer.backchannel_logout(request_args=request.to_dict())
def self_sign_jwks(keyjar, iss, kid='', lifetime=3600): """ Create a signed JWT containing a JWKS. The JWT is signed by one of the keys in the JWKS. :param keyjar: A KeyJar instance with at least one private signing key :param iss: issuer of the JWT, should be the owner of the keys :param kid: A key ID if a special key should be used otherwise one is picked at random. :param lifetime: The lifetime of the signed JWT :return: A signed JWT """ # _json = json.dumps(jwks) _jwt = JWT(keyjar, iss=iss, lifetime=lifetime) jwks = keyjar.export_jwks(issuer=iss) return _jwt.pack(owner=iss, jwks=jwks, kid=kid)
def test_rpt(): kb = KeyBundle(JWKS["keys"]) kj = KeyJar() kj.issuer_keys[''] = [kb] token_factory = JWT(kj, lifetime=3600, iss=issuer) client_id = 'https://example.com/client' ressrv_id = 'https://rs.example.org/' rpt = token_factory.pack(kid='sign1', aud=[client_id, ressrv_id], azp=ressrv_id, type='rpt') _rj = jws.factory(rpt) jti = json.loads(_rj.jwt.part[1].decode('utf8'))['jti'] info = token_factory.unpack(rpt) assert set(info.keys()), {'aud', 'azp', 'ext', 'iat', 'iss', 'jti', 'kid', 'type'}
def test_logout_with_none(self): # Now for the backchannel logout. This happens on the OP logout_info = LogoutToken(events={BACK_CHANNEL_LOGOUT_EVENT: {}}) alg = "RS256" _jws = JWT( self.provider.keyjar, iss=self.provider.baseurl, lifetime=86400, sign_alg=alg, ) logout_token = _jws.pack(aud=CLIENT_ID, **logout_info) # The logout request that gets sent to the RP request = BackChannelLogoutRequest(logout_token=logout_token) # The RP evaluates the request. If everything is OK a session ID (== original state # value) is returned. with pytest.raises(MessageException): self.consumer.backchannel_logout(request_args=request.to_dict())
def test_rpt(): kb = KeyBundle(JWKS["keys"]) kj = KeyJar() kj.issuer_keys[''] = [kb] token_factory = JWT(kj, lifetime=3600, iss=issuer) client_id = 'https://example.com/client' ressrv_id = 'https://rs.example.org/' rpt = token_factory.pack(kid='sign1', aud=[client_id, ressrv_id], azp=ressrv_id, type='rpt') _rj = jws.factory(rpt) jti = json.loads(_rj.jwt.part[1].decode('utf8'))['jti'] info = token_factory.unpack(rpt) assert set(info.keys()), { 'aud', 'azp', 'ext', 'iat', 'iss', 'jti', 'kid', 'type' }
def request_signed_by_signing_keys(keyjar, msreq, iss, lifetime, kid=''): """ A metadata statement signing request with 'signing_keys' signed by one of the keys in 'signing_keys'. :param keyjar: A KeyJar instance with the private signing key :param msreq: Metadata statement signing request. A MetadataStatement instance. :param iss: Issuer of the signing request also the owner of the signing keys. :return: Signed JWT where the body is the metadata statement """ try: jwks_to_keyjar(msreq['signing_keys'], iss) except KeyError: jwks = keyjar.export_jwks(issuer=iss) msreq['signing_keys'] = jwks _jwt = JWT(keyjar, iss=iss, lifetime=lifetime) return _jwt.pack(owner=iss, kid=kid, **msreq.to_dict())
def test_verify_id_token_iss_not_in_keyjar(): idt = IdToken(**{ "sub": "553df2bcf909104751cfd8b2", "aud": [ "5542958437706128204e0000", "554295ce3770612820620000" ], "auth_time": 1441364872, "azp": "554295ce3770612820620000", }) kj = KeyJar() kj.add_symmetric("", 'dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ', ['sig']) kj.add_symmetric("https://sso.qa.7pass.ctf.prosiebensat1.com", 'dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ', ['sig']) packer = JWT(kj, sign_alg='HS256', lifetime=3600, iss='https://example.com/op') _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(id_token=_jws) with pytest.raises(ValueError): verify_id_token(msg, check_hash=True, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000")
def __init__(self, keyjar, rpt_lifetime, iss, ressrv_id, rsr_path, ticket_lifetime=3600): # database with all permission requests self.permission_requests = PermissionRequests() # database with all authorization decisions self.authz_db = AuthzDB() # database with all registered permissions self.permit = Permission() # database with all the registered resource sets self.resource_set = MemResourceSetDB( rsr_path=rsr_path, delete_rsid=self.permit.delete_rsid) self.map_rsid_id = {} self.map_id_rsid = {} self.map_user_id = {} self.rpt_factory = JWT(keyjar, lifetime=rpt_lifetime, iss=iss) self.ticket_factory = JWT(keyjar, lifetime=ticket_lifetime, iss=iss) self.authzdesc_lifetime = 3600 self.client_id = ressrv_id self.rsr_path = rsr_path self.ad2rpt = {} self.rpt2adid = {}
def test_verify_id_token(): idt = IdToken(**{ "sub": "553df2bcf909104751cfd8b2", "aud": [ "5542958437706128204e0000", "554295ce3770612820620000" ], "auth_time": 1441364872, "azp": "554295ce3770612820620000", }) kj = KeyJar() kj.add_symmetric("", 'dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ', ['sig']) kj.add_symmetric("https://sso.qa.7pass.ctf.prosiebensat1.com", 'dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ', ['sig']) packer = JWT(kj, sign_alg='HS256', iss="https://sso.qa.7pass.ctf.prosiebensat1.com", lifetime=3600) _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(id_token=_jws) vidt = verify_id_token(msg, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000") assert vidt
def unpack_software_statement(software_statement, iss, keyjar): _jwt = JWT(keyjar, iss=iss, msgtype=SoftwareStatement) return _jwt.unpack(software_statement)
def create_access_token(self, key_thumbprint): # creating the access_token jwt_constructor = JWT(self.keyjar, iss=self.me) # Audience is myself return jwt_constructor.pack( kid='abc', cnf={'kid': key_thumbprint}, aud=self.me)
class ADB(object): """ Expects to be one ADB instance per Resource Server """ def __init__(self, keyjar, rpt_lifetime, iss, ressrv_id, rsr_path, ticket_lifetime=3600): # database with all permission requests self.permission_requests = PermissionRequests() # database with all authorization decisions self.authz_db = AuthzDB() # database with all registered permissions self.permit = Permission() # database with all the registered resource sets self.resource_set = MemResourceSetDB( rsr_path=rsr_path, delete_rsid=self.permit.delete_rsid) self.map_rsid_id = {} self.map_id_rsid = {} self.map_user_id = {} self.rpt_factory = JWT(keyjar, lifetime=rpt_lifetime, iss=iss) self.ticket_factory = JWT(keyjar, lifetime=ticket_lifetime, iss=iss) self.authzdesc_lifetime = 3600 self.client_id = ressrv_id self.rsr_path = rsr_path self.ad2rpt = {} self.rpt2adid = {} def pending_permission_requests(self, owner, user): """ Return outstanding permission requests that is known to belong to an owner and bound to a requestor. :param owner: :param user: :return: """ res = [] for tick in self.permission_requests.requestor2tickets(user): rsid = self.permission_requests.ticket2rsid(tick) if self.resource_set.belongs_to(rsid, owner): res.append(tick) return res def is_expired(self, tinfo): if utc_time_sans_frac() <= tinfo['exp']: return False return True def permission_request_allowed(self, ticket, identity): """ Verify that whatever permission requests the ticket represents they are now allow. :param ticket: The ticket :param identity: Who has the ticket :return: Dictionary, with permission request as key and identifiers of authz decisions that permits the requests as values. """ _tinfo = self.rpt_factory.unpack(ticket) if self.is_expired(_tinfo): raise TicketError('expired', '{} > {}'.format(utc_time_sans_frac(), _tinfo['exp'])) try: prrs = self.permission_requests[ticket] except KeyError: logger.warning("Someone is using a ticket that doesn't exist") raise TicketError('invalid', ticket) else: result = {} for prr in prrs: owner = self.resource_set.owner(prr['resource_set_id']) _adids = self.authz_db.match(owner, identity, **prr.to_dict()) if not _adids: # all or nothing raise TicketError('not_authorized') result[prr.to_json()] = _adids return result def store_permission(self, permission, owner): """ Store a permission :param permission: The permission to store :param owner: The user setting the permission :return: A permission ID """ max_scopes = self.resource_set.read( owner, permission['resource_set_id'])["scopes"] # if no scopes are defined == all are requested try: _scopes = permission['scopes'] except KeyError: permission['scopes'] = max_scopes else: permission['scopes'] = [s for s in _scopes if s in max_scopes] pm = PermissionDescription(**permission) return self.authz_db.add(owner, perm_desc=pm) def register_permission(self, owner, rpt, rsid, scopes): """ :param owner: Resource owner :param rpt: Requesting party token :param rsid: Resource set id :param scopes: list of scopes """ now = utc_time_sans_frac() authz = AuthzDescription(resource_set_id=rsid, scopes=scopes, exp=now + self.authzdesc_lifetime, iat=now) self.permit.set(owner, rpt, authz) def resource_set_registration(self, method, owner, body=None, rsid=''): """ :param method: HTTP method :param owner: The owner of the resource set :param body: description of the resource set :param rsid: resource set id :return: tuple (http response code, http message, http response args) """ return self.resource_set.registration(method, owner, body, rsid) def issue_rpt(self, ticket, identity): """ As a side effect if a RPT is issued the ticket is removed and can not be used again. :param ticket: The ticket :param identity: Information about the entity who wants the RPT :return: A RPT """ idmap = self.permission_request_allowed(ticket, identity) if not idmap: return None rpt = self.rpt_factory.pack(aud=[self.client_id], type='rpt') for rsd in self.permission_requests[ticket]: owner = self.resource_set.owner(rsd['resource_set_id']) self.permit.bind_owner_to_rpt(owner, rpt) self.bind_rpt_to_authz_dec(rpt, idmap[rsd.to_json()]) self.register_permission(owner, rpt, rsd['resource_set_id'], rsd['scopes']) del self.permission_requests[ticket] return rpt def introspection(self, rpt): try: res = [] for owner in self.permit.rpt2owner[rpt]: res.extend(self.permit.get(owner, rpt)) return res except KeyError: return [] def bind_rpt_to_authz_dec(self, rpt, adid): for id in adid: try: self.ad2rpt[id].append(rpt) except KeyError: self.ad2rpt[id] = [rpt] try: self.rpt2adid[rpt].extend(adid) except KeyError: self.rpt2adid[rpt] = adid def remove_permission(self, owner, pid): """ :param owner: The owner of the resource set :param pid: The permission id """ # find all RPTs that has been issued based on this permission for rpt in self.ad2rpt[pid]: if self.rpt2adid[rpt] == [pid]: del self.rpt2adid[rpt] else: self.rpt2adid[rpt].remove(pid) self.permit.delete_rpt(rpt) del self.ad2rpt[pid] self.authz_db.delete(owner, pid=pid) def read_permission(self, owner, pid): return self.authz_db.read(owner, pid)
def test_jwt_pack(): _jwt = JWT(keyjar, lifetime=3600, iss=issuer).pack() assert _jwt assert len(_jwt.split('.')) == 3