fix(auth): protect setup and expire sessions
This commit is contained in:
@@ -10,10 +10,25 @@ PASSWORD = "correct horse battery staple"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_setup_requires_bootstrap_secret(tmp_path) -> None:
|
||||
conftest = importlib.import_module("conftest")
|
||||
config = importlib.import_module("backup_tool.config")
|
||||
app_module = importlib.import_module("backup_tool.api.app")
|
||||
settings = conftest.make_settings(tmp_path).model_copy(
|
||||
update={"public_base_url": "https://backup.example.test", "bootstrap_secret": "bootstrap"}
|
||||
key = tmp_path / "master.key"
|
||||
key.write_bytes(b"m2-test-master-key-material-32-bytes-minimum")
|
||||
key.chmod(0o600)
|
||||
roots = []
|
||||
for name in ("data", "repositories", "sources", "restores"):
|
||||
path = tmp_path / name
|
||||
path.mkdir()
|
||||
roots.append(path)
|
||||
settings = config.Settings(
|
||||
data_dir=roots[0],
|
||||
database_url=f"sqlite+aiosqlite:///{roots[0] / 'metadata.db'}",
|
||||
repository_roots=(roots[1],),
|
||||
local_source_roots=(roots[2],),
|
||||
restore_roots=(roots[3],),
|
||||
master_key_file=key,
|
||||
public_base_url="https://backup.example.test",
|
||||
bootstrap_secret="bootstrap-secret-123",
|
||||
)
|
||||
cli = importlib.import_module("backup_tool.cli")
|
||||
from alembic import command
|
||||
@@ -21,10 +36,21 @@ async def test_remote_setup_requires_bootstrap_secret(tmp_path) -> None:
|
||||
|
||||
command.upgrade(cli.build_alembic_config(settings), "head")
|
||||
app = app_module.create_app(settings)
|
||||
async with AsyncClient(transport=ASGITransport(app=app), base_url="https://backup.example.test") as client:
|
||||
denied = await client.post("/api/v2/setup", json={"username": "admin", "password": PASSWORD})
|
||||
async with AsyncClient(
|
||||
transport=ASGITransport(app=app), base_url="https://backup.example.test"
|
||||
) as client:
|
||||
denied = await client.post(
|
||||
"/api/v2/setup", json={"username": "admin", "password": PASSWORD}
|
||||
)
|
||||
assert denied.status_code == 403
|
||||
accepted = await client.post("/api/v2/setup", json={"username": "admin", "password": PASSWORD, "bootstrap_secret": "bootstrap"})
|
||||
accepted = await client.post(
|
||||
"/api/v2/setup",
|
||||
json={
|
||||
"username": "admin",
|
||||
"password": PASSWORD,
|
||||
"bootstrap_secret": "bootstrap-secret-123",
|
||||
},
|
||||
)
|
||||
assert accepted.status_code == 201
|
||||
await app.state.engine.dispose()
|
||||
|
||||
@@ -33,5 +59,11 @@ def test_expired_session_is_rejected(tmp_path) -> None:
|
||||
auth = importlib.import_module("backup_tool.security.auth")
|
||||
key = tmp_path / "master.key"
|
||||
key.write_bytes(b"x" * 32)
|
||||
expired = auth.sign_session("user", "csrf", key, expires_at=datetime.now(UTC) - timedelta(seconds=1), session_id="session")
|
||||
expired = auth.sign_session(
|
||||
"user",
|
||||
"csrf",
|
||||
key,
|
||||
expires_at=datetime.now(UTC) - timedelta(seconds=1),
|
||||
session_id="session",
|
||||
)
|
||||
assert auth.verify_session(expired, key) is None
|
||||
|
||||
Reference in New Issue
Block a user