From 271e6e1f26347dde8e39c89efc8ce5891b2f3f1b Mon Sep 17 00:00:00 2001 From: Kraiem Taha Yassine Date: Wed, 31 Jul 2024 11:31:28 +0200 Subject: [PATCH] Dev (#2444) * refactor(chalice): upgraded dependencies * refactor(chalice): upgraded dependencies feat(chalice): support heatmaps * fix(chalice): fixed Math-operators validation refactor(chalice): search for sessions that have events for heatmaps * refactor(chalice): search for sessions that have at least 1 location event for heatmaps * refactor(chalice): upgraded dependencies * refactor(chalice): upgraded dependencies feat(chalice): support heatmaps * fix(chalice): fixed Math-operators validation refactor(chalice): search for sessions that have events for heatmaps * refactor(chalice): search for sessions that have at least 1 location event for heatmaps * refactor(chalice): upgraded dependencies refactor(crons): upgraded dependencies refactor(alerts): upgraded dependencies * feat(chalice): get top 10 values for autocomplete CH * refactor(chalice): cleaned code refactor(chalice): upgraded dependencies refactor(alerts): upgraded dependencies refactor(crons): upgraded dependencies * feat(chalice): autocomplete return top 10 with stats * fix(chalice): fixed autocomplete top 10 meta-filters * feat(chalice): spot login/logout/refresh * feat(chalice): spot only allow authorized endpoints feat(chalice): spot get Slack channels * refactor(chalice): refactored JWT authorizer refactor(chalice): enhanced Spot endpoint access control --- api/auth/auth_jwt.py | 151 ++++++++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 67 deletions(-) diff --git a/api/auth/auth_jwt.py b/api/auth/auth_jwt.py index ddee4d3d5..7989406ac 100644 --- a/api/auth/auth_jwt.py +++ b/api/auth/auth_jwt.py @@ -27,81 +27,95 @@ def _get_current_auth_context(request: Request, jwt_payload: dict) -> schemas.Cu return request.state.currentContext +async def _process_refresh_call(request: Request) -> schemas.CurrentContext: + if "refreshToken" not in request.cookies: + logger.warning("Missing refreshToken cookie.") + jwt_payload = None + else: + jwt_payload = authorizers.jwt_refresh_authorizer(scheme="Bearer", token=request.cookies["refreshToken"]) + + if jwt_payload is None or jwt_payload.get("jti") is None: + logger.warning("Null refreshToken's payload, or null JTI.") + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, + detail="Invalid refresh-token or expired refresh-token.") + auth_exists = users.refresh_auth_exists(user_id=jwt_payload.get("userId", -1), + jwt_jti=jwt_payload["jti"]) + if not auth_exists: + logger.warning("refreshToken's user not found.") + logger.warning(jwt_payload) + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, + detail="Invalid refresh-token or expired refresh-token.") + + credentials: HTTPAuthorizationCredentials = await super(JWTAuth, self).__call__(request) + if credentials: + if not credentials.scheme == "Bearer": + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + detail="Invalid authentication scheme.") + old_jwt_payload = authorizers.jwt_authorizer(scheme=credentials.scheme, token=credentials.credentials, + leeway=datetime.timedelta( + days=config("JWT_LEEWAY_DAYS", cast=int, default=3) + )) + if old_jwt_payload is None \ + or old_jwt_payload.get("userId") is None \ + or old_jwt_payload.get("userId") != jwt_payload.get("userId"): + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Invalid token or expired token.") + + return _get_current_auth_context(request=request, jwt_payload=jwt_payload) + + logger.warning("Invalid authorization code (refresh logic).") + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid authorization code for refresh.") + + +async def _process_spot_refresh_call(request: Request) -> schemas.CurrentContext: + if "refreshToken" not in request.cookies: + logger.warning("Missing sopt-refreshToken cookie.") + jwt_payload = None + else: + jwt_payload = authorizers.jwt_refresh_authorizer(scheme="Bearer", token=request.cookies["refreshToken"]) + + if jwt_payload is None or jwt_payload.get("jti") is None: + logger.warning("Null spot-refreshToken's payload, or null JTI.") + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, + detail="Invalid spot-refresh-token or expired refresh-token.") + auth_exists = spot.refresh_auth_exists(user_id=jwt_payload.get("userId", -1), + jwt_jti=jwt_payload["jti"]) + if not auth_exists: + logger.warning("spot-refreshToken's user not found.") + logger.warning(jwt_payload) + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, + detail="Invalid spot-refresh-token or expired refresh-token.") + + credentials: HTTPAuthorizationCredentials = await super(JWTAuth, self).__call__(request) + if credentials: + if not credentials.scheme == "Bearer": + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + detail="Invalid spot-authentication scheme.") + old_jwt_payload = authorizers.jwt_authorizer(scheme=credentials.scheme, token=credentials.credentials, + leeway=datetime.timedelta( + days=config("JWT_LEEWAY_DAYS", cast=int, default=3) + )) + if old_jwt_payload is None \ + or old_jwt_payload.get("userId") is None \ + or old_jwt_payload.get("userId") != jwt_payload.get("userId"): + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, + detail="Invalid spot-token or expired token.") + + return _get_current_auth_context(request=request, jwt_payload=jwt_payload) + + logger.warning("Invalid authorization code (spot-refresh logic).") + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid authorization code for spot-refresh.") + + class JWTAuth(HTTPBearer): def __init__(self, auto_error: bool = True): super(JWTAuth, self).__init__(auto_error=auto_error) async def __call__(self, request: Request) -> Optional[schemas.CurrentContext]: if request.url.path in ["/refresh", "/api/refresh"]: - if "refreshToken" not in request.cookies: - logger.warning("Missing refreshToken cookie.") - jwt_payload = None - else: - jwt_payload = authorizers.jwt_refresh_authorizer(scheme="Bearer", token=request.cookies["refreshToken"]) - - if jwt_payload is None or jwt_payload.get("jti") is None: - logger.warning("Null refreshToken's payload, or null JTI.") - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, - detail="Invalid refresh-token or expired refresh-token.") - auth_exists = users.refresh_auth_exists(user_id=jwt_payload.get("userId", -1), - jwt_jti=jwt_payload["jti"]) - if not auth_exists: - logger.warning("refreshToken's user not found.") - logger.warning(jwt_payload) - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, - detail="Invalid refresh-token or expired refresh-token.") - - credentials: HTTPAuthorizationCredentials = await super(JWTAuth, self).__call__(request) - if credentials: - if not credentials.scheme == "Bearer": - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, - detail="Invalid authentication scheme.") - old_jwt_payload = authorizers.jwt_authorizer(scheme=credentials.scheme, token=credentials.credentials, - leeway=datetime.timedelta( - days=config("JWT_LEEWAY_DAYS", cast=int, default=3) - )) - if old_jwt_payload is None \ - or old_jwt_payload.get("userId") is None \ - or old_jwt_payload.get("userId") != jwt_payload.get("userId"): - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Invalid token or expired token.") - - return _get_current_auth_context(request=request, jwt_payload=jwt_payload) + return await _process_refresh_call(request) elif request.url.path in ["/spot/refresh", "/spot/api/refresh"]: - if "refreshToken" not in request.cookies: - logger.warning("Missing sopt-refreshToken cookie.") - jwt_payload = None - else: - jwt_payload = authorizers.jwt_refresh_authorizer(scheme="Bearer", token=request.cookies["refreshToken"]) - - if jwt_payload is None or jwt_payload.get("jti") is None: - logger.warning("Null spot-refreshToken's payload, or null JTI.") - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, - detail="Invalid spot-refresh-token or expired refresh-token.") - auth_exists = spot.refresh_auth_exists(user_id=jwt_payload.get("userId", -1), - jwt_jti=jwt_payload["jti"]) - if not auth_exists: - logger.warning("spot-refreshToken's user not found.") - logger.warning(jwt_payload) - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, - detail="Invalid spot-refresh-token or expired refresh-token.") - - credentials: HTTPAuthorizationCredentials = await super(JWTAuth, self).__call__(request) - if credentials: - if not credentials.scheme == "Bearer": - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, - detail="Invalid spot-authentication scheme.") - old_jwt_payload = authorizers.jwt_authorizer(scheme=credentials.scheme, token=credentials.credentials, - leeway=datetime.timedelta( - days=config("JWT_LEEWAY_DAYS", cast=int, default=3) - )) - if old_jwt_payload is None \ - or old_jwt_payload.get("userId") is None \ - or old_jwt_payload.get("userId") != jwt_payload.get("userId"): - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, - detail="Invalid spot-token or expired token.") - - return _get_current_auth_context(request=request, jwt_payload=jwt_payload) + return await _process_refresh_call(request) else: credentials: HTTPAuthorizationCredentials = await super(JWTAuth, self).__call__(request) @@ -131,6 +145,9 @@ class JWTAuth(HTTPBearer): # Allow access to spot endpoints only raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Unauthorized access (spot).") + elif jwt_payload.get("aud", "").startswith("front") and request.url.path.startswith("/spot"): + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, + detail="Unauthorized access endpoint reserved for Spot only.") return _get_current_auth_context(request=request, jwt_payload=jwt_payload)