From c42dc98f54e2a50f6538d9a0a14c321b28f2ee97 Mon Sep 17 00:00:00 2001 From: Kris Jordan Date: Mon, 20 Mar 2023 11:43:25 -0400 Subject: [PATCH] Fix invalid authorization bearer token error (#11) * Log user out who authenticates with bad token If a token is no longer valid, or does not validate with the key on the server, we are responding with a 401 HTTP status code. In the front-end client, we are intercepting 401 errors and logging the user out of the front-end. This raises an important secondary issue, in other places we may need to fix response code to 403 if a user is validated with system but does not have access to a resource. * Respond with correct error code (403) lacking perm --- backend/api/admin/roles.py | 12 ++++++------ backend/api/admin/users.py | 2 +- backend/api/authentication.py | 10 +++++++--- .../src/app/navigation/http-request.interceptor.ts | 9 ++++++++- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/backend/api/admin/roles.py b/backend/api/admin/roles.py index 22131a8..8fa63eb 100644 --- a/backend/api/admin/roles.py +++ b/backend/api/admin/roles.py @@ -23,7 +23,7 @@ def list_roles( try: return role_service.list(subject) except UserPermissionError as e: - raise HTTPException(status_code=401, detail=str(e)) + raise HTTPException(status_code=403, detail=str(e)) @api.get("/{id}", tags=["Roles"]) @@ -35,7 +35,7 @@ def role_details( try: return role_service.details(subject, id) except UserPermissionError as e: - raise HTTPException(status_code=401, detail=str(e)) + raise HTTPException(status_code=403, detail=str(e)) @api.post('/{id}/permission', tags=["Roles"]) @@ -48,7 +48,7 @@ def grant_permission( try: return role_service.grant(subject, id, permission) except UserPermissionError as e: - raise HTTPException(status_code=401, detail=str(e)) + raise HTTPException(status_code=403, detail=str(e)) @api.delete("/{id}/permission/{permissionId}", tags=["Roles"]) @@ -61,7 +61,7 @@ def revoke_permission( try: return role_service.revoke(subject, id, permissionId) except UserPermissionError as e: - raise HTTPException(status_code=401, detail=str(e)) + raise HTTPException(status_code=403, detail=str(e)) @api.post('/{id}/member', tags=["Roles"]) @@ -74,7 +74,7 @@ def add_member( try: return role_service.add(subject, id, member) except UserPermissionError as e: - raise HTTPException(status_code=401, detail=str(e)) + raise HTTPException(status_code=403, detail=str(e)) @api.delete("/{id}/member/{userId}", tags=["Roles"]) @@ -87,4 +87,4 @@ def remove_member( try: return role_service.remove(subject, id, userId) except UserPermissionError as e: - raise HTTPException(status_code=401, detail=str(e)) + raise HTTPException(status_code=403, detail=str(e)) diff --git a/backend/api/admin/users.py b/backend/api/admin/users.py index 44144c6..dde4ba4 100644 --- a/backend/api/admin/users.py +++ b/backend/api/admin/users.py @@ -29,4 +29,4 @@ def list_users( page=page, page_size=page_size, order_by=order_by, filter=filter) return user_service.list(subject, pagination_params) except UserPermissionError as e: - raise HTTPException(status_code=401, detail=str(e)) + raise HTTPException(status_code=403, detail=str(e)) diff --git a/backend/api/authentication.py b/backend/api/authentication.py index 262f50e..9a74be2 100644 --- a/backend/api/authentication.py +++ b/backend/api/authentication.py @@ -45,12 +45,16 @@ def authenticated_pid( token: HTTPAuthorizationCredentials | None = Depends(HTTPBearer()) ) -> tuple[int, str]: if token: - auth_info = jwt.decode( - token.credentials, _JWT_SECRET, algorithms=[_JST_ALGORITHM]) - return int(auth_info['pid']), auth_info['uid'] + try: + auth_info = jwt.decode( + token.credentials, _JWT_SECRET, algorithms=[_JST_ALGORITHM]) + return int(auth_info['pid']), auth_info['uid'] + except jwt.exceptions.InvalidSignatureError: + ... raise HTTPException(status_code=401, detail='Unauthorized') + @api.get('/verify') def auth_verify(token: str, continue_to: str = '/'): return jwt.decode(token, _JWT_SECRET, algorithms=[_JST_ALGORITHM], options={'verify_signature': True}) diff --git a/frontend/src/app/navigation/http-request.interceptor.ts b/frontend/src/app/navigation/http-request.interceptor.ts index 83577f4..f15ea65 100644 --- a/frontend/src/app/navigation/http-request.interceptor.ts +++ b/frontend/src/app/navigation/http-request.interceptor.ts @@ -10,6 +10,7 @@ import { import { Observable, of } from 'rxjs'; import { catchError, tap } from 'rxjs/operators' import { NavigationService } from './navigation.service'; +import { AuthenticationService } from '../authentication.service'; @Injectable({ providedIn: 'root' @@ -17,7 +18,8 @@ import { NavigationService } from './navigation.service'; export class HttpRequestInterceptor implements HttpInterceptor { constructor( - private navigationService: NavigationService + private navigationService: NavigationService, + private authService: AuthenticationService ) {} intercept(request: HttpRequest, next: HttpHandler): Observable> { @@ -36,7 +38,12 @@ export class HttpRequestInterceptor implements HttpInterceptor { this.navigationService.setSending(false); } if (e instanceof HttpErrorResponse) { + if (e.status === 401) { + this.authService.signOut(); + } else { this.navigationService.error(e); + } + throw e; } return of(e); }),