""" Integration tests for OAuth 2.0 metadata endpoint. Tests the /.well-known/oauth-authorization-server endpoint per RFC 8414. """ import json import pytest from fastapi.testclient import TestClient @pytest.fixture def metadata_app(monkeypatch, tmp_path): """Create app for metadata testing.""" db_path = tmp_path / "test.db" monkeypatch.setenv("GONDULF_SECRET_KEY", "a" * 32) monkeypatch.setenv("GONDULF_BASE_URL", "https://auth.example.com") monkeypatch.setenv("GONDULF_DATABASE_URL", f"sqlite:///{db_path}") monkeypatch.setenv("GONDULF_DEBUG", "true") from gondulf.main import app return app @pytest.fixture def metadata_client(metadata_app): """Create test client for metadata tests.""" with TestClient(metadata_app) as client: yield client class TestMetadataEndpoint: """Tests for OAuth 2.0 Authorization Server Metadata endpoint.""" def test_metadata_returns_json(self, metadata_client): """Test metadata endpoint returns JSON response.""" response = metadata_client.get("/.well-known/oauth-authorization-server") assert response.status_code == 200 assert "application/json" in response.headers["content-type"] def test_metadata_includes_issuer(self, metadata_client): """Test metadata includes issuer field.""" response = metadata_client.get("/.well-known/oauth-authorization-server") data = response.json() assert "issuer" in data assert data["issuer"] == "https://auth.example.com" def test_metadata_includes_authorization_endpoint(self, metadata_client): """Test metadata includes authorization endpoint.""" response = metadata_client.get("/.well-known/oauth-authorization-server") data = response.json() assert "authorization_endpoint" in data assert data["authorization_endpoint"] == "https://auth.example.com/authorize" def test_metadata_includes_token_endpoint(self, metadata_client): """Test metadata includes token endpoint.""" response = metadata_client.get("/.well-known/oauth-authorization-server") data = response.json() assert "token_endpoint" in data assert data["token_endpoint"] == "https://auth.example.com/token" def test_metadata_includes_response_types(self, metadata_client): """Test metadata includes supported response types.""" response = metadata_client.get("/.well-known/oauth-authorization-server") data = response.json() assert "response_types_supported" in data assert "code" in data["response_types_supported"] def test_metadata_includes_grant_types(self, metadata_client): """Test metadata includes supported grant types.""" response = metadata_client.get("/.well-known/oauth-authorization-server") data = response.json() assert "grant_types_supported" in data assert "authorization_code" in data["grant_types_supported"] def test_metadata_includes_token_auth_methods(self, metadata_client): """Test metadata includes token endpoint auth methods.""" response = metadata_client.get("/.well-known/oauth-authorization-server") data = response.json() assert "token_endpoint_auth_methods_supported" in data assert "none" in data["token_endpoint_auth_methods_supported"] class TestMetadataCaching: """Tests for metadata endpoint caching behavior.""" def test_metadata_includes_cache_header(self, metadata_client): """Test metadata endpoint includes Cache-Control header.""" response = metadata_client.get("/.well-known/oauth-authorization-server") assert "Cache-Control" in response.headers # Should allow caching assert "public" in response.headers["Cache-Control"] assert "max-age" in response.headers["Cache-Control"] def test_metadata_is_cacheable(self, metadata_client): """Test metadata endpoint allows public caching.""" response = metadata_client.get("/.well-known/oauth-authorization-server") cache_control = response.headers["Cache-Control"] # Should be cacheable for a reasonable time assert "public" in cache_control class TestMetadataSecurity: """Security tests for metadata endpoint.""" def test_metadata_includes_security_headers(self, metadata_client): """Test metadata endpoint includes security headers.""" response = metadata_client.get("/.well-known/oauth-authorization-server") assert "X-Frame-Options" in response.headers assert "X-Content-Type-Options" in response.headers def test_metadata_requires_no_authentication(self, metadata_client): """Test metadata endpoint is publicly accessible.""" response = metadata_client.get("/.well-known/oauth-authorization-server") # Should work without any authentication assert response.status_code == 200 def test_metadata_returns_valid_json(self, metadata_client): """Test metadata returns valid parseable JSON.""" response = metadata_client.get("/.well-known/oauth-authorization-server") # Should not raise data = json.loads(response.content) assert isinstance(data, dict)