refac
This commit is contained in:
@@ -2230,7 +2230,6 @@ class OAuthManager:
|
||||
sessions via Redis, and deletes their OAuth sessions.
|
||||
Returns a JSONResponse per the OIDC Back-Channel Logout 1.0 spec.
|
||||
"""
|
||||
import jwt as pyjwt
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
# 1. Extract logout_token from form body
|
||||
@@ -2248,7 +2247,7 @@ class OAuthManager:
|
||||
|
||||
# 2. Peek at unverified issuer to match against configured providers
|
||||
try:
|
||||
unverified_claims = pyjwt.decode(logout_token, options={'verify_signature': False})
|
||||
unverified_claims = jwt.decode(logout_token, options={'verify_signature': False})
|
||||
token_issuer = unverified_claims.get('iss')
|
||||
except Exception as e:
|
||||
log.warning(f'Back-channel logout: cannot decode logout_token: {e}')
|
||||
@@ -2265,35 +2264,27 @@ class OAuthManager:
|
||||
|
||||
# 3. Find the configured provider whose issuer matches the token
|
||||
matched_provider = None
|
||||
matched_client_id = None
|
||||
matched_client = None
|
||||
matched_jwks_uri = None
|
||||
matched_issuer = None
|
||||
|
||||
for provider_name in OAUTH_PROVIDERS:
|
||||
server_metadata_url = self.get_server_metadata_url(provider_name)
|
||||
if not server_metadata_url:
|
||||
client = self.get_client(provider_name)
|
||||
if not client:
|
||||
continue
|
||||
|
||||
try:
|
||||
async with aiohttp.ClientSession(trust_env=True) as session:
|
||||
async with session.get(server_metadata_url, ssl=AIOHTTP_CLIENT_SESSION_SSL) as r:
|
||||
if r.status != 200:
|
||||
continue
|
||||
oidc_config = await r.json()
|
||||
|
||||
provider_issuer = oidc_config.get('issuer')
|
||||
if provider_issuer and provider_issuer == token_issuer:
|
||||
client = self.get_client(provider_name)
|
||||
matched_provider = provider_name
|
||||
matched_client_id = client.client_id if client else None
|
||||
matched_jwks_uri = oidc_config.get('jwks_uri')
|
||||
matched_issuer = provider_issuer
|
||||
break
|
||||
oidc_config = await client.load_server_metadata()
|
||||
except Exception as e:
|
||||
log.debug('Back-channel logout: error checking provider %s: %s', provider_name, e)
|
||||
continue
|
||||
|
||||
if not matched_provider or not matched_client_id or not matched_jwks_uri:
|
||||
if oidc_config.get('issuer') == token_issuer:
|
||||
matched_provider = provider_name
|
||||
matched_client = client
|
||||
matched_jwks_uri = oidc_config.get('jwks_uri')
|
||||
break
|
||||
|
||||
if not matched_provider or not matched_client or not matched_client.client_id or not matched_jwks_uri:
|
||||
log.warning(f'Back-channel logout: no configured provider matches issuer {token_issuer}')
|
||||
return JSONResponse(
|
||||
status_code=400,
|
||||
@@ -2305,20 +2296,37 @@ class OAuthManager:
|
||||
|
||||
# 4. Validate the logout_token signature and claims
|
||||
try:
|
||||
jwks_client = pyjwt.PyJWKClient(matched_jwks_uri)
|
||||
signing_key = jwks_client.get_signing_key_from_jwt(logout_token)
|
||||
token_kid = jwt.get_unverified_header(logout_token).get('kid')
|
||||
if not token_kid:
|
||||
raise jwt.InvalidTokenError('logout_token missing kid header')
|
||||
|
||||
claims = pyjwt.decode(
|
||||
try:
|
||||
jwk_set = jwt.PyJWKSet.from_dict(await matched_client.fetch_jwk_set())
|
||||
except jwt.PyJWTError as e:
|
||||
raise jwt.InvalidTokenError(str(e))
|
||||
|
||||
signing_key = next(
|
||||
(
|
||||
key
|
||||
for key in jwk_set.keys
|
||||
if key.key_id == token_kid and key.public_key_use in ['sig', None]
|
||||
),
|
||||
None,
|
||||
)
|
||||
if not signing_key:
|
||||
raise jwt.InvalidTokenError('no signing key matches the token kid')
|
||||
|
||||
claims = jwt.decode(
|
||||
logout_token,
|
||||
signing_key.key,
|
||||
algorithms=['RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512'],
|
||||
audience=matched_client_id,
|
||||
issuer=matched_issuer,
|
||||
audience=matched_client.client_id,
|
||||
issuer=token_issuer,
|
||||
options={
|
||||
'require': ['iss', 'aud', 'iat', 'events'],
|
||||
},
|
||||
)
|
||||
except pyjwt.InvalidTokenError as e:
|
||||
except jwt.InvalidTokenError as e:
|
||||
log.warning(f'Back-channel logout: invalid logout_token: {e}')
|
||||
return JSONResponse(
|
||||
status_code=400,
|
||||
|
||||
Reference in New Issue
Block a user