81 lines
2.8 KiB
Markdown
81 lines
2.8 KiB
Markdown
|
|
# 0005 — Keycloak SSO mit Dev-Bypass für Read/Write-Trennung
|
||
|
|
|
||
|
|
| | |
|
||
|
|
|---|---|
|
||
|
|
| **Status** | accepted |
|
||
|
|
| **Datum** | 2026-04-10 |
|
||
|
|
| **Refs** | Issue #43, Commit 7159240 + 303b30f, app/auth.py |
|
||
|
|
|
||
|
|
## Kontext
|
||
|
|
|
||
|
|
Die Webapp soll öffentlich durchsuchbar sein (Assessments lesen, PDFs
|
||
|
|
ansehen, Auswertungen), aber Analyse-Aktionen (Antrag bewerten, Programme
|
||
|
|
indexieren) nur authentifizierten Nutzern erlauben. Der User betreibt
|
||
|
|
bereits einen Keycloak-Server unter `sso.toppyr.de` mit Realm `collaboration`.
|
||
|
|
|
||
|
|
## Optionen
|
||
|
|
|
||
|
|
### Option A — Keycloak-only mit hartem 401
|
||
|
|
|
||
|
|
Alle POST-Endpoints erfordern JWT. Ohne Keycloak-Server läuft nichts.
|
||
|
|
|
||
|
|
**Vorteile:** Klar, sicher.
|
||
|
|
**Nachteile:** Lokale Entwicklung blockiert ohne Keycloak-Instanz.
|
||
|
|
|
||
|
|
### Option B — Dev-Bypass: Auth nur wenn ENV gesetzt
|
||
|
|
|
||
|
|
Wenn `KEYCLOAK_URL` leer ist → ALLE Endpoints offen (Dev-Modus).
|
||
|
|
Wenn gesetzt → POST-Endpoints erfordern JWT, GET bleibt offen.
|
||
|
|
|
||
|
|
**Vorteile:** Lokale Dev ohne Keycloak. Prod sofort sicher per ENV.
|
||
|
|
**Nachteile:** Versehentlich Prod ohne ENV = alles offen.
|
||
|
|
|
||
|
|
### Option C — API-Key statt Keycloak
|
||
|
|
|
||
|
|
Einfacher API-Key-Header für POST-Endpoints.
|
||
|
|
|
||
|
|
**Vorteile:** Zero-Dependency.
|
||
|
|
**Nachteile:** Kein SSO, kein User-Identity, keine Gruppen/Rollen.
|
||
|
|
|
||
|
|
## Entscheidung
|
||
|
|
|
||
|
|
**Option B.** Dev-Bypass ermöglicht reibungslose lokale Entwicklung und
|
||
|
|
Batch-Skripte (die keinen JWT haben). Prod-Absicherung über die drei
|
||
|
|
ENV-Vars in docker-compose.yml. Die Keycloak-Client-Registrierung in
|
||
|
|
`sso.toppyr.de` ist ein einmaliger manueller Schritt.
|
||
|
|
|
||
|
|
## Implementation
|
||
|
|
|
||
|
|
- `app/auth.py`: JWKS-Cache (1h TTL), `get_current_user` (optional),
|
||
|
|
`require_auth` (pflicht), `keycloak_login_url` (für Browser-Redirect)
|
||
|
|
- POST-Endpoints (`/analyze`, `/api/analyze-drucksache`,
|
||
|
|
`/api/programme/index`): `user: dict = Depends(require_auth)`
|
||
|
|
- GET-Endpoints: unverändert offen
|
||
|
|
- Frontend: `initAuth()` prüft `/api/auth/me`, steuert
|
||
|
|
"Jetzt prüfen"-Button (disabled + Tooltip wenn nicht eingeloggt)
|
||
|
|
und "Anmelden"-Button im Header
|
||
|
|
|
||
|
|
## Konsequenzen
|
||
|
|
|
||
|
|
### Positiv
|
||
|
|
|
||
|
|
- Read-Only für alle, Write nur mit Login — klare Trennung
|
||
|
|
- Batch-Skripte und auto-Re-Analyse im Container laufen im Dev-Modus
|
||
|
|
(KEYCLOAK_URL nicht gesetzt), keine Auth-Hürde für Maintenance
|
||
|
|
- Keycloak-Rollen über `realm_access.roles` im JWT verfügbar für
|
||
|
|
künftige Gruppen-Features (#94 Bookmarks/Kommentare)
|
||
|
|
|
||
|
|
### Negativ
|
||
|
|
|
||
|
|
- Dev-Modus ist unsicher — wenn jemand KEYCLOAK_URL in Prod vergisst
|
||
|
|
zu setzen, ist alles offen. Mitigation: Health-Endpoint oder
|
||
|
|
Startup-Warning wenn ENV fehlt.
|
||
|
|
- JWKS-Cache (1h) bedeutet: nach Key-Rotation dauert es bis zu 1h bis
|
||
|
|
alte Tokens abgelehnt werden. Für dieses Projekt akzeptabel.
|
||
|
|
|
||
|
|
### Folgen für andere ADRs
|
||
|
|
|
||
|
|
- #94 Bookmarks/Kommentare baut auf der User-Identity aus dem JWT auf
|
||
|
|
(`sub`, `email`, `realm_access.roles`).
|
||
|
|
- #95 Queuing könnte Auth-User priorisieren.
|