Let administrators link Microsoft accounts whose UPN differs from mail
Some checks are pending
CI / PHP lint (7.4) (pull_request) Waiting to run
CI / PHP lint (8.0) (pull_request) Waiting to run
CI / PHP lint (8.1) (pull_request) Waiting to run
CI / PHP lint (8.2) (pull_request) Waiting to run
CI / PHP lint (8.3) (pull_request) Waiting to run
CI / PHP lint (8.4) (pull_request) Waiting to run
CI / WordPress Coding Standards (pull_request) Waiting to run
CI / WordPress.org Plugin Check (pull_request) Waiting to run

Privileged accounts are never linked through the settable mail
attribute. Two new ways make that workable when UPN and e-mail differ:

- "Link Microsoft account" on the profile screen: the signed-in user
  (nonce, same browser via the state cookie, same user at the callback)
  signs in with Microsoft once and binds that identity. Existing links
  can only be removed by an administrator; an object ID bound elsewhere
  is refused.
- "Assigned Microsoft account (UPN)" per user, editable by
  administrators, used by sign-in and user sync; with an option to
  remove a link.

Sign-in now finds accounts by bound object ID first, then by assigned
UPN, then by e-mail, so linked users sign in whatever their addresses.

Also: third-audit report (docs/security-audit.md section 7), README
section on linking administrator accounts, translations, tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Friederich Loheide 2026-09-24 03:57:45 +00:00
parent 9b893e42bc
commit 81b3a74ae5
12 changed files with 1583 additions and 995 deletions

View file

@ -32,6 +32,7 @@
- [Nur-Button-Modus & Fallback](#nur-button-modus--fallback)
- [Eigene Login-Seite](#eigene-login-seite)
- [Benutzer-Sync](#benutzer-sync)
- [Administrator-Konten verknüpfen](#administrator-konten-verknüpfen)
- [Sicherheitskonzept](#sicherheitskonzept)
- [Shortcode & Hooks](#shortcode--hooks)
- [Fehlerbehebung](#fehlerbehebung)
@ -304,12 +305,11 @@ Plugins, die `wp-login.php` umbenennen (z. B. WPS Hide Login), sind kompatibel,
### Benutzer-Sync
> **Administrator-Konten** (alle mit `manage_options`, `promote_users`, `edit_users` oder Super-Admin) werden nie über das
> `mail`-Attribut verknüpft, sondern nur, wenn der **User Principal Name** eines Mitglieds (kein Gast) exakt ihrer
> WordPress-E-Mail entspricht das `mail`-Attribut kann jeder Benutzer- oder Exchange-Admin des Tenants frei setzen, der
> UPN nur auf verifizierten Domains. Dieselbe Regel gilt für die erste Microsoft-Anmeldung eines Administrators. Ihre
> E-Mail-Adresse ändert der Sync nie automatisch. Bei allen anderen Konten informiert WordPress die alte Adresse über eine
> Änderung.
> **Privilegierte Konten** (Administratoren, Redakteure mit `unfiltered_html`, alle mit Rechten an Benutzern, Plugins
> oder Themes auf irgendeiner Site des Netzwerks sowie deaktivierte Konten, die solche Rollen zurückbekämen) werden
> nie über das frei setzbare `mail`-Attribut verknüpft. Siehe [Administrator-Konten verknüpfen](#administrator-konten-verknüpfen).
> Ihre E-Mail-Adresse ändert der Sync nie automatisch. Bei allen anderen Konten informiert WordPress die alte Adresse über
> eine Änderung.
Tab *Benutzer-Sync*. Legt WordPress-Konten für Microsoft-365-Benutzer an und hält sie aktuell manuell per Knopfdruck,
automatisch per WP-Cron (stündlich, zweimal täglich, täglich) oder per WP-CLI.
@ -385,6 +385,22 @@ wp m365-login sync --dry-run # Testlauf
wp m365-login sync # echter Lauf
```
### Administrator-Konten verknüpfen
Das `mail`-Attribut in Entra ID kann jeder Benutzer- oder Exchange-Administrator des Tenants frei setzen wer es auf die
Adresse eines WordPress-Admins setzt, dürfte sonst dessen Konto übernehmen. Privilegierte Konten werden deshalb nur auf
einem dieser Wege mit einem Microsoft-Konto verknüpft (per Anmeldung oder Sync):
| Weg | Wann sinnvoll |
| --- | --- |
| **Selbst verknüpfen:** *Profil → Microsoft 365 → „Mit Microsoft-Konto verknüpfen“*. Die Person ist in WordPress angemeldet (beweist das WordPress-Konto) und meldet sich einmal bei Microsoft an (beweist das Microsoft-Konto). | Immer auch wenn UPN und Mailadresse völlig verschieden sind. Im Nur-Button-Modus vorher über den Fallback-Link mit Passwort anmelden. |
| **Zuweisen:** Ein Administrator trägt beim Bearbeiten des Benutzers unter *Microsoft 365* den **UPN** ein (*Zugewiesenes Microsoft-Konto*). Anmeldung und Sync verknüpfen genau dieses Konto. | Mehrere Admins einrichten, ohne dass jeder selbst klicken muss. |
| **Automatisch:** UPN eines Mitglieds (kein Gast) = WordPress-E-Mail. | Wenn UPN und Mailadresse bei euch gleich sind. |
Nach der Verknüpfung findet die Anmeldung das Konto über die unveränderliche Objekt-ID E-Mail-Adresse oder UPN dürfen sich
danach ändern. Eine bestehende Verknüpfung kann nur ein Administrator aufheben (*Verknüpfung mit dem Microsoft-Konto
aufheben* im Profil); eine Person kann ihr Konto nicht selbst auf ein anderes Microsoft-Konto umhängen.
---
## Sicherheitskonzept
@ -403,7 +419,7 @@ wp m365-login sync # echter Lauf
| Secret-Diebstahl aus der Datenbank | AES-256-GCM, Schlüssel per HKDF aus `AUTH_KEY`/`SECURE_AUTH_KEY`; ohne `wp-config.php` ist der Datensatz wertlos. Gilt für Client Secret und privaten Zertifikatsschlüssel. |
| Secret-Abfluss im Transport | Zertifikatsmodus: es wird nie ein Geheimnis übertragen, nur eine 5 Minuten gültige, signierte Client Assertion (RFC 7523). |
| Kontoübernahme im Multi-Tenant-Modus | `email`-Claim fremder Tenants wird ignoriert (nur UPN mit verifizierter Domain oder `xms_edov`). |
| Flooding der State-Tabelle | Max. 30 Login-Starts pro IP und 10 Minuten; Proxy-Header per `M365_LOGIN_CLIENT_IP_HEADER`. |
| Flooding der State-Tabelle | Max. 300 Login-Starts pro IP und 10 Minuten; Proxy-Header per `M365_LOGIN_CLIENT_IP_HEADER` am besten ein einwertiger Header wie `HTTP_CF_CONNECTING_IP` oder `HTTP_X_REAL_IP` (bei `X-Forwarded-For` zählt der rechte, vom Proxy geschriebene Eintrag). |
| Offene Redirects | `redirect_to` läuft durch `wp_validate_redirect`, alle Redirects über `wp_safe_redirect`. |
| Fehler-Reflektion | Fehlermeldungen sind Codes → feste, übersetzte Texte; Details nur ins Log (`WP_DEBUG_LOG`). |
| Rate Limiting Fallback-Key | 10 Fehlversuche pro IP / 15 Min. |