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

Commit 16aac13

Browse files
committed
Port token exchange feature to oidcop
Fix tests
1 parent 8927805 commit 16aac13

File tree

3 files changed

+153
-73
lines changed

3 files changed

+153
-73
lines changed

src/oidcop/oauth2/token.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def _mint_token(
6868
token_args = meth(_context, client_id, token_args)
6969

7070
if token_args:
71-
_args = {"token_args": token_args}
71+
_args = token_args
7272
else:
7373
_args = {}
7474

src/oidcop/oidc/token.py

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
import logging
22
from typing import Optional
33
from typing import Union
4+
from urllib.parse import urlparse
45

6+
from cryptojwt.exception import JWKESTException
57
from cryptojwt.jwe.exception import JWEException
68
from cryptojwt.jws.exception import NoSuitableSigningKeys
79
from cryptojwt.jwt import utc_time_sans_frac
810
from oidcmsg import oidc
911
from oidcmsg.message import Message
12+
from oidcmsg.exception import MissingRequiredValue, MissingRequiredAttribute
1013
from oidcmsg.oidc import RefreshAccessTokenRequest
1114
from oidcmsg.oidc import TokenErrorResponse
12-
15+
from oidcmsg.oauth2 import (TokenExchangeRequest, ResponseMessage,
16+
TokenExchangeResponse)
1317
from oidcop import oauth2
1418
from oidcop import sanitize
19+
from oidcop.oauth2.authorization import check_unknown_scopes_policy
1520
from oidcop.oauth2.token import TokenEndpointHelper
1621
from oidcop.session.grant import AuthorizationCode
1722
from oidcop.session.grant import RefreshToken
1823
from oidcop.session.token import MintingNotAllowed
1924
from oidcop.token.exception import UnknownToken
25+
from oidcop.exception import UnAuthorizedClientScope, ToOld
26+
from oidcop.session.token import AccessToken
2027

2128
logger = logging.getLogger(__name__)
2229

@@ -376,10 +383,15 @@ def __init__(self, endpoint, config=None):
376383
def post_parse_request(self, request, client_id="", **kwargs):
377384
request = TokenExchangeRequest(**request.to_dict())
378385

379-
# if "client_id" not in request:
380-
# request["client_id"] = client_id
386+
if "client_id" not in request:
387+
request["client_id"] = client_id
388+
389+
_context = self.endpoint.server_get("endpoint_context")
381390

382-
keyjar = getattr(self.endpoint_context, "keyjar", "")
391+
try:
392+
keyjar = _context.keyjar
393+
except AttributeError:
394+
keyjar = ""
383395

384396
try:
385397
request.verify(keyjar=keyjar, opponent_id=client_id)
@@ -393,12 +405,11 @@ def post_parse_request(self, request, client_id="", **kwargs):
393405
error="invalid_request", error_description="%s" % err
394406
)
395407

396-
397408
error = self.check_for_errors(request=request)
398409
if error is not None:
399410
return error
400411

401-
_mngr = self.endpoint_context.session_manager
412+
_mngr = _context.session_manager
402413
try:
403414
_session_info = _mngr.get_session_info_by_token(
404415
request["subject_token"], grant=True
@@ -421,13 +432,12 @@ def post_parse_request(self, request, client_id="", **kwargs):
421432
return self.error_cls(
422433
error="invalid_request", error_description="Subject token inactive"
423434
)
424-
425435
return request
426436

427437
def check_for_errors(self, request):
428-
context = self.endpoint.endpoint_context
438+
_context = self.endpoint.server_get("endpoint_context")
429439
if "resource" in request:
430-
iss = urlparse(context.issuer)
440+
iss = urlparse(_context.issuer)
431441
if any(
432442
urlparse(res).netloc != iss.netloc for res in request["resource"]
433443
):
@@ -437,7 +447,7 @@ def check_for_errors(self, request):
437447

438448
if "audience" in request:
439449
if any(
440-
aud != context.issuer for aud in request["audience"]
450+
aud != _context.issuer for aud in request["audience"]
441451
):
442452
return TokenErrorResponse(
443453
error="invalid_target", error_description="Unknown audience"
@@ -468,7 +478,7 @@ def check_for_errors(self, request):
468478
def token_exchange_response(self, token):
469479
response_args = {
470480
"issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
471-
"token_type": token.type,
481+
"token_type": token.token_type,
472482
"access_token": token.value,
473483
"scope": token.scope,
474484
"expires_in": token.usage_rules["expires_in"]
@@ -485,31 +495,61 @@ def process_request(self, request, **kwargs):
485495
# return TokenErrorResponse(
486496
# error="invalid_request", error_description="Not allowed"
487497
# )
488-
_mngr = self.endpoint_context.session_manager
498+
_context = self.endpoint.server_get("endpoint_context")
499+
_mngr = _context.session_manager
489500
try:
490501
_session_info = _mngr.get_session_info_by_token(
491-
request["subject_token"],
492-
grant=True,
502+
request["subject_token"], grant=True
493503
)
494-
except KeyError:
504+
except ToOld:
505+
logger.error("Subject token has expired.")
506+
return self.error_cls(
507+
error="invalid_request",
508+
error_description="Subject token has expired"
509+
)
510+
except (KeyError, UnknownToken):
495511
logger.error("Subject token invalid.")
496512
return self.error_cls(
497-
error="invalid_grant",
498-
error_description="Subject token invalid",
513+
error="invalid_request",
514+
error_description="Subject token invalid"
499515
)
500516

501517
token = _mngr.find_token(_session_info["session_id"], request["subject_token"])
518+
519+
if not isinstance(token, AccessToken):
520+
return self.error_cls(
521+
error="invalid_request", error_description="Wrong token type"
522+
)
523+
524+
if token.is_active() is False:
525+
return self.error_cls(
526+
error="invalid_request", error_description="Subject token inactive"
527+
)
528+
502529
grant = _session_info["grant"]
503530

531+
request_info = dict(scope=request.get("scope", []))
532+
try:
533+
check_unknown_scopes_policy(request_info, request["client_id"], _context)
534+
except UnAuthorizedClientScope:
535+
logger.error("Unauthorized scope requested.")
536+
return self.error_cls(
537+
error="invalid_grant",
538+
error_description="Unauthorized scope requested",
539+
)
540+
504541
try:
505-
new_token = grant.mint_token(
542+
new_token = self._mint_token(
543+
token_class=token.token_class,
544+
grant=grant,
506545
session_id=_session_info["session_id"],
507-
endpoint_context=self.endpoint_context,
508-
token_type='access_token',
509-
token_handler=_mngr.token_handler["access_token"],
546+
client_id=request["client_id"],
510547
based_on=token,
511-
resources=request.get("resource"),
512548
scope=request.get("scope"),
549+
token_args={
550+
"resources":request.get("resource"),
551+
},
552+
token_type=token.token_type
513553
)
514554
except MintingNotAllowed:
515555
logger.error("Minting not allowed for 'access_token'")

0 commit comments

Comments
 (0)