M9-Plan: SAML/ADFS als Alternative dokumentiert
Ergaenzt den Abschnitt, was eine direkte SAML-Anbindung ans ADFS zusaetzlich kosten wuerde - als Entscheidungsgrundlage neben dem beschlossenen OIDC-Weg, nicht als beschlossener Weg. Kernpunkte: SAML braucht ext-dom, ext-simplexml und ext-mbstring sowie Composer; in der aktuellen Dev-Umgebung fehlt jede XML-Faehigkeit (nicht einmal DOMDocument existiert), SAML liesse sich dort weder bauen noch testen. Dazu eigenes SP-Zertifikat samt Erneuerung, eine Tabelle gegen Wiedereinspielung, eine umfangreiche Pruefliste fuer eingehende Assertions und der automatische Zertifikatswechsel von ADFS als haeufigste Stoerungsursache. Empfehlung bleibt OIDC ueber Entra; SAML waere Stufe 3 nach Magic-Link und OIDC, mit der Erweiterungspruefung auf dem Zielhost als erster Aufgabe. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -215,6 +215,175 @@ die Admin-Oberfläche summieren sich.
|
||||
4. Admin-Oberfläche inklusive Testanmeldung.
|
||||
5. `enforce_sso` scharfschalten, Notzugangs-Regeln und Protokollierung.
|
||||
|
||||
---
|
||||
|
||||
## Alternative: SAML 2.0 direkt gegen ADFS
|
||||
|
||||
Nur relevant, wenn ein Kunde die Anmeldung **direkt** am ADFS will statt über
|
||||
Entra ID. Hier steht, was das zusätzlich kostet — als Entscheidungsgrundlage,
|
||||
nicht als beschlossener Weg.
|
||||
|
||||
### Voraussetzungen (zuerst klären)
|
||||
|
||||
SAML heißt XML, und XML heißt PHP-Erweiterungen:
|
||||
|
||||
```text
|
||||
ext-dom Pflicht
|
||||
ext-simplexml Pflicht
|
||||
ext-mbstring Pflicht
|
||||
ext-openssl Pflicht (vorhanden)
|
||||
ext-zlib für Redirect-Binding (vorhanden)
|
||||
Composer für die Bibliothek
|
||||
```
|
||||
|
||||
**In der aktuellen Dev-Umgebung ist davon nichts vorhanden** — `DOMDocument`
|
||||
existiert nicht einmal. SAML lässt sich hier weder entwickeln noch testen. Vor
|
||||
allem anderen muss deshalb geklärt werden:
|
||||
|
||||
1. Welche Erweiterungen bringt der Netcup-Webspace mit (`php -m` dort)?
|
||||
2. Wie sieht eine Entwicklungsumgebung aus, in der man das überhaupt bauen kann?
|
||||
|
||||
Ist Punkt 1 negativ, endet der SAML-Weg hier.
|
||||
|
||||
### Bibliothek
|
||||
|
||||
`onelogin/php-saml` (v4) ist der De-facto-Standard und die realistische Wahl.
|
||||
SimpleSAMLphp ist ein vollständiges Föderations-Framework und für einen
|
||||
einzelnen Service Provider deutlich überdimensioniert.
|
||||
|
||||
**Selbst implementieren ist ausgeschlossen.** XML-Signaturprüfung ist der
|
||||
klassische Ort für *XML Signature Wrapping*: Der Angreifer hängt eine zweite,
|
||||
manipulierte Assertion so ins Dokument, dass die Signaturprüfung das echte
|
||||
Element prüft, die Anwendung aber das gefälschte liest. Diese Klasse von
|
||||
Fehlern hat über Jahre reihenweise SAML-Implementierungen getroffen.
|
||||
|
||||
### Datenmodell
|
||||
|
||||
`tenant_sso_providers` um SAML-Felder erweitern (oder eigene Tabelle):
|
||||
|
||||
```text
|
||||
protocol VARCHAR(10) 'oidc' | 'saml'
|
||||
idp_entity_id VARCHAR(500)
|
||||
idp_sso_url VARCHAR(500)
|
||||
idp_slo_url VARCHAR(500) optional
|
||||
idp_x509_certs TEXT mehrere! siehe Zertifikatswechsel
|
||||
idp_metadata_url VARCHAR(500) für automatische Aktualisierung
|
||||
sp_entity_id VARCHAR(500)
|
||||
attr_email VARCHAR(200) welches Attribut die E-Mail trägt
|
||||
```
|
||||
|
||||
Zusätzlich eine Tabelle gegen Wiedereinspielung:
|
||||
|
||||
```text
|
||||
saml_seen_assertions assertion_id (UNIQUE), tenant_id, expires_at
|
||||
```
|
||||
|
||||
Ohne diese Tabelle kann eine einmal abgefangene Assertion innerhalb ihres
|
||||
Gültigkeitsfensters mehrfach eingelöst werden.
|
||||
|
||||
### Endpunkte
|
||||
|
||||
Alle pfadbasiert auf `APP_HOST`, **keine** Subdomain je Mandant:
|
||||
|
||||
```text
|
||||
/saml/metadata.php?tenant=<slug> SP-Metadaten (XML) für den Kunden
|
||||
/saml/acs.php?tenant=<slug> Assertion Consumer Service (HTTP-POST)
|
||||
/saml/sls.php?tenant=<slug> Single Logout (optional)
|
||||
```
|
||||
|
||||
### SP-Zertifikat
|
||||
|
||||
Der Service Provider braucht ein eigenes Schlüsselpaar (selbstsigniert
|
||||
genügt), dessen öffentlicher Teil in den Metadaten steht:
|
||||
|
||||
- Privater Schlüssel **außerhalb** des Webroots, Rechte 0600.
|
||||
- Laufzeit und Erneuerung einplanen — läuft es ab, bricht die Anmeldung.
|
||||
- Bei Erneuerung müssen die Kunden die Metadaten neu importieren, sofern sie
|
||||
sie nicht per URL automatisch beziehen.
|
||||
|
||||
### Prüfliste für eingehende Assertions
|
||||
|
||||
Diese Punkte muss die Umsetzung nachweislich abdecken:
|
||||
|
||||
- Die **Assertion** selbst muss signiert sein, nicht nur die Response.
|
||||
- `Issuer` stimmt mit `idp_entity_id` des Mandanten überein.
|
||||
- `Audience` ist unsere `sp_entity_id`.
|
||||
- `Destination`/`Recipient` entsprechen unserer ACS-URL.
|
||||
- `NotBefore` / `NotOnOrAfter` gültig, mit definierter Toleranz.
|
||||
- `InResponseTo` passt zu einer von uns gestellten Anfrage.
|
||||
- `assertion_id` wurde noch nicht verwendet (Wiedereinspielung).
|
||||
- Unsignierte Assertions und SHA-1 werden **abgelehnt**.
|
||||
|
||||
Zur Zeittoleranz: SAML reagiert empfindlich auf Uhrabweichungen. Die
|
||||
Angleichung von PHP und MySQL (siehe Commit `064c872`) ist dafür Voraussetzung;
|
||||
zusätzlich sollte die Serverzeit per NTP laufen.
|
||||
|
||||
### ADFS-Besonderheiten
|
||||
|
||||
- **Automatischer Zertifikatswechsel**: ADFS erneuert sein Token-Signing-
|
||||
Zertifikat standardmäßig selbsttätig (jährlich, Ankündigung 30 Tage vorher).
|
||||
Wer nur ein Zertifikat fest hinterlegt, steht an diesem Tag still. Deshalb
|
||||
entweder **mehrere** Zertifikate parallel akzeptieren oder die
|
||||
IdP-Metadaten regelmäßig per Cron neu einlesen. Das ist die mit Abstand
|
||||
häufigste Störungsursache bei ADFS-Anbindungen.
|
||||
- **Claim Rules** muss der Kunde bei sich anlegen: E-Mail bzw. UPN als NameID
|
||||
oder als Attribut. Ohne passende Regel kommt eine Assertion ohne E-Mail an.
|
||||
- ADFS erwartet SHA-256; SHA-1 ist abgekündigt.
|
||||
- Der Kunde importiert unsere Metadaten als **Relying Party Trust** (per URL
|
||||
oder Datei).
|
||||
|
||||
### Mandantenfähigkeit
|
||||
|
||||
Ein Service Provider, viele IdPs. Der Mandant ergibt sich aus dem
|
||||
aufgerufenen ACS-Pfad **und** muss zusätzlich gegen den `Issuer` der Assertion
|
||||
geprüft werden. Stimmen beide nicht überein, wird abgelehnt — sonst könnte
|
||||
eine gültige Assertion aus Mandant A an der ACS-URL von Mandant B eingereicht
|
||||
werden.
|
||||
|
||||
Es gelten unverändert die Regeln aus dem OIDC-Teil: kein automatisches
|
||||
Anlegen von Konten, `saas_session_login()` direkt mit festem Mandanten, nie
|
||||
über die Mandantenauswahl.
|
||||
|
||||
### Oberfläche für den Mandanten-Administrator
|
||||
|
||||
1. SP-Metadaten zum Herunterladen bzw. als URL zum Kopieren.
|
||||
2. IdP-Metadaten hinterlegen: als URL (bevorzugt, ermöglicht automatische
|
||||
Aktualisierung) oder als hochgeladene XML-Datei.
|
||||
3. Beim Einlesen fremder XML-Dateien externe Entitäten und Netzwerkzugriffe
|
||||
unterbinden (XXE); unter PHP 8 ist das Standard, muss aber abgesichert
|
||||
bleiben.
|
||||
4. Testanmeldung, bevor `enforce_sso` aktiviert werden darf.
|
||||
|
||||
### Testbarkeit
|
||||
|
||||
Ohne echtes ADFS zum Ausprobieren wird das nichts. Möglichkeiten, absteigend
|
||||
nach Aussagekraft: ein ADFS-Testsystem des Kunden, ein lokales SimpleSAMLphp
|
||||
als Test-IdP, oder Entra ID als SAML-IdP konfiguriert (der Kunde hat es
|
||||
ohnehin) — Letzteres testet den Weg allerdings nicht gegen ADFS selbst.
|
||||
|
||||
### Aufwand im Vergleich
|
||||
|
||||
| | OIDC (Entra) | SAML (ADFS) |
|
||||
|---|---|---|
|
||||
| Zusätzliche PHP-Erweiterungen | keine | dom, simplexml, mbstring |
|
||||
| Composer nötig | nein | ja |
|
||||
| Fremdbibliothek | optional | zwingend |
|
||||
| Eigene Zertifikate | nein | ja, inkl. Erneuerung |
|
||||
| Zertifikatswechsel der Gegenseite | entfällt | jährlich, bricht sonst |
|
||||
| Wiedereinspielungsschutz | über `nonce` | eigene Tabelle nötig |
|
||||
| Prüfschritte am Token | überschaubar | umfangreiche Prüfliste |
|
||||
| In der Dev-Umgebung baubar | ja | **nein** |
|
||||
|
||||
### Empfehlung
|
||||
|
||||
Weiterhin OIDC über Entra ID. SAML lohnt sich nur, wenn ein Kunde
|
||||
ausdrücklich kein Entra für diese Anwendung zulässt — und selbst dann wäre der
|
||||
Umweg über einen Broker (Keycloak/Authentik übersetzt SAML nach OIDC) meist
|
||||
günstiger als eine eigene SAML-Implementierung samt Zertifikatspflege.
|
||||
|
||||
Falls SAML doch kommt: **nach** Stufe 1 und 2, als eigenständige Stufe 3, und
|
||||
mit der Erweiterungsprüfung auf dem Zielhost als erster Aufgabe.
|
||||
|
||||
## Offene Punkte
|
||||
|
||||
- **Composer**: Für OIDC nicht zwingend nötig (`openssl` + `json` +
|
||||
|
||||
Reference in New Issue
Block a user