danielmarschall / oidplus

OIDplus 2.0 - An OpenSource online Registration Authority for OIDs and other Object Types
https://www.oidplus.com
Apache License 2.0
10 stars 6 forks source link

OAuth plugins not working with multiple domains (canonical / reverse proxy) #19

Closed wehowski closed 11 months ago

wehowski commented 11 months ago

Hello Daniel, the OAuth Login does not work anymore? https://registry.frdl.de/?goto=oidplus%3Alogin_webfan

I will investigate this at the weekend...

wehowski commented 11 months ago

...I try to do the same login as in the google OAuth Plugin, but without success...

//  $email is correct so far...!
   OIDplus::authUtils()->raLoginEx($email, 'Webfan');

        OIDplus::db()->query("UPDATE ###ra set last_login = ".OIDplus::db()->sqlDate()." where email = ?", array($email));
      OIDplus::logger()->log("V2:[OK]RA(%1)", "RA '%1' logged in via Webfan OAuth2", $email);
        OIDplus::invoke_shutdown();

        // Go back to OIDplus

        header('Location:'.OIDplus::webpath(null,OIDplus::PATH_ABSOLUTE_CANONICAL));
danielmarschall commented 11 months ago

Ich kümmere mich gleich darum. Muss jetzt den neuen BigMac probieren :)

wehowski commented 11 months ago

Keine Hektik, ich kann mich später auch nochmal dran setzen. Erstmal guten Appetit 😃

danielmarschall commented 11 months ago

Es funktioniert bei mir einwandfrei. Bitte lösche einmal deine Cookies. Das Problem könnte sein, dass durch das Setzen von "cookieDomain" alle Subdomains erlaubt werden (.registry.frdl.de, man beachte den Punkt davor). Wenn du aber noch ein altes Cookie hast, das KEIN Punkt davor hat, dann wird das bevorzugt, und es bleibt für ewig drin.

wehowski commented 11 months ago

Hallo Daniel, mh. ich dachte ich hätte die Cookies gelöscht. Aber Du hast mich auf den Fehler gebracht:

    //  header('Location:'.OIDplus::webpath(null,OIDplus::PATH_ABSOLUTE_CANONICAL));
        header('Location:'.OIDplus::webpath(null,OIDplus::PATH_ABSOLUTE));

Der Caonical Path ist NICHT der OAuth Path.

Geht nun, danke!!!

Viele Grüße Till

danielmarschall commented 11 months ago

Solltest du nicht lieber die Google-OAuth Einstellungen ändern, anstelle den OIDplus Quelltext? Weil beim nächsten Update wird ja dann die Änderung ggf. wieder überschrieben.

Eigentlich ist es ja so beabsichtigt, dass der Canonical Path in allen Fällen bevorzugt wird. Wenn ich beispielsweise auf https://webfan.de/apps/registry/ gehe, dann sollten alle Vorkommnisse von registry.frdl.de entfernt sein. Den Benutzer geht es ja nix an, wie die Adresse hinter dem Proxy heißt?!

wehowski commented 11 months ago

...ich suche grad die Google OAuth Einstellungen, aber die developer console ist so unübersichtlich....

danielmarschall commented 11 months ago

Bitte lasse mich wissen, ob ich etwas am Code ändern sollte. Vielleicht auch den OAuth Pfad per Baseconfig einstellbar machen?

Kann man beim Webfan OAuth und Google OAuth auch mehrere Pfade einstellbar machen? Denn ggf. wollen Besucher ja sowohl von registry.frdl.de als auch von webfan.de/apps sich einloggen können

wehowski commented 11 months ago

Hallo Daniel, habs gefunden. Wenn ich die recirect_url direkt angebe gehts: 'redirect_uri'=>'https://registry.frdl.de/plugins/viathinksoft/publicPages/810_login_google/oauth.php',

wehowski commented 11 months ago

Bitte lasse mich wissen, ob ich etwas am Code ändern sollte. Vielleicht könnte die Callbackurl konfigurierbar sein?

wehowski commented 11 months ago

Kann man beim Webfan OAuth und Google OAuth auch mehrere Pfade einstellbar machen? Bei Google ja, bei Webfan jein: Bei API OAuth (api.webfan.de) schon, bei Webfan meine ich nur mit eigenen credentials per url aber das müsste ich mal nachschauen und testen....

danielmarschall commented 11 months ago

Wenn ich das so sehe, dann glaube ich, dass die redirect_uri niemals Canonical sein darf. Wer sich auf Domain1 einloggt (und dort ein Cookie erzeugt), der MUSS zu Domain1 umgeleitet werden. Wer sich auf Domain2 einloggt (und dort ein Cookie erzeugt), der MUSS zu Domain2 umgeleitet werden.

Ebenso das header('Location:...')

wehowski commented 11 months ago

Du wirst ja vom OAuth auf einer Domain (der Callback-Url) eingeloggt, hier muss auch hin redirected werden, dort ist man ja dann eingeloggt.

danielmarschall commented 11 months ago

Hm... jetzt wird's kompliziert... Das Problem beim Proxy ist ja, dass das System hinter dem Proxy nicht weiß, wie die tatsächliche URL vor dem Proxy ist. PATH_ABSOLUTE wird somit immer registry.frdl.de sein. Frdl.de ist hinter dem Proxy und weiß somit überhaupt nicht, dass der Besucher von webfan.de kommt (und dafür dort ein Cookie bekommen hat). Was ist dann die Lösung?

wehowski commented 11 months ago

Was ist dann die Lösung? Ich würde vorschlagen redirect_url konfigurierbar zu machen, und das finale redirect von der callback-url abzuleiten (oder relativen Pfad angeben). Im Moment funktionieren beide OAuths, Google und Webfan (schau mal).

Ich glaube das es mit dem Proxy auch funktionieren würde mit entsprechend konfigurierten call-back-urls? Bin erstmal froh das es läuft, ich kann das mit dem Proxy mal bei Gelegenheit mit einem Extra-Client ausprobieren!

danielmarschall commented 11 months ago

Ich versteh es nicht. Angenommen man könnte callback-url einstellbar machen, z.B. "xyz.frdl.de" . Wenn ich dann aber "webfan.de" aufrufe, dann funktioniert es nicht, weil ich dann nach xyz.frdl.de umgeleitet werde, aber das Login-Cookie wurde auf webfan.de gelegt. Also kann es doch nur entweder hier oder dort funktionieren?

wehowski commented 11 months ago

Ich denke es funktionier hier UND dort, aber nicht gleichzeitig. Man muss sich einfach entscheiden welche Domain man bevorzugt und das bei den Einstellungen berücksichtigen. Soweit meine These.

Ich probier das gleich mal aus und berichte Dir...

wehowski commented 11 months ago

Du hast recht, über den Proxy funktioniert es leider nicht! Persönlich kann ich damit leben, das OAuth geht ja. Eine spontane Idee für eine Lösung hab ich leider noch nicht...

danielmarschall commented 11 months ago

Ich habe zwei Ideen:

wehowski commented 11 months ago

Idee 2: Die canonical URL ist ja der Proxy über den funktionierts bei mir nicht. Idee 1: Ja, wenn die aus der redirect-einstellung kommt müsste es gehen, aber: Es müsste doch reichen einfach die Callback-Url konfigurierbar zu machen so wie es jetzt bei mir editiert ist, sofern der Proxy nicht für OAuth verwendet wird? Das ändern der Url bringt ja nichts wenn es ein anderes Problem mit dem Proxy gibt, vl. muss ich das nochmal genauer untersuchen... ...

danielmarschall commented 11 months ago

Es ist ja gut, dass es für dich funktioniert, aber ich möchte gerne dass man OAuth über beide URLs verwenden kann. Deswegen bringt das Einstellen von callback/redirect-uri nix, denn dann geht entweder A oder B, aber nicht beides. Es bringt eine Menge Frust sowohl bei den Anwendern als auch bei den Administratoren, wenn OAuth über Domain A funktioniert und über Domain B nicht. Das Mindeste wäre, dass eine verständliche Fehlermeldung kommen muss, in der der Benutzer darum gebeten wird, die andere Domain zu verwenden.

Die Idee 2 wäre ja, dass alles auf Canonical umgeleitet wird, und du dann in webfan und Google dementsprecht die Canonical URL als gültige URL eingibst.

Idee 1 würde die Callback URL per JavaScript ermitteln. Das wär ja auch gut, denn es ist ja bei Google möglich, mehrere URLs als gültige Callback URLs zu erlauben?

wehowski commented 11 months ago

Ich habe das grad schon mit Webfan und einem anderen Client mit Canonical-Callback-Url getestet (siehe oben), aber es hat leider nicht funktioniert: "Invalid access token". Ich kann gerne nochmal alle Einstellungen überprüfen und nochmal testen? Der Client ist noch eingestellt und in der base config auskommentiert.

wehowski commented 11 months ago

Hab grad in google auch nochmal die canonical hinzugefügt: https://webfan.de/apps/registry/plugins/frdl/publicPages/801_login_webfan/oauth.php

danielmarschall commented 11 months ago

Hm... habe grad lange drüber nachgedacht und ich verstehe irgendwie grad nicht, warum es überhaupt ein Problem gibt...

Verstehe ich den Flow korrekt?

  1. OIDplusPagePublicLoginGoogle.class.php ruft Google.com auf und übergibt redirect_uri = Canonical/oauth.php

  2. Google macht den Login-Kram und leitet den Besucher danach zu Canonical/oauth.php um.

  3. In Canonical/oauth.php wird ein Cookie gesetzt und der Benutzer wird zu Canonical/index.php umgeleitet.

In Schritt 3 wird das Cookie also in Canonical angelegt UND der Benutzer wird zu Canonical umgeleitet. Also muss es doch funktionieren?! Alles was du machen müsstest, ist bei Google zu sagen dass deine Canonical URL die richtige ist?!

wehowski commented 11 months ago

Hab die canonical Url geändert und entsprechend eingestellt, geht aber nicht: "Die Anfrage des Client ist ungültig" Ich habe aber im Moment auch keine passende Erklärung, außer das es vl. an meinem Proxy liegen könnte und ich da was konfigurieren muss!?!

danielmarschall commented 11 months ago

Wäre es für dich viel Aufwand, mir einen kleinen Proxy anzulegen, der auf oidplus.viathinksoft.com/oidplus_dev umleitet? Dann würde ich gerne selbst mal experimentieren

wehowski commented 11 months ago

Hier ist der Proxy: https://webfan.de/apps/dev-registry/ Danke für Deine ganze Mühe!!!

wehowski commented 11 months ago

Hier kannst Du auch OAuth Client zum testen anlegen: https://api.webfan.de/apps/developer/ (z.B. mit dem WEID-Account) Oder ich erstelle Dir einen in Webfan, wir müssen dann nur url und credentials austauschen?

wehowski commented 11 months ago

Hallo Daniel, je nachdem wo das Login iniziiert wird, wird ja ein "state" in die Session geschrieben? Möglicherweise könnte es mit dem javascript klappen, ABER: Habe es grad nochmal versucht und das Login von der entsprechenden caonical initiiert, aber auch das hat nicht geklappt. Seltsam.

danielmarschall commented 11 months ago

Erster Test: OHNE Verwendung von CANONICAL_SYSTEM_URL : webfan.de leitet zu Google weiter, und Google leitet zu viathinksoft.de weiter. Es gibt jetzt einen Fehler wegen fehlendem oder falschem CSRF Cookie auf viathinksoft.de ("state" Parameter durch Google durchgereicht). Aber wenn ich diese CSRF Prüfung auskommentiere, dann funktioniert der Google OAuth einwandfrei.

Zweiter Test: Setzen von CANONICAL_SYSTEM_URL auf webfan.de : Dann meldet Google "redirect_uri_mismatch", obwohl ich in https://console.cloud.google.com/apis/credentials/consent die Domain webfan.de als vertrauenswürdig eingestellt habe.

danielmarschall commented 11 months ago

Moment, man muss die Weiterleitungs-Domains hier ändern: https://console.cloud.google.com/apis/credentials

wehowski commented 11 months ago

https://console.cloud.google.com/apis/credentials/oauthclient/123...x ... ist es bei mir? Ich finde das etwas unübersichtlich und schwer zu finden teilweise bei google....

danielmarschall commented 11 months ago

Bis auf das CSRF-Thema funktioniert es bei mir einwandfrei.

image

dann hier:

image

dort dann eintragen: https://..../plugins/viathinksoft/publicPages/810_login_google/oauth.php

wehowski commented 11 months ago

Ich glaube Deine Idee, erst auf die richtige Domain zu leiten (z.B. mit Javascript) und dann das OAuth Login zu starten ist die richtige?

Edit: Der State Parameter ist vorgesehen in der OAuth spec., auch wenn er optional ist(?) sollte man ihn denke ich verwenden!?

danielmarschall commented 11 months ago

Ich bin mir nicht 100% sicher, wie ich das mache, weil ich mir über den Login-Flow nicht sicher bin.

In oauth.php steht:

$cont = url_post_contents(
    "https://oauth2.googleapis.com/token",
    array(
        "grant_type"    => "authorization_code",
        "code"          => $_GET['code'],
        "redirect_uri"  => OIDplus::webpath(__DIR__,OIDplus::PATH_ABSOLUTE_CANONICAL).'oauth.php', // TODO: dynamic??
        "client_id"     => OIDplus::baseConfig()->getValue('GOOGLE_OAUTH2_CLIENT_ID'),
        "client_secret" => OIDplus::baseConfig()->getValue('GOOGLE_OAUTH2_CLIENT_SECRET')
    )
);

Aber zu dem Zeitpunkt weiß das PHP-Script ja noch nicht, was JavaScript da gesagt hat? Außer ich würde diese JavaScript-Information in den State-Parameter mit übergeben...

Der State Parameter ist wichtig, um CSRF zu verhindern.

wehowski commented 11 months ago

Hallo Daniel, Du hattest doch schon an anderer Stelle die "trusted proxies" detectiert. Würde es helfen für jeden erkannten, vertrauten Proxy eine entsprechende callback-url zu konfigurieren in der base config?

danielmarschall commented 11 months ago

Ich denke, dass ich die Lösung skizziert habe...

Google überprüft, ob die redirect_uri autorisiert ist, daher kein Sicherheitsrisiko.

~Allerdings werde ich den state am besten noch mit dem Server-Secret verschlüsseln, oder mit einem HMAC sichern, damit da niemand was rumfummelt!~ Quatsch, geht nicht, denn JavaScript weiß das Serversecret nicht

wehowski commented 11 months ago

Google überprüft, ob die redirect_uri autorisiert ist, daher kein Sicherheitsrisiko. Das gilt nicht für alle Clients, aber die übergebene uri könnte man auch noch grob oder anhand der config überprüfen. Der State muss m.E. nicht verschlüsselt werden, der steht ja so wie ich es verstanden habe in der session und schützt vor unauthorisierten callbacks und kann relativ frei vergeben werden? Wenn einer "rummfummelt" müsste er eh erst eine Session erzeugen? Oder vertue ich mich hier?

EDIT: Der State müsste ggf. statt nur in der (JWT-)Session noch zur Synchronisation irgendwo temporär gespeichert werden?

danielmarschall commented 11 months ago

Es gibt keine PHP Sessions mehr, nur noch JWT. Und JavaScript soll ja die URL ermitteln und dann an Google geben. Und JavaScript ist durch den potentiellen Angreifer steuerbar. Ich erstelle jetzt erstmal einen Prototypen

danielmarschall commented 11 months ago

SVN Revision 1372 should fix the issue, by obtaining the redirect_uri via JavaScript. (Update will be at OIDplus in approx 10 minutes, and in Github in approx 1 hour) Please make sure to delete all cookies and force-reload the page.

@wehowski Bitte sag mir ob nun alles funktioniert und bitte passe dein Webfan OAuth plugin dementsprechend an. Die Änderungen sind nicht komplex, dürfte ganz einfach sein.

wehowski commented 11 months ago

Hallo Daniel, Webfan geht nicht mit beiden Urls aber das klammer ich erstmal aus, muss ich anpassen. Google geht mit registry.frdl aber mit webfan: Fehler 400: redirect_uri_mismatch Sorry, die uri war nicht ganz korrekt, Mist wie peinlich. Nun geht Google mit beiden urls.