Skip to content

Commit

Permalink
Check usernames in tokens match before refreshing access token #129
Browse files Browse the repository at this point in the history
  • Loading branch information
VKTB committed Nov 8, 2024
1 parent fb6894c commit c80ac0c
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 3 deletions.
6 changes: 6 additions & 0 deletions scigateway_auth/common/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ class MaintenanceFileWriteError(Exception):
"""


class UsernameMismatchError(Exception):
"""
Exception raised when the usernames in the access and refresh tokens do not match.
"""


class UserNotAdminError(Exception):
"""
Exception raised when a non-admin user performs an action that requires the user to be an admin.
Expand Down
3 changes: 2 additions & 1 deletion scigateway_auth/routers/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
ICATAuthenticationError,
InvalidJWTError,
JWTRefreshError,
UsernameMismatchError,
)
from scigateway_auth.common.schemas import LoginDetailsPostRequestSchema
from scigateway_auth.src.authentication import ICATAuthenticator
Expand Down Expand Up @@ -97,7 +98,7 @@ def refresh_access_token(
try:
access_token = jwt_handler.refresh_access_token(token, refresh_token)
return JSONResponse(content=access_token)
except (BlacklistedJWTError, InvalidJWTError, JWTRefreshError) as exc:
except (BlacklistedJWTError, InvalidJWTError, JWTRefreshError, UsernameMismatchError) as exc:
message = "Unable to refresh access token"
logger.exception(message)
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=message) from exc
Expand Down
12 changes: 10 additions & 2 deletions scigateway_auth/src/jwt_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
BlacklistedJWTError,
InvalidJWTError,
JWTRefreshError,
UsernameMismatchError,
)
from scigateway_auth.src.authentication import ICATAuthenticator

Expand Down Expand Up @@ -52,7 +53,10 @@ def get_refresh_token(self, icat_username: str) -> str:
"""
logger.info("Getting a refresh token")
return self._pack_jwt(
{"exp": datetime.now(timezone.utc) + timedelta(days=config.authentication.refresh_token_validity_days)},
{
"username": icat_username,
"exp": datetime.now(timezone.utc) + timedelta(days=config.authentication.refresh_token_validity_days),
},
)

def refresh_access_token(self, access_token: str, refresh_token: str):
Expand All @@ -62,16 +66,20 @@ def refresh_access_token(self, access_token: str, refresh_token: str):
:param access_token: The JWT access token to refresh.
:param refresh_token: The JWT refresh token.
:raises JWTRefreshError: If the JWT access token cannot be refreshed.
:raises UsernameMismatchError: If the usernames in the access and refresh tokens do not match
:return: JWT access token with an updated expiry time.
"""
logger.info("Refreshing access token")

if self._is_refresh_token_blacklisted(refresh_token):
raise BlacklistedJWTError(f"Attempted refresh from token in blacklist: {refresh_token}")

self.verify_token(refresh_token)
refresh_token_payload = self.verify_token(refresh_token)
try:
access_token_payload = self._get_jwt_payload(access_token, {"verify_exp": False})
if access_token_payload["username"] != refresh_token_payload["username"]:
raise UsernameMismatchError("The usernames in the access and refresh tokens do not match")

access_token_payload["exp"] = datetime.now(timezone.utc) + timedelta(
minutes=config.authentication.access_token_validity_minutes,
)
Expand Down

0 comments on commit c80ac0c

Please sign in to comment.