Private JWK files were written under the default umask (observed 0664 — group and world readable). Create the key directory 0700, chmod private key files (private_jwks.json, token_jwks.json) to 0600 after they are written, and refuse to start if a pre-existing private key is group/world accessible. Tests now use an isolated per-test key directory. Refs: porchlight-91i Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
57 lines
2.1 KiB
Python
57 lines
2.1 KiB
Python
from pathlib import Path
|
|
|
|
from httpx import ASGITransport, AsyncClient
|
|
|
|
from porchlight.app import create_app
|
|
from porchlight.config import Settings
|
|
|
|
|
|
async def test_configured_clients_are_registered(tmp_path: Path) -> None:
|
|
"""Clients defined in config should be registered in the OIDC server."""
|
|
toml_content = """\
|
|
issuer = "https://test.example.com"
|
|
|
|
[clients.test-rp]
|
|
client_secret = "test-secret-0123456789abcdef"
|
|
redirect_uris = ["https://app.example.com/callback"]
|
|
scope = ["openid", "profile"]
|
|
"""
|
|
toml_file = tmp_path / "test.toml"
|
|
toml_file.write_text(toml_content)
|
|
|
|
settings = Settings(_toml_file=str(toml_file), session_secret="x" * 32, signing_key_path=str(tmp_path / "keys"))
|
|
app = create_app(settings)
|
|
|
|
async with (
|
|
AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client,
|
|
app.router.lifespan_context(app),
|
|
):
|
|
response = await client.get("/health")
|
|
assert response.status_code == 200
|
|
|
|
oidc_server = app.state.oidc_server
|
|
assert "test-rp" in oidc_server.context.cdb
|
|
cdb_entry = oidc_server.context.cdb["test-rp"]
|
|
assert cdb_entry["client_id"] == "test-rp"
|
|
assert cdb_entry["client_secret"] == "test-secret-0123456789abcdef"
|
|
assert ("https://app.example.com/callback", {}) in cdb_entry["redirect_uris"]
|
|
assert cdb_entry["scope"] == ["openid", "profile"]
|
|
assert cdb_entry["allowed_scopes"] == ["openid", "profile"]
|
|
|
|
|
|
async def test_manage_app_always_registered(tmp_path: Path) -> None:
|
|
"""The internal manage-app client is always registered, even without config file clients."""
|
|
settings = Settings(
|
|
issuer="https://test.example.com", session_secret="x" * 32, signing_key_path=str(tmp_path / "keys")
|
|
)
|
|
app = create_app(settings)
|
|
|
|
async with (
|
|
AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client,
|
|
app.router.lifespan_context(app),
|
|
):
|
|
response = await client.get("/health")
|
|
assert response.status_code == 200
|
|
|
|
oidc_server = app.state.oidc_server
|
|
assert "manage-app" in oidc_server.context.cdb
|