Authentifizierung & Authority¶
Das MoE-System unterscheidet zwei vollständig getrennte Authentifizierungsebenen:
| Ebene | Zugangspunkt | Nutzer |
|---|---|---|
| Admin-Backend | /login |
Admins (mit is_admin = 1) |
| User-Portal | /user/login |
Endnutzer (alle Rollen) |
Admin-Authentifizierung¶
Lokale Anmeldung¶
- Formular ausfüllen: Benutzername + Passwort + CSRF-Token
- Passwort-Prüfung: bcrypt-Vergleich via passlib
is_admin = 1muss gesetzt sein — normale User werden abgewiesen- Session wird angelegt:
OIDC / Authentik (optional)¶
Erfordert folgende Umgebungsvariablen:
| Variable | Beschreibung |
|---|---|
AUTHENTIK_URL |
Basis-URL der Authentik-Instanz |
OIDC_CLIENT_ID |
OAuth2-Client-ID |
OIDC_CLIENT_SECRET |
OAuth2-Client-Secret |
Flow:
Admin öffnet /login
│
Button "Mit Authentik anmelden (SSO)"
│
GET /auth/login → Redirect zu Authentik /application/o/authorize/
│ Scopes: openid profile email groups
│
User authentifiziert sich bei Authentik
│
GET /auth/callback?code=... → Token-Exchange /application/o/token/
│
Admin-Check: user muss in Gruppe "moe-admins" ODER is_superuser=true
│
Session anlegen + OIDC-Token speichern
Admin-Prüfung bei OIDC:
Logout¶
- Lokale Anmeldung: Session löschen
- OIDC: Session löschen + Redirect zu Authentik
end-session/Endpunkt
User-Portal-Authentifizierung¶
Anmeldung¶
Formular unter /user/login:
- Benutzername + Passwort eingeben
- bcrypt-Passwort-Vergleich
is_active = 1wird geprüft (gesperrte User werden abgewiesen)- Session:
Passwort-Reset-Flow¶
/user/forgot-password
│ E-Mail-Adresse eingeben
│
Token generieren (secrets.token_urlsafe(32))
Token-Hash in DB: password_reset_tokens (TTL 1 Stunde, single-use)
E-Mail versenden (wenn SMTP konfiguriert)
│
/user/reset-password?token=...
│ Token validieren (nicht abgelaufen, noch nicht genutzt)
│
Neues Passwort eingeben (min. 8 Zeichen)
bcrypt-Hash speichern
Token als used markieren
Sicherheitsverhalten
Bei /user/forgot-password zeigt das System immer die Meldung „Falls ein Account existiert..." — unabhängig davon, ob die E-Mail tatsächlich registriert ist. Dadurch werden Account-Enumerations verhindert.
API-Key-Authentifizierung¶
Für API-Anfragen an den Orchestrator werden API-Keys verwendet. Kein Session-Cookie, kein Login — stateless.
Unterstützte Header¶
Validierungsablauf¶
Incoming Request
│
Header parsen → Key extrahieren
│
SHA-256 berechnen: hash = sha256(key)
│
Redis-Lookup: GET user:apikey:{hash}
│ │
Cache Hit Cache Miss
TTL 5 Minuten SQLite-Lookup:
SELECT ... FROM api_keys
WHERE key_hash = ? AND is_active = 1
JOIN users WHERE is_active = 1
│
Redis-Cache befüllen (TTL 300s)
│
User-Objekt prüfen:
- is_active == 1?
- Budget nicht überschritten?
- Permissions für angeforderte Ressource?
│
Request ausführen oder ablehnen (401/403/429)
Redis-Schema¶
user:apikey:{sha256-hash} → HASH
user_id STRING
username STRING
role STRING (user|subscriber|expert|admin)
is_active STRING (1|0)
daily_limit STRING (Integer oder leer = unlimitiert)
monthly_limit STRING
total_limit STRING
permissions STRING (JSON: {resource_type: [id, ...]})
cost_factor STRING (Float)
TTL: 300 Sekunden
CSRF-Schutz¶
Alle Formulare im Admin-Backend und User-Portal sind CSRF-geschützt:
- Token generiert per Session:
secrets.token_hex(16) - Validiert Server-seitig mit
secrets.compare_digest() - Session-Lebensdauer: max. 8 Stunden (
SESSION_MAX_AGE = 28800)
Session-Konfiguration¶
Admin-Impersonation¶
Admins können User-Sessions übernehmen:
- Admin-Session wird geprüft (
is_admin = 1) - User-Session wird für die laufende Sitzung gesetzt:
- Redirect zu
/user/dashboard - Oranges Impersonation-Banner erscheint
Beenden:
Setzt Admin-Session zurück, löscht User-Impersonation-Flags.Sicherheitsübersicht¶
| Mechanismus | Implementierung |
|---|---|
| Passwort-Hashing | bcrypt (passlib) |
| API-Key-Speicherung | SHA-256 Hash, nie Klartext |
| CSRF-Schutz | HMAC-basierter Session-Token |
| Session-TTL | 8 Stunden |
| Redis-Cache-TTL | 5 Minuten (API-Keys) |
| OIDC-Gruppe | moe-admins |
| Password-Reset-TTL | 1 Stunde, single-use |
| Budget-Enforcement | Redis-Counter + Orchestrator-Check |