from typing import Any, Dict, List, Optional from authlib.oauth2 import OAuth2Error from django.conf import settings from django.http import HttpRequest, HttpResponse, JsonResponse from owslib.auth import JWTAuth, jwt_auth_enabled_for_env, jwt_auth_from_config from owslib.ext.django.settings import ENVIRONMENT from owslib.ext.django.typing import GetResponseCallable from owslib.urlpath import is_path_match # Settings ENABLED: Optional[bool] = getattr(settings, "JWT_AUTH_ENABLED", None) EXCLUDE_PATHS: Optional[List[str]] = getattr(settings, "JWT_AUTH_EXCLUDE_PATHS", None) JWKS_URL: Optional[str] = getattr(settings, "JWT_AUTH_JWKS_URL", None) CLAIM_OPTIONS: Optional[Dict[str, Any]] = getattr( settings, "JWT_AUTH_CLAIM_OPTIONS", None ) CACHE_TIMEOUT: Optional[int] = getattr(settings, "JWT_AUTH_CACHE_TIMEOUT", None) REALM: Optional[str] = getattr(settings, "JWT_AUTH_REALM", None) def _get_auth() -> Optional[JWTAuth]: if not JWKS_URL: return None return JWTAuth( jwks_url=JWKS_URL, claims_options=CLAIM_OPTIONS, cache_timeout=CACHE_TIMEOUT, realm=REALM, ) class JWTAuthenticationMiddleware: def __init__(self, get_response: GetResponseCallable) -> None: self.get_response = get_response self.enabled = jwt_auth_enabled_for_env(ENVIRONMENT, enabled=ENABLED) self.exclude_paths = EXCLUDE_PATHS self.auth = _get_auth() or jwt_auth_from_config( environment=ENVIRONMENT, cache_timeout=CACHE_TIMEOUT, realm=REALM, ) def __call__(self, request: HttpRequest) -> HttpResponse: if self.enabled and not is_path_match( request.path, match=self.exclude_paths, ): try: token = self.auth.authenticate(request.headers.get("authorization")) except OAuth2Error as exc: headers = dict(exc.get_headers()) headers.pop("Content-Type", None) return JsonResponse( data={ "code": exc.error or "Authentication error", "message": exc.get_error_description(), "detail": {}, }, status=exc.status_code, headers=headers, ) setattr(request, "token", token) return self.get_response(request)