This commit is contained in:
1 parent
4db3f45164
commit
d25c04cdd2
175 files changed
+56243
-15
No files matched your search
@@ -0,0 +1,103 @@
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
import httpx2
|
||||
|
||||
from gewu.adapters.git_repository import GitCanonicalRepository
|
||||
from gewu.adapters.sqlite_identity import SQLiteIdentityStore
|
||||
from gewu.application.reading import CanonicalNodeReader
|
||||
from gewu.bootstrap.app import create_app
|
||||
|
||||
|
||||
def test_admin_credentials_sessions_and_secret_free_audit(tmp_path: Path) -> None:
|
||||
async def exercise() -> None:
|
||||
store = SQLiteIdentityStore(tmp_path / "identity.sqlite3")
|
||||
admin = store.provision(credential_id="admin", principal_id="operator", roles=("admin",))
|
||||
viewer = store.provision(credential_id="viewer", principal_id="reader", roles=("viewer",))
|
||||
mixed = store.provision(
|
||||
credential_id="mixed", principal_id="agent", roles=("agent", "admin")
|
||||
)
|
||||
app = create_app(
|
||||
identity_provider=store,
|
||||
credential_administration=store,
|
||||
node_reader=CanonicalNodeReader(GitCanonicalRepository(tmp_path / "knowledge.git")),
|
||||
)
|
||||
async with httpx2.AsyncClient(
|
||||
transport=httpx2.ASGITransport(app=app), base_url="http://test"
|
||||
) as http:
|
||||
assert (await http.get("/v1/admin/credentials")).status_code == 401
|
||||
for token in (viewer, mixed):
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
assert (await http.get("/v1/admin/credentials", headers=headers)).status_code == 403
|
||||
assert (await http.get("/v1/admin/events", headers=headers)).status_code == 403
|
||||
assert (
|
||||
await http.post(
|
||||
"/v1/admin/credentials",
|
||||
headers=headers,
|
||||
json={
|
||||
"credential_id": "denied",
|
||||
"principal_id": "denied",
|
||||
"role": "admin",
|
||||
},
|
||||
)
|
||||
).status_code == 403
|
||||
assert (
|
||||
await http.delete("/v1/admin/credentials/viewer", headers=headers)
|
||||
).status_code == 403
|
||||
session = await http.post("/v1/session", headers={"Authorization": f"Bearer {admin}"})
|
||||
csrf = {"X-GEWU-CSRF": session.json()["csrf_token"]}
|
||||
body = {
|
||||
"credential_id": "new",
|
||||
"principal_id": "researcher",
|
||||
"role": "agent",
|
||||
"project_ids": ["pilot"],
|
||||
}
|
||||
assert (await http.post("/v1/admin/credentials", json=body)).status_code == 403
|
||||
assert (
|
||||
await http.post(
|
||||
"/v1/admin/credentials", json=body, headers={**csrf, "Origin": "https://other"}
|
||||
)
|
||||
).status_code == 403
|
||||
assert (
|
||||
await http.post("/v1/admin/credentials", headers=csrf, content=b" " * 4097)
|
||||
).status_code == 413
|
||||
assert (
|
||||
await http.post(
|
||||
"/v1/admin/credentials", headers=csrf, json={**body, "project_ids": []}
|
||||
)
|
||||
).status_code == 422
|
||||
created = await http.post("/v1/admin/credentials", headers=csrf, json=body)
|
||||
assert created.status_code == 201
|
||||
token = created.json()["token"]
|
||||
principal = store.authenticate(token)
|
||||
assert principal and principal.project_ids == frozenset({"pilot"})
|
||||
assert (
|
||||
await http.post("/v1/admin/credentials", headers=csrf, json=body)
|
||||
).status_code == 409
|
||||
listing = await http.get("/v1/admin/credentials")
|
||||
assert listing.headers["cache-control"] == "private, no-store"
|
||||
assert token not in listing.text and "token_digest" not in listing.text
|
||||
assert (
|
||||
await http.delete("/v1/admin/credentials/admin", headers=csrf)
|
||||
).status_code == 409
|
||||
assert (await http.delete("/v1/admin/credentials/new")).status_code == 403
|
||||
assert (await http.delete("/v1/admin/credentials/new", headers=csrf)).status_code == 200
|
||||
assert store.authenticate(token) is None
|
||||
assert (await http.delete("/v1/admin/credentials/new", headers=csrf)).status_code == 404
|
||||
# Revocation invalidates already-issued browser sessions as well as bearer keys.
|
||||
viewer_session = store.create_browser_session(viewer)
|
||||
assert (
|
||||
await http.delete("/v1/admin/credentials/viewer", headers=csrf)
|
||||
).status_code == 200
|
||||
assert store.authenticate_browser_session(viewer_session.session_token) is None
|
||||
events = await http.get("/v1/admin/events")
|
||||
assert [e["action"] for e in events.json()] == [
|
||||
"credential.revoked",
|
||||
"credential.revoked",
|
||||
"credential.created",
|
||||
]
|
||||
assert token not in events.text and admin not in events.text
|
||||
reopened = SQLiteIdentityStore(store.database)
|
||||
assert len(reopened.list_admin_events(limit=50)) == 3
|
||||
|
||||
asyncio.run(exercise())
|
||||
Reference in new issue
Block a user