feat(auth): Anmeldung ueber Microsoft Entra (SSO)

OpenID Connect mit Authorization Code Flow und PKCE, vollstaendig
serverseitig - der Browser sieht weder Tenant- noch Client-ID. Genutzt wird
dieselbe App-Registrierung wie die Postfachanbindung, also kein zweites
Secret; delegiert statt app-only.

Nach dem Token-Tausch beweist ein Aufruf von /me bei Graph, dass das
Zugriffstoken gilt, und liefert die Objekt-ID. Sie landet in der neuen Spalte
crm_users.entra_oid und ist danach die stabile Verknuepfung - die E-Mail-
Adresse eines Menschen kann sich aendern, die Objekt-ID nicht.

Bewusst so entschieden:
  - Es werden keine Konten angelegt. Wer kein CRM-Konto mit derselben Adresse
    hat, wird abgewiesen; Zugriff vergibt weiter die Nutzerverwaltung.
  - Die Anmeldung mit Benutzername und Passwort bleibt fuer alle bestehen -
    Notzugang, falls Entra oder das Secret ausfaellt.
  - Das CRM-Token kommt als Einmal-Ticket zurueck, nicht in der Adresszeile:
    die Rueckleitung ist ein GET und stuende sonst in Browserverlauf und
    Apache-Log.
  - Keine Signaturpruefung des ID-Tokens und damit keine JWKS-Bibliothek. Es
    kommt ueber TLS direkt vom Token-Endpunkt (OIDC Core 3.1.3.7); geprueft
    werden aud, tid, nonce und exp, und der Graph-Aufruf belegt den Rest.

Ohne MS_SSO_ENABLED=true bleibt alles aus und die Anmeldemaske sieht aus wie
bisher.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sascha Wolf
2026-09-21 08:14:23 +02:00
co-authored by Claude Opus 5
parent 2d84bac91d
commit 419e57b55d
23 changed files with 1188 additions and 19 deletions
+26
View File
@@ -94,3 +94,29 @@ SCANNER_SCHEDULER_OFFSET=0
# Fallback fuer den OpenAI-Key; bevorzugt wird der Wert aus den Einstellungen.
# OPENAI_API_KEY=
# ---------------------------------------------------------------------------
# Anmeldung ueber Microsoft Entra (SSO)
# ---------------------------------------------------------------------------
# Nutzt dieselbe App-Registrierung wie die Postfachanbindung - also dieselben
# MS_TENANT_ID / MS_CLIENT_ID / MS_CLIENT_SECRET, kein zweites Secret.
#
# In Entra zusaetzlich noetig:
# - Authentifizierung > Plattform hinzufuegen > Web
# Umleitungs-URI: der Wert von MS_SSO_REDIRECT_URI, zeichengenau
# Implizite Genehmigung: beide Haken aus
# - Delegierte Berechtigungen mit Administratorzustimmung:
# openid, profile, User.Read (Foto zusaetzlich: ProfilePhoto.Read.All)
#
# Es werden keine Konten angelegt: wer sich per Microsoft anmeldet, braucht ein
# bestehendes CRM-Konto mit derselben E-Mail-Adresse. Die Anmeldung mit
# Benutzername und Passwort bleibt parallel bestehen.
#
# Ohne MS_SSO_ENABLED=true bleibt alles aus und die Anmeldemaske sieht aus wie
# bisher.
MS_SSO_ENABLED=false
MS_SSO_REDIRECT_URI=https://crm.perinco.de/api/auth/sso/callback
# Optionale Einschraenkung auf E-Mail-Domains, kommagetrennt. Leer = keine
# zusaetzliche Pruefung; Tenant und vorhandenes CRM-Konto begrenzen ohnehin.
MS_SSO_ALLOWED_DOMAINS=perinco.de