from typing import Any, Dict import httpx import pytest import respx from authlib.jose import jwt from flask import Flask from flask.testing import FlaskClient from owslib.auth import JWTAuth from owslib.ext.flask.auth import JWTAuth as JWTAuthExt from tests.typing import MakeTokenType @pytest.fixture def auth() -> JWTAuth: return JWTAuth(jwks_url="https://test/.well-known/jws") @pytest.fixture def app(auth: JWTAuth) -> Flask: app = Flask("test") jwt_auth = JWTAuthExt(enabled=True, exclude_paths=["/public"]) jwt_auth.init_app(app) # Replace default auth jwt_auth.auth = auth @app.get("/private") def private() -> str: return "ok" @app.get("/public") def public() -> str: return "ok" return app @pytest.fixture def client(app: Flask) -> FlaskClient: return app.test_client() def test_jwt_auth_private_endpoint_denied(client: FlaskClient) -> 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: FlaskClient, auth: JWTAuth, 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="secret1") 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: FlaskClient, make_token: MakeTokenType, auth: JWTAuth, 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({"sub": "10000"}) response = client.get( "/private", headers={"authorization": f"bearer {token_string}"}, ) assert response.status_code == 200 def test_jwt_auth_public_endpoint(client: FlaskClient) -> None: response = client.get("/public") assert response.status_code == 200