feat(auth): Passwort-Login (1FA) für die App; Admin ebenfalls 1FA
Variante 1: Senioren behalten ihren persönlichen Link; zusätzlich ein Passwort-Einstieg ohne 2FA über Authelia. - Neuer Endpunkt GET /api/login (app_login): hinter Authelia (nginx-Location /login, one_factor), erkennt den per Remote-User weitergereichten Nutzer (Admin ODER normaler Authelia-Nutzer), mintet das va_token-Cookie und leitet in die App (/). Cookie-Mint in _issue_login_cookie() gemeinsam mit /api/admin/login refaktoriert. - "Persönlicher Zugang nötig"-Seite (main.py) bekommt einen großen Knopf „Mit Benutzername & Passwort anmelden" -> /login. Bare / leitet bewusst NICHT automatisch um (Senioren ohne Authelia-Konto würden sonst feststecken). Begleitende Infra (außerhalb des Repos): - nginx: location = /login (auth_request one_factor -> /api/login). - Authelia: access_control-Regel voice.jamulix.de -> one_factor (über der *.jamulix.de-Wildcard); damit sind App-Login UND Admin nur noch 1FA, andere Subdomains bleiben 2FA. Tests: /api/login für Nicht-Admin/Admin/ohne-Identität. 257 Offline-Tests grün. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
904f7db82c
commit
6792e1be86
3 changed files with 63 additions and 21 deletions
|
|
@ -71,3 +71,26 @@ def test_admin_login_rejects_without_identity(forward_auth):
|
|||
# (In Produktion faengt nginx das vorher mit dem Authelia-Redirect ab.)
|
||||
r = client.get("/api/admin/login", follow_redirects=False)
|
||||
assert r.status_code == 403
|
||||
|
||||
|
||||
# --- /api/login (1FA-Passwort-Einstieg, auch fuer Nicht-Admins) ---
|
||||
|
||||
def test_app_login_non_admin_gets_cookie(forward_auth):
|
||||
# Normaler Authelia-Nutzer (kein Admin) bekommt trotzdem ein gueltiges Cookie.
|
||||
r = client.get("/api/login", headers={HEADER: "lieschen"}, follow_redirects=False)
|
||||
assert r.status_code == 303
|
||||
assert r.headers["location"] == "/"
|
||||
raw = r.headers["set-cookie"].split(f"{CAPABILITY_COOKIE}=", 1)[1].split(";", 1)[0]
|
||||
user = deps.get_store().get_user_by_token(raw)
|
||||
assert user is not None and user.external_id == "lieschen"
|
||||
|
||||
|
||||
def test_app_login_admin_also_works(forward_auth):
|
||||
r = client.get("/api/login", headers={HEADER: "dschlueter"}, follow_redirects=False)
|
||||
assert r.status_code == 303
|
||||
assert f"{CAPABILITY_COOKIE}=" in r.headers.get("set-cookie", "")
|
||||
|
||||
|
||||
def test_app_login_rejects_without_identity(forward_auth):
|
||||
r = client.get("/api/login", follow_redirects=False)
|
||||
assert r.status_code == 403
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue