ich richte DiscourseConnect zwischen einer WordPress-Website und einer gehosteten Discourse-Instanz ein und stoße auf einen anhaltenden Fehler bei der HMAC-Signaturvalidierung.
Konfiguration
WordPress ist die Authentifizierungs-/Provider-Seite.
WordPress empfängt die DiscourseConnect-Anfrage und gibt den Callback zurück, der sso und sig enthält.
Der Callback erreicht Discourse, wird aber abgelehnt, da die HMAC-Signatur nicht validiert werden kann.
Wir haben umfangreich debuggt und das Problem erheblich eingegrenzt.
Was wir bestätigt haben
wp_unslash() verändert die Callback-Werte nicht.
Die Validierungseingaben von EA/WordPress stimmen mit den Parametern überein, die aus der von WordPress beobachteten Query String rekonstruiert wurden.
Der erwartete Callback-Code wird definitiv ausgeführt.
Die deployed Source-Dateien stimmen mit unserem Build-Manifest überein.
Wir haben auf falsche Dateien und doppelte Definitionen geprüft.
PHP-FPM wurde nach den letzten Korrekturen neu gestartet, es handelt sich also nicht um einen veralteten PHP-Prozess oder einen opcache-Zustand.
Eine völlig neue DiscourseConnect-Anfrage nach diesen Änderungen scheitert weiterhin an der HMAC-Validierung.
Mit anderen Worten: Der aktuelle Fehler ist bei einer neuen Anfrage reproduzierbar.
Was wir noch nicht beweisen konnten
Dass das effektive Secret, das Discourse zur Laufzeit verwendet, bytegenau identisch mit dem von WordPress verwendeten Secret ist.
Dass der sso-Payload nicht irgendwo verändert wird, bevor WordPress die Anfrage beobachtet.
An dieser Stelle wollen wir nicht blindlings weiter an Einstellungen oder Code herumfummeln.
Frage
Wie ist für das aktuelle Discourse/DiscourseConnect der beste Weg, exakt festzustellen, welchen Payload und welches Secret Discourse verwendet, wenn es die erwartete HMAC berechnet?
Gibt es eine empfohlene Debugging-/Logging-Methode, mit der wir den HMAC-Eingabewert auf der Discourse-Seite mit dem auf der WordPress-Seite vergleichen können, ohne das eigentliche Secret öffentlich preiszugeben?
Falls es bekannte Probleme gibt, die mit der Verarbeitung durch WordPress/PHP, URL-Encoding, Base64-Payloads, Reverse Proxies oder gehostetem Discourse zusammenhängen und diese Situation verursachen könnten, wäre ich auch für Hinweise dankbar.
Ich kann bereinigte Anfrage-/Callback-Werte, relevanten WordPress-Code und Logs bereitstellen, falls benötigt.
Hallo Richard. WP-Discourse ist installiert, aber der DiscourseConnect-Anbieter und die Login-Sync-Funktionen sind deaktiviert.
Wir verwenden ein kleines, selbstgeschriebenes WordPress-Plugin als DiscourseConnect-Anbieter. Es empfängt die Parameter sso und sig von Discourse, prüft den eingehenden HMAC mit dem gemeinsamen Geheimnis und erstellt danach die signierte Antwort an Discourse.
Der Fehler tritt derzeit bei der eingehenden Anfrage von Discourse an WordPress auf – unsere neue Diagnose zeigt, dass die Neuberechnung des HMAC nicht mit der von Discourse empfangenen sig übereinstimmt.
Ich kann gerne den relevanten PHP-Callback-/Validierungscode posten. Ich entferne vorher die Konfigurationswerte/Geheimnisse.
Ja — du hast recht. Meine Formulierung im ursprünglichen Beitrag war vertauscht.
Der aktuelle Fehler tritt auf in der Richtung Discourse → WordPress.
Discourse erzeugt die DiscourseConnect-Anfrage, die sso und sig enthält. WordPress empfängt sie, und unser benutzerdefinierter EA-Provider versucht, die Signatur zu verifizieren. Diese eingehende HMAC-Verifikation schlägt fehl, daher bricht WordPress dort ab. Es kommt nicht so weit, dass es den authentifizierten Nutzern-Payload an Discourse zurückgibt.
WP-Discourse ist installiert, aber sein DiscourseConnect-Provider und die Funktionen zur Synchronisierung der Nutzereinloggung sind deaktiviert. Wir verwenden derzeit den benutzerdefinierten EA-Provider, weil wir die EA-Konto-/Profil-Ebene unter unserer Kontrolle halten möchten.
Ich werde unten den relevanten Callback-/Konfigurations-/HMAC-Validierungscode posten, wobei alle Geheimnisse und privaten Konfigurationen entfernt wurden.
Danke, Richard. Ich habe diesen Punkt mit der Request-Verarbeitung in PHP/WordPress und dem aktuellen Discourse-Signierungsprozess abgeglichen.
In unserem Callback lesen wir aus $_GET, sodass PHP die Query-Parameter bereits URL-dekodiert hat, bevor EA sie erhält. wp_unslash() hebt lediglich das Request-Slashing von WordPress auf; es führt keine URL-Decodierung durch.
Wenn man an dieser Stelle erneut urldecode() anwendet, würde der Wert doppelt dekodiert, was ein Base64-+ in ein Leerzeichen umwandeln könnte und den HMAC selbst wieder brechen würde.
Ich habe außerdem bestätigt, dass unsere neue Diagnose den HMAC weiterhin fehlschlägt, nachdem die WordPress- und Discourse-Secrets korrigiert wurden, um übereinzustimmen.
Daher glaube ich nicht, dass das Ersetzen von wp_unslash() durch urldecode() die richtige Lösung für diesen bestimmten Callback-Pfad ist. Ich weiterverfolge, wo die signierte Nutzlast abweichen könnte, bevor sie PHP erreicht.
ich wollte noch kurz das Thema WordPress/Discourse SSO abschließen. Wir haben es zum Laufen gebracht.
Am Ende war die Lösung, zum Standard-WP-Discourse DiscourseConnect Provider zurückzukehren, anstatt bei unserer eigenen DiscourseConnect/HMAC-Implementierung zu bleiben.
Wir haben einen neuen Discourse-API-Schlüssel erstellt, das DiscourseConnect-Shared-Secret rotiert, den WP-Discourse Provider auf Netzwerk-Ebene aktiviert und die Discourse-Connect-URL von unserem alten eigenen Callback auf die von WP-Discourse festgelegte WordPress-Website-URL geändert.
Anschließend haben wir mit einem völlig neuen WordPress-Nutzer und einer sauberen Discourse-Sitzung getestet:
WordPress-Login → Community betreten → automatisch als derselbe Nutzer in Discourse angemeldet.
Der Standard-WP-Discourse verarbeitet das SSO nun also korrekt.
Danke nochmals, dass du uns während der Fehlersuche in die richtige Richtung gewiesen hast.