class TestToken2(object): @pytest.fixture(autouse=True) def create_token(self): kb = KeyBundle(JWKS["keys"]) kj = KeyJar() kj.issuer_keys[''] = [kb] self.access_token = JWTToken( 'T', keyjar=kj, iss='https://example.com/as', sign_alg='RS256') def test_create(self): sid = rndstr(32) session_info = SESSION_INFO _jwt = self.access_token(sid, sinfo=session_info, kid='sign1', lifetime=1200) assert _jwt assert len(_jwt.split('.')) == 3 # very simple JWS check def test_create_with_aud(self): sid = rndstr(32) session_info = SESSION_INFO _jwt = self.access_token( sid, sinfo=session_info, kid='sign1', aud=['https://example.com/rs'], lifetime=1200) assert _jwt info = self.access_token.get_info(_jwt) assert info['exp'] - info['iat'] == 1200
class TestEncToken(object): @pytest.fixture(autouse=True) def create_token(self): kb = KeyBundle(JWKS["keys"]) kj = KeyJar() kj.issuer_keys[''] = [kb] self.access_token = JWTToken('T', keyjar=kj, lt_pattern={ 'code': 3600, 'token': 900 }, iss='https://example.com/as', encrypt=True) def test_enc_create(self): sid = rndstr(32) session_info = SESSION_INFO _jwe = self.access_token(sid, sinfo=session_info, kid='sign1') assert _jwe assert len(_jwe.split('.')) == 5 # very simple JWE check def test_parse_enc(self): sid = rndstr(32) session_info = SESSION_INFO _jwe = self.access_token(sid, sinfo=session_info, kid='sign1') _info = self.access_token.get_info(_jwe) assert _info
class TestEncToken(object): @pytest.fixture(autouse=True) def create_token(self): kb = KeyBundle(JWKS["keys"]) kj = KeyJar() kj.issuer_keys[''] = [kb] self.access_token = JWTToken('T', keyjar=kj, lt_pattern={'code': 3600, 'token': 900}, iss='https://example.com/as', encrypt=True) def test_enc_create(self): sid = rndstr(32) session_info = SESSION_INFO _jwe = self.access_token(sid, sinfo=session_info, kid='sign1') assert _jwe assert len(_jwe.split('.')) == 5 # very simple JWE check def test_parse_enc(self): sid = rndstr(32) session_info = SESSION_INFO _jwe = self.access_token(sid, sinfo=session_info, kid='sign1') _info = self.access_token.get_info(_jwe) assert _info
class TestEncToken(object): @pytest.fixture(autouse=True) def create_token(self): kb = KeyBundle(JWKS["keys"]) kj = KeyJar() kj.issuer_keys[""] = [kb] self.token = JWTToken( "T", keyjar=kj, lifetime={"code": 3600, "token": 900}, iss="https://example.com/as", encrypt=True ) def test_enc_create(self): sid = rndstr(32) session_info = {"sub": "subject_id", "client_id": "https://example.com/rp", "response_type": ["code"]} _jwe = self.token(sid, sinfo=session_info, kid="sign1") assert _jwe assert len(_jwe.split(".")) == 5 # very simple JWE check def test_parse_enc(self): sid = rndstr(32) session_info = {"sub": "subject_id", "client_id": "https://example.com/rp", "response_type": ["code"]} _jwe = self.token(sid, sinfo=session_info, kid="sign1") _info = self.token.get_info(_jwe) assert _info
def test_pkce_token(): kb = KeyBundle(JWKS["keys"]) kj = KeyJar() kj.issuer_keys[''] = [kb] constructor = JWTToken('A', keyjar=kj, lt_pattern={'': 900}, iss='https://example.com/as', sign_alg='RS256', encrypt=True) sid = rndstr(32) session_info = { 'sub': 'subject_id', 'client_id': 'https://example.com/rp', 'response_type': ['code'], 'authzreq': '{}' } _cli = Client(config={'code_challenge': {'method': 'S512', 'length': 96}}) args, cv = _cli.add_code_challenge() access_grant = constructor( sid, sinfo=session_info, kid='sign1', code_challenge=args['code_challenge'], code_challenge_method=args['code_challenge_method']) _info = constructor.get_info(access_grant) assert _info['code_challenge_method'] == args['code_challenge_method'] assert _info['code_challenge'] == args['code_challenge']
def test_pkce_token(): kb = KeyBundle(JWKS["keys"]) kj = KeyJar() kj.issuer_keys[""] = [kb] constructor = JWTToken( "A", keyjar=kj, lt_pattern={"": 900}, iss="https://example.com/as", sign_alg="RS256", encrypt=True, ) sid = rndstr(32) session_info = { "sub": "subject_id", "client_id": "https://example.com/rp", "response_type": ["code"], "authzreq": "{}", } _cli = Client(config={"code_challenge": {"method": "S512", "length": 96}}) args, cv = _cli.add_code_challenge() access_grant = constructor( sid, sinfo=session_info, kid="sign1", code_challenge=args["code_challenge"], code_challenge_method=args["code_challenge_method"], ) _info = constructor.get_info(access_grant) assert _info["code_challenge_method"] == args["code_challenge_method"] assert _info["code_challenge"] == args["code_challenge"]
class TestToken2(object): @pytest.fixture(autouse=True) def create_token(self): kb = KeyBundle(JWKS["keys"]) kj = KeyJar() kj.issuer_keys[""] = [kb] self.access_token = JWTToken("T", keyjar=kj, iss="https://example.com/as", sign_alg="RS256") def test_create(self): sid = rndstr(32) session_info = SESSION_INFO _jwt = self.access_token(sid, sinfo=session_info, kid="sign1", lifetime=1200) assert _jwt assert len(_jwt.split(".")) == 3 # very simple JWS check def test_create_with_aud(self): sid = rndstr(32) session_info = SESSION_INFO _jwt = self.access_token( sid, sinfo=session_info, kid="sign1", aud=["https://example.com/rs"], lifetime=1200, ) assert _jwt info = self.access_token.get_info(_jwt) assert info["exp"] - info["iat"] == 1200
class TestToken2(object): @pytest.fixture(autouse=True) def create_token(self): kb = KeyBundle(JWKS["keys"]) kj = KeyJar() kj.issuer_keys[''] = [kb] self.access_token = JWTToken('T', keyjar=kj, iss='https://example.com/as', sign_alg='RS256') def test_create(self): sid = rndstr(32) session_info = SESSION_INFO _jwt = self.access_token(sid, sinfo=session_info, kid='sign1', lifetime=1200) assert _jwt assert len(_jwt.split('.')) == 3 # very simple JWS check def test_create_with_aud(self): sid = rndstr(32) session_info = SESSION_INFO _jwt = self.access_token(sid, sinfo=session_info, kid='sign1', aud=['https://example.com/rs'], lifetime=1200) assert _jwt info = self.access_token.get_info(_jwt) assert info['exp'] - info['iat'] == 1200
class TokenHandler(object): """ Class for handling tokens. Note! the token and refresh token factories both keep their own token databases. """ def __init__( self, issuer, token_policy, token_factory=None, refresh_token_factory=None, keyjar=None, sign_alg="RS256", ): """ Initialize the class. :param token_factory: A callable function that returns a token :param refresh_token_factory: A callable function that returns a refresh token :param token_policy: A dictionary of the form {'access_token': {<target_id>: {<grant_type>: <lifetime>}}, 'refresh_token': {<target_id>: {<grant_type>: <lifetime>}}} :param keyjar: A oic.utils.keyio.KeyJar instance :param sign_alg: Which signature algorithm to use. :return: a TokenHandler instance """ self.token_policy = token_policy if token_factory is None: self.token_factory = JWTToken( "T", keyjar=keyjar, iss=issuer, sign_alg=sign_alg ) else: self.token_factory = token_factory if refresh_token_factory is None: self.refresh_token_factory = JWTToken( "R", keyjar=keyjar, iss="https://example.com/as", sign_alg=sign_alg, token_storage={}, ) else: self.refresh_token_factory = refresh_token_factory def get_access_token(self, target_id, scope, grant_type): """ Return access token for given inputs. :param target_id: :param scope: :param grant_type: :return: """ # No default, either there is an explicit policy or there is not try: lifetime = self.token_policy["access_token"][target_id][grant_type] except KeyError: raise NotAllowed( "Access token for grant_type {} for target_id {} not allowed" ) sid = rndstr(32) return self.token_factory( sid, target_id=target_id, scope=scope, grant_type=grant_type, lifetime=lifetime, ) def refresh_access_token(self, target_id, token, grant_type, **kwargs): """ Return refresh_access_token for given input. :param target_id: Who gave me this token :param token: The refresh_token :param grant_type: Which grant type the token is connected to :param kwargs: Extra key word arguments :return: New access_token """ # Check that the token is an refresh token info = self.refresh_token_factory.get_info(token) # Make sure the token should is usable by the client to get a # refresh token try: if target_id != info["azr"]: raise NotAllowed("{} can't use this token".format(target_id)) except KeyError: if target_id not in info["aud"]: raise NotAllowed("{} can't use this token".format(target_id)) if self.token_factory.is_valid(info): try: lifetime = self.token_policy["access_token"][target_id][grant_type] except KeyError: raise NotAllowed( "Issue access token for grant_type {} for target_id {} not allowed" ) else: sid = self.token_factory.db[info["jti"]] try: _aud = kwargs["aud"] except KeyError: _aud = info["aud"] return self.token_factory( sid, target_id=target_id, lifetime=lifetime, aud=_aud ) def get_refresh_token(self, target_id, grant_type, sid): try: lifetime = self.token_policy["refresh_token"][target_id][grant_type] except KeyError: raise NotAllowed( "Issue access token for grant_type {} for target_id {} not allowed" ) else: return self.refresh_token_factory( sid, target_id=target_id, lifetime=lifetime ) def invalidate(self, token): if self.token_factory.valid(token): self.token_factory.invalidate(token)
class TokenHandler(object): def __init__(self, issuer, token_policy, token_factory=None, refresh_token_factory=None, keyjar=None, sign_alg='RS256'): """ Note! the token and refresh token factories both keep their own token databases. :param token_factory: A callable function that returns a token :param refresh_token_factory: A callable function that returns a refresh token :param token_policy: A dictionary of the form {'access_token': {<target_id>: {<grant_type>: <lifetime>}}, 'refresh_token': {<target_id>: {<grant_type>: <lifetime>}}} :param keyjar: A oic.utils.keyio.KeyJar instance :param sign_alg: Which signature algorithm to use. :return: a TokenHandler instance """ self.token_policy = token_policy if token_factory is None: self.token_factory = JWTToken('T', keyjar=keyjar, iss=issuer, sign_alg=sign_alg) else: self.token_factory = token_factory if refresh_token_factory is None: self.refresh_token_factory = JWTToken('R', keyjar=keyjar, iss='https://example.com/as', sign_alg=sign_alg) else: self.refresh_token_factory = refresh_token_factory def get_access_token(self, target_id, scope, grant_type): """ :param target_id: :param scope: :param grant_type: :return: """ # No default, either there is an explicit policy or there is not try: lifetime = self.token_policy['access_token'][target_id][grant_type] except KeyError: raise NotAllowed( 'Access token for grant_type {} for target_id {} not allowed') sid = rndstr(32) return self.token_factory(sid, target_id=target_id, scope=scope, grant_type=grant_type, lifetime=lifetime) def refresh_access_token(self, target_id, token, grant_type, **kwargs): """ :param target_id: Who gave me this token :param token: The refresh_token :param grant_type: Which grant type the token is connected to :param kwargs: Extra key word arguments :return: New access_token """ # Check that the token is an refresh token info = self.refresh_token_factory.get_info(token) # Make sure the token should is usable by the client to get a # refresh token try: if target_id != info["azr"]: raise NotAllowed("{} can't use this token".format(target_id)) except KeyError: if target_id not in info['aud']: raise NotAllowed("{} can't use this token".format(target_id)) if self.token_factory.is_valid(info): try: lifetime = self.token_policy['access_token'][target_id][ grant_type] except KeyError: raise NotAllowed( 'Issue access token for grant_type {} for target_id {} not allowed') else: sid = self.token_factory.db[info['jti']] try: _aud = kwargs['aud'] except KeyError: _aud = info['aud'] return self.token_factory( sid, target_id=target_id, lifetime=lifetime, aud=_aud) def get_refresh_token(self, target_id, grant_type, sid): try: lifetime = self.token_policy['refresh_token'][target_id][grant_type] except KeyError: raise NotAllowed( 'Issue access token for grant_type {} for target_id {} not allowed') else: return self.refresh_token_factory( sid, target_id=target_id, lifetime=lifetime) def invalidate(self, token): if self.token_factory.valid(token): self.token_factory.invalidate(token)