From 5cc4a7f19138dd952cd1bb0c78f9fd88634a0396 Mon Sep 17 00:00:00 2001 From: Lance Tan <63096217+ltan02@users.noreply.github.com> Date: Sun, 24 Mar 2024 23:27:01 -0700 Subject: [PATCH] Update middleware to support AllowAny (#67) --- backend/auction/urls.py | 2 +- backend/auction/views.py | 12 +- backend/util/authentication.py | 6 +- backend/util/middleware.py | 48 +++++-- frontend/sample.env | 4 +- .../searchBars/ListingsSearchBar.jsx | 4 +- .../timers/CurrentAuctionCountdown.jsx | 4 +- frontend/src/pages/HomePage.jsx | 119 +++++++++--------- frontend/src/pages/ListingsPage.jsx | 12 +- .../pages/auth/bidders/BidderLogInPage.jsx | 4 +- .../pages/auth/bidders/BidderRegisterPage.jsx | 15 +++ frontend/src/utils/auctionUtils.js | 34 +++-- 12 files changed, 162 insertions(+), 102 deletions(-) diff --git a/backend/auction/urls.py b/backend/auction/urls.py index f3ca8dc..27ed768 100644 --- a/backend/auction/urls.py +++ b/backend/auction/urls.py @@ -5,9 +5,9 @@ AddToAuctionApiView, AuctionDetailApiView, AuctionListApiView, + AuctionVehiclesApiView, GetSavedUnitApiView, SaveUnitApiView, - AuctionVehiclesApiView, ) urlpatterns = [ diff --git a/backend/auction/views.py b/backend/auction/views.py index b1530b6..3a76f04 100644 --- a/backend/auction/views.py +++ b/backend/auction/views.py @@ -7,7 +7,7 @@ from core.permissions import IsAdminUser, IsAuthenticated from services.AWSCognitoService import AWSCognitoService -from vehicle.models import SavedUnits, Vehicle, Equipment, Trailer +from vehicle.models import Equipment, SavedUnits, Trailer, Vehicle from .models import Auction, AuctionItem from .serializers import AuctionSerializer @@ -243,5 +243,11 @@ def get(self, request, **kwargs): equipment_data = [{"id": equipment.id} for equipment in equipment_list] trailer_data = [{"id": trailer.id} for trailer in trailer_list] - return Response({"vehicles": vehicle_data, "equipment": equipment_data, - "trailers": trailer_data}, status=status.HTTP_200_OK) + return Response( + { + "vehicles": vehicle_data, + "equipment": equipment_data, + "trailers": trailer_data, + }, + status=status.HTTP_200_OK, + ) diff --git a/backend/util/authentication.py b/backend/util/authentication.py index ad35794..3112b50 100644 --- a/backend/util/authentication.py +++ b/backend/util/authentication.py @@ -34,7 +34,11 @@ def authenticate(self, request): if not token: return (unauthenticated_user, None) - if request.path.startswith("/api/v1/auth"): + if ( + request.path.startswith("/api/v1/auth") + or request.path == "/api/v1/bidders/" + or request.path == "/api/v1/admins/" + ): return (unauthenticated_user, None) try: diff --git a/backend/util/middleware.py b/backend/util/middleware.py index 8973123..38b2bfd 100644 --- a/backend/util/middleware.py +++ b/backend/util/middleware.py @@ -1,26 +1,31 @@ import jwt +import requests +from django.conf import settings from django.utils.deprecation import MiddlewareMixin +from rest_framework import exceptions -from services import AWSCognitoService +from services.AWSCognitoService import AWSCognitoService from util.jwt import decode_token class RefreshTokenMiddleware(MiddlewareMixin): def process_request(self, request): - if request.path.startswith("/api/v1/auth"): + if request.path.startswith("/api/v1/auth") or request.path in [ + "/api/v1/bidders/", + "/api/v1/admins/", + ]: return + id_token = request.COOKIES.get("idToken") refresh_token = request.COOKIES.get("refreshToken") if not refresh_token: return try: - access_token = request.COOKIES.get("accessToken") - jwt.decode(access_token, options={"verify_signature": False}) - return self.get_response(request) + self.verify_jwt_token(id_token) except jwt.ExpiredSignatureError: cognito_service = AWSCognitoService() - decoded_id_token = decode_token(request.COOKIES.get("idToken")) + decoded_id_token = self.decode_jwt_without_validation(id_token) new_tokens = cognito_service.refresh_tokens( decoded_id_token.get("sub"), refresh_token ) @@ -36,7 +41,7 @@ def process_request(self, request): httponly=True, samesite="Lax", ) - if new_tokens.get("RefreshToken"): + if "RefreshToken" in new_tokens: response.set_cookie( "refreshToken", new_tokens.get("RefreshToken"), @@ -46,3 +51,32 @@ def process_request(self, request): return response return None + + def verify_jwt_token(self, token): + jwks_url = settings.SIMPLE_JWT["JWK_URL"] + jwks = requests.get(jwks_url).json() + public_keys = { + jwk["kid"]: jwt.algorithms.RSAAlgorithm.from_jwk(jwk) + for jwk in jwks["keys"] + } + + headers = jwt.get_unverified_header(token) + kid = headers["kid"] + key = public_keys.get(kid) + if not key: + raise exceptions.AuthenticationFailed("Public key not found.") + + return jwt.decode( + token, + key=key, + algorithms=["RS256"], + audience=settings.SIMPLE_JWT["AUDIENCE"], + issuer=settings.SIMPLE_JWT["ISSUER"], + ) + + def decode_jwt_without_validation(self, token): + # Decode without validation + decoded = jwt.decode( + token, options={"verify_signature": False, "verify_exp": False} + ) + return decoded diff --git a/frontend/sample.env b/frontend/sample.env index 53050ed..4aa8b47 100644 --- a/frontend/sample.env +++ b/frontend/sample.env @@ -1,3 +1,3 @@ REACT_APP_NODE_ENV="dev" -REACT_APP_DEV_BACKEND_BASE_URL="http://127.0.0.1:8000/api/v1/" -REACT_APP_PROD_BACKEND_BASE_URL="http://api.auction.microvaninc.com/api/v1/" \ No newline at end of file +REACT_APP_DEV_BACKEND_BASE_URL="http://localhost:8000/api/v1" +REACT_APP_PROD_BACKEND_BASE_URL="https://www.api.auction.microvaninc.com/api/v1" \ No newline at end of file diff --git a/frontend/src/components/searchBars/ListingsSearchBar.jsx b/frontend/src/components/searchBars/ListingsSearchBar.jsx index 37688e6..8e06b14 100644 --- a/frontend/src/components/searchBars/ListingsSearchBar.jsx +++ b/frontend/src/components/searchBars/ListingsSearchBar.jsx @@ -37,10 +37,10 @@ export default function ListingSearchBar({ setResults }) { }; return ( -
@@ -94,13 +94,13 @@ export default function ListingsPage() {