Skip to content
This repository was archived by the owner on Jun 23, 2023. It is now read-only.

Commit 852e710

Browse files
authored
Merge pull request #116 from nsklikas/fix-refresh-id-token
Fix refresh tokens
2 parents 10058ed + ee87c96 commit 852e710

6 files changed

Lines changed: 175 additions & 58 deletions

File tree

src/oidcop/oauth2/token.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ def process_request(self, req: Union[Message, dict], **kwargs):
253253
_resp = {
254254
"access_token": access_token.value,
255255
"token_type": access_token.token_type,
256-
"scope": _grant.scope,
256+
"scope": scope,
257257
}
258258

259259
if access_token.expires_at:
@@ -318,7 +318,7 @@ def post_parse_request(
318318
if "scope" in request:
319319
req_scopes = set(request["scope"])
320320
scopes = set(grant.find_scope(token.based_on))
321-
if scopes < req_scopes:
321+
if not req_scopes.issubset(scopes):
322322
return self.error_cls(
323323
error="invalid_request",
324324
error_description="Invalid refresh scopes",

src/oidcop/oidc/token.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def process_request(self, req: Union[Message, dict], **kwargs):
218218
_resp = {
219219
"access_token": access_token.value,
220220
"token_type": token_type,
221-
"scope": _grant.scope,
221+
"scope": scope,
222222
}
223223

224224
if access_token.expires_at:
@@ -246,7 +246,7 @@ def process_request(self, req: Union[Message, dict], **kwargs):
246246
if "id_token" in _mints and "openid" in scope:
247247
try:
248248
_idtoken = self._mint_token(
249-
token_class="refresh_token",
249+
token_class="id_token",
250250
grant=_grant,
251251
session_id=_session_info["session_id"],
252252
client_id=_session_info["client_id"],
@@ -307,7 +307,7 @@ def post_parse_request(
307307
if "scope" in request:
308308
req_scopes = set(request["scope"])
309309
scopes = set(grant.find_scope(token.based_on))
310-
if scopes < req_scopes:
310+
if not req_scopes.issubset(scopes):
311311
return self.error_cls(
312312
error="invalid_request",
313313
error_description="Invalid refresh scopes",

src/oidcop/token/id_token.py

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
from oidcop.session.claims import claims_match
1313
from oidcop.token import is_expired
1414
from oidcop.token.exception import InvalidToken
15+
16+
from ..util import get_logout_id
1517
from . import Token
1618
from . import UnknownToken
17-
from ..util import get_logout_id
1819

1920
logger = logging.getLogger(__name__)
2021

@@ -131,7 +132,13 @@ def __init__(
131132
self.provider_info = construct_endpoint_info(self.default_capabilities, **kwargs)
132133

133134
def payload(
134-
self, session_id, alg="RS256", code=None, access_token=None, extra_claims=None,
135+
self,
136+
session_id,
137+
alg="RS256",
138+
code=None,
139+
access_token=None,
140+
extra_claims=None,
141+
user_info=None,
135142
):
136143
"""
137144
Collect payload for the ID Token.
@@ -155,16 +162,18 @@ def payload(
155162
if _val:
156163
_args[attr] = _val
157164

158-
_claims_restriction = grant.claims.get("id_token")
159-
if _claims_restriction == {}:
160-
user_info = None
161-
else:
162-
user_info = _context.claims_interface.get_user_claims(
163-
user_id=session_information["user_id"], claims_restriction=_claims_restriction,
164-
)
165-
if _claims_restriction and "acr" in _claims_restriction and "acr" in _args:
166-
if claims_match(_args["acr"], _claims_restriction["acr"]) is False:
167-
raise ValueError("Could not match expected 'acr'")
165+
if not user_info:
166+
_claims_restriction = grant.claims.get("id_token")
167+
if _claims_restriction == {}:
168+
user_info = None
169+
else:
170+
user_info = _context.claims_interface.get_user_claims(
171+
user_id=session_information["user_id"],
172+
claims_restriction=_claims_restriction,
173+
)
174+
if _claims_restriction and "acr" in _claims_restriction and "acr" in _args:
175+
if claims_match(_args["acr"], _claims_restriction["acr"]) is False:
176+
raise ValueError("Could not match expected 'acr'")
168177

169178
if user_info:
170179
try:
@@ -203,15 +212,16 @@ def payload(
203212
return _args
204213

205214
def sign_encrypt(
206-
self,
207-
session_id,
208-
client_id,
209-
code=None,
210-
access_token=None,
211-
sign=True,
212-
encrypt=False,
213-
lifetime=None,
214-
extra_claims=None,
215+
self,
216+
session_id,
217+
client_id,
218+
code=None,
219+
access_token=None,
220+
sign=True,
221+
encrypt=False,
222+
lifetime=None,
223+
extra_claims=None,
224+
user_info=None,
215225
) -> str:
216226
"""
217227
Signed and or encrypt a IDToken
@@ -240,6 +250,7 @@ def sign_encrypt(
240250
code=code,
241251
access_token=access_token,
242252
extra_claims=extra_claims,
253+
user_info=user_info,
243254
)
244255

245256
if lifetime is None:
@@ -249,7 +260,15 @@ def sign_encrypt(
249260

250261
return _jwt.pack(_payload, recv=client_id)
251262

252-
def __call__(self, session_id: Optional[str] = "", ttype: Optional[str] = "", **kwargs) -> str:
263+
def __call__(
264+
self,
265+
session_id: Optional[str] = "",
266+
ttype: Optional[str] = "",
267+
encrypt=False,
268+
code=None,
269+
access_token=None,
270+
**kwargs,
271+
) -> str:
253272
_context = self.server_get("endpoint_context")
254273

255274
user_id, client_id, grant_id = _context.session_manager.decrypt_session_id(session_id)
@@ -265,11 +284,16 @@ def __call__(self, session_id: Optional[str] = "", ttype: Optional[str] = "", **
265284

266285
lifetime = self.lifetime
267286

268-
# Weed out stuff that doesn't belong here
269-
kwargs = {k: v for k, v in kwargs.items() if k in ["encrypt", "code", "access_token"]}
270-
271287
id_token = self.sign_encrypt(
272-
session_id, client_id, sign=True, lifetime=lifetime, extra_claims=xargs, **kwargs
288+
session_id,
289+
client_id,
290+
sign=True,
291+
lifetime=lifetime,
292+
extra_claims=xargs,
293+
encrypt=encrypt,
294+
code=code,
295+
access_token=access_token,
296+
user_info=kwargs,
273297
)
274298

275299
return id_token

tests/test_05_id_token.py

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ def test_id_token_payload_0(self):
235235
"nonce",
236236
"iat",
237237
"exp",
238+
"email",
239+
"email_verified",
240+
"jti",
241+
"scope",
242+
"client_id",
238243
"iss",
239244
}
240245

@@ -252,6 +257,11 @@ def test_id_token_payload_with_code(self):
252257
"auth_time",
253258
"aud",
254259
"exp",
260+
"email",
261+
"email_verified",
262+
"jti",
263+
"scope",
264+
"client_id",
255265
"c_hash",
256266
"iss",
257267
"iat",
@@ -277,6 +287,11 @@ def test_id_token_payload_with_access_token(self):
277287
"auth_time",
278288
"aud",
279289
"exp",
290+
"email",
291+
"email_verified",
292+
"jti",
293+
"scope",
294+
"client_id",
280295
"iss",
281296
"iat",
282297
"nonce",
@@ -300,6 +315,11 @@ def test_id_token_payload_with_code_and_access_token(self):
300315
"auth_time",
301316
"aud",
302317
"exp",
318+
"email",
319+
"email_verified",
320+
"jti",
321+
"scope",
322+
"client_id",
303323
"iss",
304324
"iat",
305325
"nonce",
@@ -308,9 +328,10 @@ def test_id_token_payload_with_code_and_access_token(self):
308328
}
309329

310330
def test_id_token_payload_with_userinfo(self):
311-
session_id = self._create_session(AREQ)
331+
req = dict(AREQ)
332+
req["claims"] = {"id_token": {"given_name": None}}
333+
session_id = self._create_session(req)
312334
grant = self.session_manager[session_id]
313-
grant.claims = {"id_token": {"given_name": None}}
314335

315336
id_token = self._mint_id_token(grant, session_id)
316337

@@ -320,6 +341,11 @@ def test_id_token_payload_with_userinfo(self):
320341
"nonce",
321342
"iat",
322343
"iss",
344+
"email",
345+
"email_verified",
346+
"jti",
347+
"scope",
348+
"client_id",
323349
"given_name",
324350
"aud",
325351
"exp",
@@ -328,9 +354,10 @@ def test_id_token_payload_with_userinfo(self):
328354
}
329355

330356
def test_id_token_payload_many_0(self):
331-
session_id = self._create_session(AREQ)
357+
req = dict(AREQ)
358+
req["claims"] = {"id_token": {"given_name": None}}
359+
session_id = self._create_session(req)
332360
grant = self.session_manager[session_id]
333-
grant.claims = {"id_token": {"given_name": None}}
334361
code = self._mint_code(grant, session_id)
335362
access_token = self._mint_access_token(grant, session_id, code)
336363

@@ -344,6 +371,11 @@ def test_id_token_payload_many_0(self):
344371
"nonce",
345372
"c_hash",
346373
"at_hash",
374+
"email",
375+
"email_verified",
376+
"jti",
377+
"scope",
378+
"client_id",
347379
"sub",
348380
"auth_time",
349381
"given_name",
@@ -391,9 +423,10 @@ def test_get_sign_algorithm(self):
391423
}
392424

393425
def test_available_claims(self):
394-
session_id = self._create_session(AREQ)
426+
req = dict(AREQ)
427+
req["claims"] = {"id_token": {"nickname": {"essential": True}}}
428+
session_id = self._create_session(req)
395429
grant = self.session_manager[session_id]
396-
grant.claims = {"id_token": {"nickname": {"essential": True}}}
397430

398431
id_token = self._mint_id_token(grant, session_id)
399432

@@ -497,11 +530,7 @@ def test_client_claims_scopes(self):
497530
grant = self.session_manager[session_id]
498531

499532
self.session_manager.token_handler["id_token"].kwargs["add_claims_by_scope"] = True
500-
501-
_claims = self.endpoint_context.claims_interface.get_claims(
502-
session_id=session_id, scopes=AREQS["scope"], claims_release_point="id_token"
503-
)
504-
grant.claims = {"id_token": _claims}
533+
grant.scope = AREQS["scope"]
505534

506535
id_token = self._mint_id_token(grant, session_id)
507536

@@ -519,11 +548,7 @@ def test_client_claims_scopes_and_request_claims_no_match(self):
519548
grant = self.session_manager[session_id]
520549

521550
self.session_manager.token_handler["id_token"].kwargs["add_claims_by_scope"] = True
522-
523-
_claims = self.endpoint_context.claims_interface.get_claims(
524-
session_id=session_id, scopes=AREQRC["scope"], claims_release_point="id_token"
525-
)
526-
grant.claims = {"id_token": _claims}
551+
grant.scope = AREQRC["scope"]
527552

528553
id_token = self._mint_id_token(grant, session_id)
529554

@@ -546,11 +571,7 @@ def test_client_claims_scopes_and_request_claims_one_match(self):
546571
grant = self.session_manager[session_id]
547572

548573
self.session_manager.token_handler["id_token"].kwargs["add_claims_by_scope"] = True
549-
550-
_claims = self.endpoint_context.claims_interface.get_claims(
551-
session_id=session_id, scopes=_req["scope"], claims_release_point="id_token"
552-
)
553-
grant.claims = {"id_token": _claims}
574+
grant.scope = _req["scope"]
554575

555576
id_token = self._mint_id_token(grant, session_id)
556577

tests/test_24_oauth2_token_endpoint.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ def test_refresh_scopes(self):
458458
_session_info["session_id"], _resp["response_args"]["refresh_token"]
459459
)
460460

461-
assert at.scope == rt.scope == _request["scope"]
461+
assert at.scope == rt.scope == _request["scope"] == _resp["response_args"]["scope"]
462462

463463
def test_refresh_more_scopes(self):
464464
areq = AUTH_REQ.copy()
@@ -475,7 +475,7 @@ def test_refresh_more_scopes(self):
475475

476476
_request = REFRESH_TOKEN_REQ.copy()
477477
_request["refresh_token"] = _resp["response_args"]["refresh_token"]
478-
_request["scope"] = ["email", "profile"]
478+
_request["scope"] = ["ema"]
479479

480480
_req = self.token_endpoint.parse_request(_request.to_json())
481481
assert isinstance(_req, TokenErrorResponse)
@@ -534,7 +534,7 @@ def test_refresh_more_scopes_2(self):
534534
_session_info["session_id"], _resp["response_args"]["refresh_token"]
535535
)
536536

537-
assert at.scope == rt.scope == _request["scope"]
537+
assert at.scope == rt.scope == _request["scope"] == _resp["response_args"]["scope"]
538538

539539
def test_do_refresh_access_token_not_allowed(self):
540540
areq = AUTH_REQ.copy()

0 commit comments

Comments
 (0)