billy the gates: Abbrechen-Button im HTTP-Auth Dialog abfragen

Hi,

wie kann ich eigentlich in PHP abfragen, ob in einem HTTP-Auth Fenster der 'Abbrechen'-Button geklickt wurde?

Ich habe mir eine schöne HTTP-Auth Klasse in PHP geschrieben. Funktioniert auch soweit ganz gut, nur den einen Fall, daß einer auf Abbrechen klickt, kann ich nicht abfangen. Ich möchte dann auf eine Fehlerseite weiterleiten, statt ein gähnend leeres Fenster zu kriegen.

  1. den einen Fall, daß einer auf Abbrechen klickt, kann ich nicht abfangen. Ich möchte dann auf eine Fehlerseite weiterleiten, statt ein gähnend leeres Fenster zu kriegen.

    Beim Klick auf Abbrechen zeigt der Browser die 401-Meldung an, die Du ihm geschickt hast (aber wenn Du nichts schickst, kann er natürlich nichts anzeigen).

    1. Beim Klick auf Abbrechen zeigt der Browser die 401-Meldung an, die Du ihm geschickt hast (aber wenn Du nichts schickst, kann er natürlich nichts anzeigen).

      also, ich muß bestimmen, was im Fall einer 401-Meldung angezeigt werden soll? Das ist doch bestimmt mode_rewrite oder sowas, ne? Oder geht das auch von PHP aus?

      1. Moin!

        also, ich muß bestimmen, was im Fall einer 401-Meldung angezeigt werden soll? Das ist doch bestimmt mode_rewrite oder sowas, ne? Oder geht das auch von PHP aus?

        Du weißt, wie eine 404-Statusseite individuell gestaltet wird?

        Genauso ist das auch bei einer 401-Statusseite - mit dem Unterschied: Bevor der Benutzer diese Seite sieht, fragt ihn der Browser nach Anmeldedaten - und wenn der User welche eingibt und OK klickt, dann wiederholt der Browser den Request (jetzt mit Anmeldedaten), ohne die 401-Seite anzuzeigen.

        Klickt der User aber Abbrechen, zeigt der Browser ihm die 401-Seite an.

        Schlägt die Authentifizierung der Anmeldedaten übrigens fehl, schickt der Webserver wieder eine 401-Statusseite, die der Browser genauso behandelt, wie die allererste Seite: Das Dialogfenster wird eingeblendet, und nach Eingabe von Daten und "OK" wird der Request wiederholt (jetzt mit den neuen Daten), ohne die Seite anzuzeigen. Das ginge im Prinzip endlos so weiter, bis irgendwann mal die Daten stimmen, oder der Benutzer mal "Abbrechen" klickt.

        - Sven Rautenberg

        --
        "Love your nation - respect the others."
        1. Hallo,

          Du weißt, wie eine 404-Statusseite individuell gestaltet wird?

          Nicht wirklich. Werd mich da wohl mal einlesen müssen. Aber bevor ich  mich verirre: muß ich das denn jetzt in so einer httpd.conf-Datei lösen (grad mal einen Artikel gefunden), oder kann ich den Fall 401 auch in PHP abfragen und dann mit einem location-Header auf meine Wunschseite weiterleiten?

          1. hi,

            Du weißt, wie eine 404-Statusseite individuell gestaltet wird?

            Nicht wirklich. Werd mich da wohl mal einlesen müssen. Aber bevor ich  mich verirre: muß ich das denn jetzt in so einer httpd.conf-Datei lösen

            Nein, per .htaccess-Konfigurationsdatei auf Verzeichnisebene ist das idR. auch möglich (sofern die Rechte vorliegen, Stichwort AllowOverride).

            oder kann ich den Fall 401 auch in PHP abfragen und dann mit einem location-Header auf meine Wunschseite weiterleiten?

            Warum willst du weiterleiten?
            Ist die Information, dass der Status 401 auftrat und für die Ressource Zugangsdaten verlangt werden, etwa nicht von Interesse?
            Dann spare dir HTTP Auth, und ersetze gleich durch 403 Forbidden.

            gruß,
            wahsaga

            --
            /voodoo.css:
            #GeorgeWBush { position:absolute; bottom:-6ft; }
            1. Danke,

              Warum willst du weiterleiten?
              Ist die Information, dass der Status 401 auftrat und für die Ressource Zugangsdaten verlangt werden, etwa nicht von Interesse?

              Ich will halt im Projekt bleiben: eine schöne Seite - passend im Outfit und da vielleicht einen Link zur Hauptseite oder so und natürlich die Information, daß der Zugriff verweigert wurde.

              1. hi,

                Ich will halt im Projekt bleiben: eine schöne Seite - passend im Outfit und da vielleicht einen Link zur Hauptseite oder so und natürlich die Information, daß der Zugriff verweigert wurde.

                Dann definiere ein ErrorDocument 401.

                Eigenes "Weiterleiten" o.ä. ist nicht erforderlich, eher sogar kontraproduktiv.

                gruß,
                wahsaga

                --
                /voodoo.css:
                #GeorgeWBush { position:absolute; bottom:-6ft; }
      2. Also, ich glaube, da ist ein Mißverständnis. Ich schicke dem Brwoser nichts. Ich kann ihm aus PHP heraus ja eine 401-Meldung schicken. Aber ich kann den Fall einfach nicht abfragen, ob der Abbrechen-Button geklickt wurde.

        Im PHP-Handbuch steht dieses Beispiel:

        <?php
          if(!isset($PHP_AUTH_USER)) {
            Header("WWW-Authenticate: Basic realm="My Realm"");
            Header("HTTP/1.0 401 Unauthorized");
            echo "Text to send if user hits Cancel button\n";
            exit;
          } else {
            echo "Hello $PHP_AUTH_USER.<P>";
            echo "You entered $PHP_AUTH_PW as your password.<P>";
          }
        ?>

        aber den if-Zweig erreiche ich da auch, wenn kein User übergeben wurde. Diese Fälle habe ich alle, auc falsches PW und so... nur den Abbrechen-Button nicht.

        1. Also, ich glaube, da ist ein Mißverständnis. Ich schicke dem Brwoser nichts.

          Wie ich schon schrieb: Wenn Du dem Browser nichts schickst, kann er auch nichts anzeigen, wenn "Abbrechen" gedrückt wird.

          if(!isset($PHP_AUTH_USER)) {
              Header("WWW-Authenticate: Basic realm="My Realm"");
              Header("HTTP/1.0 401 Unauthorized");

          aber den if-Zweig erreiche ich da auch, wenn kein User übergeben wurde. [..] nur den Abbrechen-Button nicht.

          Und warum ist es für Dich so unangenehm, den Fall "Benutzer hat keine Zugangsdaten" und den Fall "Benutzer hat keine Zugangsdaten und bricht den Vorgang ab" als ein- und denselben zu behandeln?
          Das Protokoll sieht jedenfalls keine Unterscheidung vor, es gibt nur die Nachricht, dass Zugangsdaten benötigt werden.

          1. Hi, es gibt noch was Neues (*)

            Und warum ist es für Dich so unangenehm, den Fall "Benutzer hat keine Zugangsdaten" und den Fall "Benutzer hat keine Zugangsdaten und bricht den Vorgang ab" als ein- und denselben zu behandeln?

            Also, weil ich, wenn die Zugangsdaten falsch waren, das Eingabefenster wieder zeigen lasse. Das klappt ja auch gut. Es geht ja nicht nur um Einbrecher, sondern um Versehentliche Falscheingaben.

            Bei "Abbrechen" hingegen gehe ich eher davon aus, daß der User es sich anders überlegt hat. Man kann das Projekt nämlich auch unangemeldet nutzen - ähnlich wie hier.

            Das Protokoll sieht jedenfalls keine Unterscheidung vor, es gibt nur die Nachricht, dass Zugangsdaten benötigt werden.

            Also in jedem Fehlerfall auf eine Errorseite verweisen? Hmm..., jedenfalls ist mir das bisher nicht gelungen - wie wahsaga empfohlen hat. Irgendwie kann ich den Apache-Kram nicht.

            *) So, jetzt die Spezialneuheit: ich konnte den Fall doch abfragen - mache das mit der IP, die bei Erstanforderung des Loginfensters zwischengespeichert wurde. Egal, jedenfalls komme ich bei Abbrechen in den richtigen Zweig und es wird anscheinend auch auf die richtige Seite weitergeleitet, aaaaaber: sie ist im Browser nicht sichtbar. Im Quelltext steht allerdings der ganze Quelltext der Seite. Was'n das???

            1. Und warum ist es für Dich so unangenehm, den Fall "Benutzer hat keine Zugangsdaten" und den Fall "Benutzer hat keine Zugangsdaten und bricht den Vorgang ab" als ein- und denselben zu behandeln?

              Also, weil ich, wenn die Zugangsdaten falsch waren, das Eingabefenster wieder zeigen lasse.

              Bei "Abbrechen" hingegen gehe ich eher davon aus, daß der User es sich anders überlegt hat. Man kann das Projekt nämlich auch unangemeldet nutzen - ähnlich wie hier.

              Gut, aber wenn sowohl Name als auch Passwort gänzlich leer waren, ist es doch naheliegender, dass es sich nicht um eine fehlerhafte Eingabe handelt (darunter verstehe ich Tippfehler), sondern um jemanden, der keine Zugangsdaten hat und somit unangemeldet bleiben möchte. Das wäre sozusagen eine Anmeldung als niemand.
              Diese Behandlung hätte sogar den kleinen Vorteil, dass man die Anmeldung mit der Return-Taste einfach wegdrücken könnte ohne erst auf "Abbrechen" zielen zu müssen.

              Aber, zugegebenermaßen, das ist Geschmackssache.

              Das Protokoll sieht jedenfalls keine Unterscheidung vor, es gibt nur die Nachricht, dass Zugangsdaten benötigt werden.

              Also in jedem Fehlerfall auf eine Errorseite verweisen?

              Verweisen schon gar nicht, direkt ausgeben. Eine Fehlermeldung gibst Du bereits mit der Authentifizierungsaufforderung aus (die die Browser allerdings erst bei "Abbrechen" anzeigen), die zweite wäre statt des 401 ein die Prozedur abwürgender 403 ("Forbidden", zum Beispiel nach drei erfolglosen Anmeldeversuchen).

              ist im Browser nicht sichtbar. Im Quelltext steht allerdings der ganze Quelltext der Seite. Was'n das???7

              Falscher MIME-Typ, Fehler im Quelltext?

              1. Bei "Abbrechen" hingegen gehe ich eher davon aus, daß der User es sich anders überlegt hat. Man kann das Projekt nämlich auch unangemeldet nutzen - ähnlich wie hier.

                Gut, aber wenn sowohl Name als auch Passwort gänzlich leer waren, ist es doch naheliegender, dass es sich nicht um eine fehlerhafte Eingabe handelt (darunter verstehe ich Tippfehler), sondern um jemanden, der keine Zugangsdaten hat und somit unangemeldet bleiben möchte. Das wäre sozusagen eine Anmeldung als niemand.

                Aaaaach, jetzt verstehe ich Dich. Du meintest ausdrücklich KEINE Zugangsdaten, nicht fehlerhafte Eingaben. Also den Fall frage ich ab. Aber der ist nochmal unterteilt in "Neuaufruf" und "Abbruch". Denn, beim ersten Aufruf der Loginklasse sind ja auch noch keine Zugangsdaten vorhanden und dann muß ich ja den Authentifizierungsheader abschicken, für das Eingabefenster. Wenn Du einen Tip hast, wie ich anders feststellen kann als durch "keine Zugangsdaten", daß das Loginfenster gerade erst angefordert wurde... her damit! Wenn ich jetzt bei "keine Zugangsdaten" die Fehlerseite schicke - was merkwürdigerweise funktioniert - bekommt der User die gleich zu Anfang. So ist das nicht gedacht ;-)

                ist im Browser nicht sichtbar. Im Quelltext steht allerdings der ganze Quelltext der Seite. Was'n das???7
                Falscher MIME-Typ, Fehler im Quelltext?

                Hmm..., also direkt aufrufen kann man die Seite und sie wird auch angezeigt, sie scheint an sich also in Ordnung zu sein. Wenn ich bei dem weißen Fenster (also im "Abbrechen"-Fall) die Adressleiste markiere und Return drücke, wird auf die richtige Fehlerseite weitergeleitet. Das muß irgendwas mit den Headern und der Weiterleitung zu tun haben.

                1. Also bevor wir (weiter) aneinander vorbeireden:

                  Der Ablauf ist folgendermaßen:

                  1. Browser, Anfrage: http://x
                  2. Server, Antwort: 401 und "<html>..Authentifizierung nötig..bla..bla..</html>"
                  3. Browser, Aktion: Login-Dialog anzeigen

                  4a) Benutzer drückt Ok
                      5)Browser, Anfrage: http://x mit Zugangsdaten
                      6)Server, Antwort: "Zugangsdaten falsch" (mit 401 oder 403), oder http://x (mit 200) ausgeben

                  4b) Benutzer drückt Abbrechen
                      5) Browser zeigt Seite an, die Server in Schritt 2) geschickt hat.

                  Daraus ergeben sich viereinhalb Fälle, die Du im Authentifzierungsabschnitt bearbeiten musst:

                  1. Neuanforderung
                  Erkennung: auth-Variablen existieren nicht, IP unbekannt (oder kein Cookie gesetzt).
                  Aktion: 401 (Authentifizierung nötig) und Seite schicken (Inhalt siehe unten).
                  Browser: Zeigt Login-Dialog, mitgeschickte Seite wird (üblicherweise) nicht angezeigt.

                  2. Abbrechen gedrückt
                  Erkennung: Nicht möglich, da der Browser keine weitere Anfrage an den Server schickt.
                  Aktion: Nicht möglich, da keine Erkennung.
                  Browser: Zeigt die Seite an, die beim letzten 401 geschickt wurde.

                  Dies ist der "halbe" Fall, weil der Server nichts davon mitbekommt.

                  3. Ok ohne Zugangsdaten gedrückt
                  Erkennung: auth-Variablen existieren nicht oder sind leer, und die IP ist von vorangehendem 401 bekannt (oder ein Cookie ist gesetzt).
                  Aktion: 403 (Zugang verweigert), 401 (Authentifizierung nötig) oder 200 (Ok), jeweils mit entsprechender Seite.
                  Browser: 403: zeigt Seite an, 401: zeigt Login-Dialog an, 200: zeigt Seite an.

                  4. Ok mit falschen Zugangsdaten gedrückt
                  Erkennung: auth-Daten falsch.
                  Aktion: 403 (Zugang verweigert) oder 401 (Authentifizierung nötig), jeweils mit entsprechender Seite.
                  Browser: 403: zeigt Seite an, 401: zeigt Login-Dialog an.

                  5. Ok mit richtigen Zugangsdaten gedrückt
                  Erkennung: auth-Daten richtig.
                  Aktion: 200 (Ok) und gewünschte Seite schicken.
                  Browser: Zeigt Seite an.

                  Wichtig ist Punkt 2, nämlich dass Du keine Möglichkeit hast, direkt auf den Abbruch zu reagieren. Du kannst lediglich vorausschauend mit den 401-Fehlern bei 1, 3 und 4 einen sowohl dem Abbruch als auch der Authentifizierungsaufforderung angemessenen Text liefern. Das könnte in Deinem Fall auch die gewünschte Seite sein, so, wie man sie ohne Authentifizierung benutzen kann, mit dem Hinweis "Sie arbeiten unangemeldet" statt "Angemeldet als Otto Normaluser".

                  Wenn ich bei dem weißen Fenster (also im "Abbrechen"-Fall) die Adressleiste markiere und Return drücke, wird auf die richtige Fehlerseite weitergeleitet. Das muß irgendwas mit den Headern und der Weiterleitung zu tun haben.

                  Bitte _keine_ Weiterleitungen, dafür besteht keine Veranlassung.

                  1. Dankeschön. Ich muss das erstmal in Ruhe lesen und melde mich dann wieder... :-)

                  2. Also bevor wir (weiter) aneinander vorbeireden:

                    Ja, ich vermute, daß wir schon in Punkt 2 aneinander vorbeireden:

                    1. Server, Antwort: 401 und "<html>..Authentifizierung nötig..bla..bla..</html>"

                    ich bekomme keine Authentifizierungsaufforderung vom SERVER. Das macht mein Script. Ich habe gar keine geschützten Verzeichnissse. Man kann sich von jeder Seite aus über ein kleines Icon einloggen. Jeder Seitenaufruf ruft meine Loginklasse auf, und die prüft, ob der User schon eingelogt ist oder sich gerade einloggen will oder auslogt etc. Bevor es jetzt von allen Seiten Gezeter gibt: JA, man kann sich bei mir AUSloggen, ohne den Brwoser zu schließen und es funktioniert wunderbar :-)

                    Mein PHP-Script schickt also diesen Header:
                    Header("WWW-Authenticate: Basic realm="Anmeldebereich"");
                    ist das der falsche?

                    und im Folgenden wird weiter abgefragt, ob die Zugangsdaten stimmen etc. Das funktioniert ja auch alles perfekt. Nur bei Abbruch und beim ersten Loginaufruf bekomme ich KEINE Werte für User & Passwort, nichtmal einen Leerstring. Insofern unterscheiden sich diese beiden Fälle schon vom leer abgeschickten Fenster (Leerstrings)

                    1. Neuanforderung
                      Erkennung: auth-Variablen existieren nicht, IP unbekannt (oder kein Cookie gesetzt).

                    ja, funktioniert.

                    Aktion: 401 (Authentifizierung nötig) und Seite schicken (Inhalt siehe unten).

                    keine Ahnung, ob ich da den richtigen schicke...

                    Browser: Zeigt Login-Dialog, mitgeschickte Seite wird (üblicherweise) nicht angezeigt.

                    1. Abbrechen gedrückt
                      Erkennung: Nicht möglich, da der Browser keine weitere Anfrage an den Server schickt.
                      Aktion: Nicht möglich, da keine Erkennung.
                      Browser: Zeigt die Seite an, die beim letzten 401 geschickt wurde.

                    Und die wird bei mir nicht angezeigt, sondern erscheint nur im Quelltext. Ich dachte, daß da vielleicht an der Stelle der Server dazwischen kommt, weil er jetzt von von einem Authentifizierungsversuch mitbekommt. Also habe ich in der httpd.conf eine Zeile eingfügt, die im Fehlerfall auf meine Fehlerseite leiten soll:
                    ErrorDocument 401 /fehlerseite.html
                    Das hat aber nichts bewirkt.

                    Wichtig ist Punkt 2, nämlich dass Du keine Möglichkeit hast, direkt auf den Abbruch zu reagieren. Du kannst lediglich vorausschauend mit den 401-Fehlern bei 1, 3 und 4 einen sowohl dem Abbruch als auch der Authentifizierungsaufforderung angemessenen Text liefern. Das könnte in Deinem Fall auch die gewünschte Seite sein,...

                    Ja, in dem Zweig für das leer abgeschickte Fenster funktioniert das auch. Da kann ich auf meine Fehlerseite weiterleiten und sie ist SICHTBAR. In dem anderen Zweig (Abbruch) aber merkwürdigerweise nicht. Da kommt irgendwas dazwischen, wenn die Seite geschickt wird. Tests mit

                    die("irgendein Text");

                    beweisen, daß ich wirklich diesen Zweig erreiche. Aber auch dieser Ausgabetext erscheint NUR IM QUELLTEXT.

                    Bitte _keine_ Weiterleitungen, dafür besteht keine Veranlassung.

                    Aber wie soll ich denn auf die Fehlerseite kommen?

                      1. Server, Antwort: 401 und "<html>..Authentifizierung nötig..bla..bla..</html>"

                      ich bekomme keine Authentifizierungsaufforderung vom SERVER. Das macht mein Script.

                      Dein Skript _ist_ der Server. Welcher Mechanismus da nun genau verantwortlich ist, ist für die Betrachtung von außen, also vom Browser her, erstmal unwichtig.

                      Mein PHP-Script schickt also diesen Header:
                      Header("WWW-Authenticate: Basic realm="Anmeldebereich"");
                      ist das der falsche?

                      Nein, der ist richtig, aber dazu gehört besagter 401-Fehler, also

                      header('HTTP/1.0 401 Unauthorized');
                      header('WWW-Authenticate: Basic realm="Anmeldebereich"');

                      1. Abbrechen gedrückt
                        Erkennung: Nicht möglich, da der Browser keine weitere Anfrage an den Server schickt.
                        Aktion: Nicht möglich, da keine Erkennung.
                        Browser: Zeigt die Seite an, die beim letzten 401 geschickt wurde.

                      Und die wird bei mir nicht angezeigt, sondern erscheint nur im Quelltext.

                      Vielleicht ist der fehlende 401 das Problem (so er denn fehlt, ist ein Schuss ins Blaue).

                      Falls Du mit Firefox probierst, solltest Du Dir aber in jedem Fall die LiveHTTPHeaders-Erweiterung  besorgen und nachschauen, was der Server ausspuckt; insbesondere die Status- (erste Zeile der Serverantwort, "HTTP/1.0 123 blafasel") sowie die Content-Type-Zeile sind interessant.

                      Also habe ich in der httpd.conf eine Zeile eingfügt, die im Fehlerfall auf meine Fehlerseite leiten soll:
                      ErrorDocument 401 /fehlerseite.html

                      Das bringt Dir nichts. ErrorDocument ist dafür gedacht, statt der in den Server fest eingebauten Fehlermeldungen eigene auszugeben. Bei PHP ist das aber irgendwo irrelevant, weil Du durch PHP schon die Möglichkeit bekommst, eine eigene Meldung auszugeben, nämlich direkt in dem Skript, das auch den Fehlercode ausgibt.

                      Wenn Du also folgendes hast,

                      if ([falsche oder keine Benuterdaten]) {
                          header('HTTP/1.0 401 Unauthorized');
                          header('WWW-Authenticate: Basic realm="Anmeldebereich"');
                          echo "<html><body>Kein Zugang mit diesen Daten</body></html>"; // Dies ist die Fehlerseite.
                          exit;
                      }
                      echo "blafasel"; // Hier ist die normale Seite.

                      dann müsste der Browser bei Abbruch den Text "Kein Zugang mit diesen Daten" anzeigen.

                      Bitte _keine_ Weiterleitungen, dafür besteht keine Veranlassung.

                      Aber wie soll ich denn auf die Fehlerseite kommen?

                      Direkt ausgeben, siehe oben.

                      Nur zur Begrifflichkeit: ErrorDocument ist (normalerweise) keine Weiterleitung, von einer "Weiterleitung an die Fehlerseite" zu sprechen kann daher etwas verwirrend sein.

                      Wie dem auch sei - falls es nicht an dem fehlenden 401 liegt, wäre es hilfreich, wenn Du Deinen Code mal bis auf das Wesentliche (lies: Zugangsdatenprüfung (mit festem Name/Passwort-Paar) und Verzweigung, das sollten nur ein oder zwei Dutzend Zeilen sein) zusammenkürzt, es mit diesem Rohbau probierst und, falls es mit dem nicht funktioniert, diesen Rohbau hier mal veröffentlichst.

            2. hi,

              ich konnte den Fall doch abfragen - mache das mit der IP, die bei Erstanforderung des Loginfensters zwischengespeichert wurde.

              Wenn du glaubst, diese müssen mit der des zweiten oder nachfolgender Requests identisch sein, irrst du.

              Egal, jedenfalls komme ich bei Abbrechen in den richtigen Zweig und es wird anscheinend auch auf die richtige Seite weitergeleitet, aaaaaber: sie ist im Browser nicht sichtbar. Im Quelltext steht allerdings der ganze Quelltext der Seite. Was'n das???

              Das's dein immer noch unsinniges Vorgehen.

              gruß,
              wahsaga

              --
              /voodoo.css:
              #GeorgeWBush { position:absolute; bottom:-6ft; }
        2. echo $begrüßung;

          Also, ich glaube, da ist ein Mißverständnis. Ich schicke dem Brwoser nichts. Ich kann ihm aus PHP heraus ja eine 401-Meldung schicken. Aber ich kann den Fall einfach nicht abfragen, ob der Abbrechen-Button geklickt wurde.
          Im PHP-Handbuch steht dieses Beispiel:
            if(!isset($PHP_AUTH_USER)) {
              Header("WWW-Authenticate: Basic realm="My Realm"");
              Header("HTTP/1.0 401 Unauthorized");
              echo "Text to send if user hits Cancel button\n";

          Und was ist das für eine Ausgabe hier?
          Richtiger hätte es übrigens heißen müssen: "Text to _display_ if user hits Cancel button." Denn gesendet wird er ja schon zusammen mit den Header-Zeilen.

          echo "$verabschiedung $name";