from typing import Any, Dict import httpx import pytest import respx from authlib.jose import jwt from starlette.applications import Starlette from starlette.middleware import Middleware from starlette.requests import Request from starlette.responses import Response from starlette.testclient import TestClient from owslib.auth import AsyncJWTAuth from owslib.ext.starlette.middleware.auth import JWTAuthenticationMiddleware from tests.typing import MakeTokenType @pytest.fixture def auth() -> AsyncJWTAuth: return AsyncJWTAuth(jwks_url="https://test/.well-known/jwks") @pytest.fixture def app(auth: AsyncJWTAuth) -> Starlette: app = Starlette( middleware=[ Middleware( JWTAuthenticationMiddleware, enabled=True, exclude_paths=["/public"], auth=auth, ), ] ) @app.route("/private") def private(request: Request) -> Response: return Response("ok") @app.route("/public") def public(request: Request) -> Response: return Response("ok") return app @pytest.fixture def client(app: Starlette) -> TestClient: return TestClient(app) def test_jwt_auth_private_endpoint_denied(client: TestClient) -> 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: TestClient, auth: AsyncJWTAuth, respx_mock: respx.MockRouter, jwk_set: Dict[str, Any], ) -> None: respx_mock.get(auth.jwks_url).mock( return_value=httpx.Response(status_code=200, json=jwk_set) ) token_string = jwt.encode({"alg": "HS256"}, {}, key="secret") response = client.get( "/private", headers={"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: TestClient, make_token: MakeTokenType, auth: AsyncJWTAuth, respx_mock: respx.MockRouter, jwk_set: Dict[str, Any], ) -> None: respx_mock.get(auth.jwks_url).mock( return_value=httpx.Response(status_code=200, json=jwk_set) ) token_string = make_token({}) response = client.get( "/private", headers={"authorization": f"bearer {token_string}"}, ) assert response.status_code == 200 def test_jwt_auth_public_endpoint(client: TestClient) -> None: response = client.get("/public") assert response.status_code == 200