from typing import Any, Dict import httpx import pytest import respx from authlib.jose import jwt from django.conf import Settings from django.http import HttpResponse from django.test.client import Client from django.urls import path from tests.typing import MakeTokenType pytestmark = pytest.mark.urls(__name__) urlpatterns = [ path("public", lambda request: HttpResponse("ok")), path("private", lambda request: HttpResponse("ok")), ] @pytest.fixture def jwks_url() -> str: return "https://test/.well-known/jwks" @pytest.fixture(autouse=True) def configure(settings: Settings, jwks_url: str) -> None: settings.MIDDLEWARE = [ # type: ignore "owslib.ext.django.middleware.auth.JWTAuthenticationMiddleware", ] settings.JWT_AUTH_JWKS_URL = jwks_url # type: ignore settings.JWT_AUTH_ENABLED = True # type: ignore settings.JWT_AUTH_EXCLUDE_PATHS = ["/public"] # type: ignore def test_jwt_auth_private_endpoint_denied(client: Client) -> None: response = client.get("/private") assert response.status_code == 401 assert response.json() == { "code": "missing_authorization", "message": 'Missing "Authorization" in headers.', "detail": {}, } def test_jwt_auth_private_endpoint_invalid_authorization( client: Client, respx_mock: respx.MockRouter, jwk_set: Dict[str, Any], jwks_url: str, ) -> None: respx_mock.get(jwks_url).mock( return_value=httpx.Response(status_code=200, json=jwk_set) ) token_string = jwt.encode({"alg": "HS256"}, {}, key="secret1") response = client.get( "/private", HTTP_AUTHORIZATION=f"bearer {token_string}", ) assert response.status_code == 401 assert response.json() == { "code": "invalid_token", "message": ( "The access token provided is expired, revoked, malformed, or " "invalid for other reasons." ), "detail": {}, } def test_jwt_auth_private_endpoint_valid_authorization( client: Client, make_token: MakeTokenType, respx_mock: respx.MockRouter, jwk_set: Dict[str, Any], jwks_url: str, ) -> None: respx_mock.get(jwks_url).mock( return_value=httpx.Response(status_code=200, json=jwk_set) ) token_string = make_token({"sub": "10000"}) response = client.get( "/private", HTTP_AUTHORIZATION=f"bearer {token_string}", ) assert response.status_code == 200 def test_jwt_auth_public_endpoint(client: Client) -> None: response = client.get("/public") assert response.status_code == 200