Anmeldung über einen generischen OIDC-Anbieter (Ziel authentik) mit Discovery, PKCE, state und nonce, dazu ein lokaler Login mit argon2 als Notfallzugang. Die Rechte stehen in einer Tabelle, die Prüfung liegt ausschließlich serverseitig, und Rolle wie Aktiv-Status werden bei jeder Anfrage aus der Datenbank gelesen — eine entzogene Rolle greift damit sofort, ein abgeschaltetes Konto kommt nicht mit gültigem Cookie noch zwölf Stunden weiter. Kein Auth.js: v5 steht dauerhaft auf Beta, das Projekt ist im Wartungsmodus und sein Prisma-Adapter deckt Prisma 7 nicht ab. Stattdessen openid-client und jose, wie in ProxLedger. Die API von openid-client 6 wurde vorher gegen die Typdefinitionen im Paket geprüft, nicht aus dem Gedächtnis geschrieben. Ein unabhängiger Review hat einen Blocker und acht weitere Befunde gefunden, alle behoben. Der wichtigste war eine offene Weiterleitung: die Prüfung des Rücksprungziels verglich Präfixe, und "/<TAB>/fremd.example" besteht alle drei Bedingungen. Browser entfernen Tabulator, Zeilenumbruch und Wagenrücklauf beim Verarbeiten einer URL, übrig bleibt "//fremd.example" und damit ein fremder Host — genau das Phishing, das die Prüfung abwehren sollte. Sie löst das Ziel jetzt gegen eine Wegwerf-Basis auf und vergleicht die Herkunft. Weitere Befunde: jede OIDC-Anmeldung hätte ohne konfigurierte Gruppen die Rolle still auf LESER gesetzt, bei einem einzigen Administrator ohne Rückweg; die Verknüpfung über die E-Mail-Adresse geschah ohne email_verified und wäre der Weg gewesen, den lokalen Notfall-Administrator zu übernehmen; der letzte aktive Administrator konnte sich selbst herabstufen. Drei Fehler waren meine eigenen. Der Platzhalter-Hash gegen den Zeitkanal war erfunden und hätte sofort geworfen statt Zeit zu kosten, die Zusage wäre also falsch gewesen. nextUrl.origin lieferte im Test localhost statt 127.0.0.1 und wäre hinter einem Reverse Proxy der interne Host; alle Umleitungen gehen jetzt über APP_URL. Und overflow-x: hidden auf body hat die eigene Mobil-Prüfung blind gemacht — auf der Benutzerseite war bei 390 px ein Knopf abgeschnitten, ohne dass scrollWidth es zeigen konnte. 274 Tests, darunter die vollständige Rechtematrix, die Angriffe auf das Rücksprungziel, die Trennung von Sitzungs- und Kurzzeit-Token und ein struktureller Nachweis, dass jede Server Action mit einer Rechteprüfung beginnt. Closes #7 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
78 lines
2.8 KiB
Bash
78 lines
2.8 KiB
Bash
# Laufzettel – Umgebungsvariablen.
|
||
# Kopieren nach .env und ausfuellen. Die .env gehoert nie ins Repo.
|
||
|
||
# ---------- Pflicht ----------
|
||
|
||
# Oeffentliche Adresse der Anwendung. Steckt in den QR-Codes und in der
|
||
# OIDC-Rueckruf-Adresse, muss also stimmen, wenn ein Reverse Proxy davor haengt.
|
||
APP_URL=https://laufzettel.example.de
|
||
|
||
# Geheimnis fuer Sitzungs-Cookies und die Verschluesselung des LDAP-Bind-Passworts.
|
||
# Mindestens 32 Zeichen. Erzeugen mit: openssl rand -base64 48
|
||
APP_SECRET=
|
||
|
||
# Zugang zur Datenbank. Im Compose-Stand wird der Dienstname postgres verwendet
|
||
# und die Datenbank ist von aussen nicht erreichbar.
|
||
POSTGRES_USER=laufzettel
|
||
POSTGRES_PASSWORD=
|
||
POSTGRES_DB=laufzettel
|
||
DATABASE_URL=postgresql://laufzettel:@postgres:5432/laufzettel?schema=public
|
||
|
||
# ---------- Anmeldung ----------
|
||
|
||
# Lokaler Login mit E-Mail und Passwort. Fuer die Entwicklung und als Notfallzugang.
|
||
# Im Betrieb mit OIDC auf false setzen.
|
||
AUTH_LOCAL_ENABLED=false
|
||
|
||
# Generischer OIDC-Anbieter, Ziel ist authentik. Leer lassen, um OIDC abzuschalten.
|
||
OIDC_ISSUER=
|
||
OIDC_CLIENT_ID=
|
||
OIDC_CLIENT_SECRET=
|
||
OIDC_NAME=authentik
|
||
# Angeforderte Bereiche. Der Standard reicht fuer authentik mit dem
|
||
# Gruppen-Mapping aus docs/betrieb/authentik.md. Nur aendern, wenn der Anbieter
|
||
# die Gruppen unter einem anderen Bereich liefert.
|
||
OIDC_SCOPE=openid profile email groups
|
||
|
||
# Zuordnung der Rollen ueber den groups-Claim. Wird bei jedem Login neu ausgewertet.
|
||
OIDC_GROUP_ADMIN=lz-admin
|
||
OIDC_GROUP_EDITOR=lz-redakteur
|
||
OIDC_GROUP_TECHNICIAN=lz-techniker
|
||
OIDC_GROUP_VIEWER=lz-leser
|
||
|
||
# Optional, nur im Betriebsmodus Dienstleistung: Gruppen wie lz-kunde-MUS binden
|
||
# Benutzer an Kunden. TECHNIKER und LESER sehen dann nur ihre Kunden.
|
||
# Leer lassen heisst: keine Einschraenkung.
|
||
OIDC_CUSTOMER_GROUP_PREFIX=
|
||
|
||
# ---------- Betrieb ----------
|
||
|
||
# Adresse, auf die der Webdienst gebunden wird. Standard ist nur localhost,
|
||
# davor gehoert ein Reverse Proxy. Fuer direkten Zugriff im LAN: 0.0.0.0
|
||
BIND_ADDR=127.0.0.1
|
||
APP_PORT=3000
|
||
|
||
# Wird beim Bauen in die Anzeige unten links uebernommen.
|
||
APP_VERSION=0.1.0
|
||
GIT_SHA=
|
||
|
||
# ---------- Seed ----------
|
||
|
||
SEED_ADMIN_EMAIL=admin@firma.example
|
||
SEED_ADMIN_PASSWORD=
|
||
# INTERN (Standard) oder DIENSTLEISTUNG. SERVICE wird als Alias akzeptiert.
|
||
SEED_MODE=INTERN
|
||
|
||
# Name der eigenen Organisation. Im Modus INTERN taucht er nirgends in der
|
||
# Oberflaeche auf, wird aber beim Wechsel zu DIENSTLEISTUNG zum ersten Kunden.
|
||
SEED_ORG_NAME=Eigene Organisation
|
||
# 2 bis 6 Grossbuchstaben oder Ziffern. Im Modus INTERN unsichtbar; im Modus
|
||
# DIENSTLEISTUNG steht das Kuerzel auf Etiketten und in der Hostname-Regel.
|
||
SEED_ORG_KUERZEL=EIGEN
|
||
|
||
# ---------- Tests ----------
|
||
|
||
# Datenbank fuer Vitest. Ohne diese Variable ueberspringen sich die Datenbanktests.
|
||
# Passend zu docker-compose.dev.yml (Port 5434, umstellbar ueber DEV_DB_PORT):
|
||
TEST_DATABASE_URL=postgresql://laufzettel:laufzettel@localhost:5434/laufzettel_test?schema=public
|