feat(anmeldung): lokale Benutzerkonten mit Pflicht-TOTP (#035)

Ohne authentik gab es nur den Notfall-Admin – ein geteiltes Konto ohne
Rollen und ohne erkennbare Akteure im Audit-Log. Admins legen jetzt
lokale Konten an; sshkv erzeugt ein Einmal-Passwort, das bei der ersten
Anmeldung ersetzt wird, danach ist TOTP Pflicht.

Rollen, Sperren (beendet Sitzungen sofort) und Zurücksetzen unter
Einstellungen → Benutzer, nur für Admins mit frischer Bestätigung.
SSHKV_LOKALE_KONTEN=0 schaltet lokale Konten ab; der Notfall-Admin
bleibt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 22:36:25 +02:00
co-authored by Claude Opus 5.5
parent d9eec3d991
commit 4219701b29
41 changed files with 1295 additions and 109 deletions
+2 -2
View File
@@ -66,10 +66,10 @@ test("OIDC ohne sshkv-Gruppe wird abgewiesen", async ({ page }) => {
test("Notfall-Admin richtet TOTP ein und bestätigt sich erneut", async ({ page }) => {
test.skip(NOTFALL_PASSWORT.length < 16, "SSHKV_BREAKGLASS_PASSWORD fehlt in .env");
await page.goto("/anmelden");
await page.getByText("Notfallzugang", { exact: true }).click();
await page.getByText("Lokales Konto oder Notfallzugang", { exact: true }).click();
await page.getByLabel("Anmeldename").fill("notfall");
await page.getByLabel("Passwort").fill(NOTFALL_PASSWORT);
await page.getByRole("button", { name: "Mit Notfallzugang anmelden" }).click();
await page.getByRole("button", { name: "Mit Benutzername anmelden" }).click();
await expect(page).toHaveURL(/\/anmelden\/totp/);
await expect(page.getByRole("img", { name: /QR-Code/ })).toBeVisible();