Skip to content

Commit

Permalink
Merge pull request #405 from TeskaLabs/fix/accept-algorithmic-token-i…
Browse files Browse the repository at this point in the history
…n-oauth-introspection

Accept algorithmic token in oauth introspection
  • Loading branch information
byewokko authored Jul 11, 2024
2 parents d6e9c8e + a99254f commit 020f73f
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## v24.20

### Pre-releases
- `v24.20-alpha14`
- `v24.20-alpha13`
- `v24.20-alpha12`
- `v24.20-alpha11`
Expand All @@ -23,6 +24,7 @@
- Default password criteria are more restrictive (#372, `v24.20-alpha1`, Compatible with Seacat Auth Webui v24.19-alpha and later, Seacat Account Webui v24.08-beta and later)

### Fix
- Fix nginx oauth introspection for self-encoded (algorithmic) sessions (#405, `v24.20-alpha14`)
- Fix token request for self-encoded (algorithmic) sessions (#404, `v24.20-alpha13`)
- Fix credential search performance (#391, `v24.20-alpha12`)
- Fix AttributeError in credentials update (#399, `v24.20-alpha11`)
Expand Down
13 changes: 2 additions & 11 deletions seacatauth/cookie/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import asab
import asab.storage
import asab.exceptions
import jwcrypto.jws

from .. import exceptions
from ..session.adapter import SessionAdapter, CookieData
Expand Down Expand Up @@ -106,17 +105,9 @@ async def get_session_by_session_cookie_value(self, cookie_value: str):
"""
Get session by cookie value.
"""
# First try interpreting the token as an algorithmic session
if "." in cookie_value:
try:
return await self.SessionService.Algorithmic.deserialize(cookie_value)
except asab.exceptions.NotAuthenticatedError as e:
# The JWToken is invalid or expired
raise exceptions.SessionNotFoundError(
"Invalid algorithmic session token", query={"cookie_value": cookie_value}) from e
except jwcrypto.jws.InvalidJWSObject:
# Not a JWT token
pass
# If there is ".", the value is not pure base64. It must be a JWT of an algorithmic session.
return await self.SessionService.Algorithmic.deserialize(cookie_value)

# Then try looking for the session in the database
try:
Expand Down
4 changes: 4 additions & 0 deletions seacatauth/openidconnect/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,10 @@ async def get_session_by_access_token(self, token_value: str):
"""
Retrieve session by its access token.
"""
if "." in token_value:
# If there is ".", the value is not pure base64. It must be a JWT of an algorithmic session.
return await self.SessionService.Algorithmic.deserialize(token_value)

try:
token_bytes = base64.urlsafe_b64decode(token_value.encode("ascii"))
except binascii.Error as e:
Expand Down
22 changes: 13 additions & 9 deletions seacatauth/session/algorithmic.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@
import uuid
import json
import datetime

import asab.exceptions
import asab.web.rest
import asab.metrics

from .adapter import SessionAdapter
from .. import exceptions
from ..authz import build_credentials_authz

L = logging.getLogger(__name__)
Expand Down Expand Up @@ -114,12 +113,14 @@ async def deserialize(self, token_value) -> SessionAdapter | None:
"""
try:
token = jwcrypto.jwt.JWT(jwt=token_value, key=self.PrivateKey)
except ValueError:
# This is not a JWToken
return None
except (jwcrypto.jws.InvalidJWSSignature, jwcrypto.jwt.JWTExpired) as e:
# JWToken invalid
raise asab.exceptions.NotAuthenticatedError() from e
except (ValueError, jwcrypto.jws.InvalidJWSObject) as e:
L.error("Corrupt algorithmic session token.")
raise exceptions.SessionNotFoundError("Corrupt algorithmic session token.") from e
except jwcrypto.jws.InvalidJWSSignature as e:
L.error("Invalid algorithmic session token signature.")
raise exceptions.SessionNotFoundError("Invalid algorithmic session token signature.") from e
except jwcrypto.jwt.JWTExpired as e:
raise exceptions.SessionNotFoundError("Expired algorithmic session token.") from e

data_dict = json.loads(token.claims)
client_dict = await self.ClientService.get(data_dict["azp"])
Expand All @@ -130,7 +131,10 @@ async def deserialize(self, token_value) -> SessionAdapter | None:
client_dict=client_dict,
scope=data_dict["scope"])
except Exception as e:
raise asab.exceptions.NotAuthenticatedError() from e
L.error(
"Failed to build session from algorithmic session token claims.", struct_data=data_dict)
raise exceptions.SessionNotFoundError(
"Failed to build session from algorithmic session token claims.") from e

return session

Expand Down

0 comments on commit 020f73f

Please sign in to comment.