Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Anmelden an Webmodul über IdHTTP (https://www.delphipraxis.net/174183-anmelden-webmodul-ueber-idhttp.html)

fwn 8. Apr 2013 16:02

Anmelden an Webmodul über IdHTTP
 
Hallo zusammen,

ich versuche grade mich in die Entwicklung eines Webservers unter Delphi XE3 einzuarbeiten. Ich habe dazu ein Webmodul mit einigen WebActionItems erstellt, die ich auch über meinen Browser ohne Probleme ansprechen kann. Jetzt möchte ich gerne mithilfe der IdHTTP Unit eine Clientanwendung erstellen, die mit diesem Server kommuniziert. Leider komme ich bei der Übermittlung von Benutzername und Passwort nicht so recht voran.
Ich gehe dabei auf der Clientseite wie folgt vor:

Code:
HTTP := TIdHTTP.Create;
HTTP.Request.BasicAuthentication := True;
HTTP.HandleRedirects := True;
HTTP.Request.Username := Benutzername;
HTTP.Request.Password := Passwort;

Response := HTTP.Get(URL);
Ich kann auf diese weise zwar die Webactions ansprechen, aber ich konnte bis jetzt keine Möglichkeit finden den Benutzernamen und das Passwort im Webmodul wieder auszulesen. Es gibt in dem WebRequest Objekt keine ensprechenden Felder und sie scheinen auch in keinem der anderen Felder zu liegen. Ich habe auch schon versucht über die OnParseAuthentication der TIdHTTPWebBrokerBridge dranzukommen, auch ohne Erfolg. Kann mir da vieleicht jemand weiterhelfen?

Gruß,
Florian

nahpets 8. Apr 2013 17:02

AW: Anmelden an Webmodul über IdHTTP
 
Hallo,

bei Indy 10 gibt es unter Bubbles\Boxtests\ eine HTTPServer.pas. In der ist eine
Delphi-Quellcode:
procedure THTTPServer.HTTPServerCommandGet(AContext:TIdContext;
  RequestInfo: TIdHTTPRequestInfo; ResponseInfo: TIdHTTPResponseInfo);
und dort wir die Anmeldung per
Delphi-Quellcode:
  if FUseAuthenticaiton and
     ((RequestInfo.AuthUsername <> 'Indy') or (RequestInfo.AuthPassword <> 'rocks')) then
  begin
    AuthFailed;
    exit;
  end;
abgefragt. Hilft Dir das weiter?

fwn 9. Apr 2013 07:04

AW: Anmelden an Webmodul über IdHTTP
 
Hallo,

danke für die schnelle Antwort!
Ich habe jetzt schon recht viel mit dem TWebModule fertig programmiert und würde deshalb eine Lösung, die dieses benutzt bevorzugen. Ich werde den Indy Server aber auf jeden Fall im Hinerkopf behalten, falls es mit dem Module gar nicht klappt.

nahpets 9. Apr 2013 10:29

AW: Anmelden an Webmodul über IdHTTP
 
Hallo,
Zitat:

Zitat von fwn (Beitrag 1210729)
Hallo,

danke für die schnelle Antwort!
Ich habe jetzt schon recht viel mit dem TWebModule fertig programmiert und würde deshalb eine Lösung, die dieses benutzt bevorzugen. Ich werde den Indy Server aber auf jeden Fall im Hinerkopf behalten, falls es mit dem Module gar nicht klappt.

mir ging es eigentlich garnicht um die Nutzung des HTTPServers sondern nur darum, ob Du eventuell "irgendwo" die Attribute RequestInfo.AuthUsername oder RequestInfo.AuthPassword finden und nutzen kannst.

Habe mal ein Webmodul zusammengedaddelt, das alle Zeichenfolgen aus dem Request als HTML-Seite zurückgibt. Eventuell kannst Du ja damit was anfangen oder sehen ob und wo Benutzer und Passwort im Request enthalten sind. Bin mir allerdings nicht sicher, ob diese Informationen überhaupt vom Server an ein Webmodul weitergegeben werden.
Delphi-Quellcode:
procedure TWebModuleRequest.waiRequestAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  sl        : TStringList;
  slResponse : TStringList;
begin
  sl        := TStringList.Create;
  slResponse := TStringList.Create;
  try
    slResponse.Add('<html><head><title>Request-Inhalt</title></head><body>');
    slResponse.Add('<h1>Request-Inhalt</h1><hr />');
    slResponse.Add('<table border="1" cellspacing="3">');
    Request.ExtractContentFields(sl);
    slResponse.Add('<tr><td>ContentFields</td><td>');
    slResponse.AddStrings(sl);
    slResponse.Add('</td></tr>');
    Request.ExtractCookieFields(sl);
    slResponse.Add('<tr><td>CookieFields</td><td>');
    slResponse.AddStrings(sl);
    slResponse.Add('</td></tr>');
    Request.ExtractQueryFields(sl);
    slResponse.Add('<tr><td>QueryFields</td><td>');
    slResponse.AddStrings(sl);
    slResponse.Add('</td></tr>');
    slResponse.Add('<tr><td>Accept</td><td>' + Request.Accept + '</td></tr>');
    slResponse.Add('<tr><td>CacheControl</td><td>' + Request.CacheControl + '</td></tr>');
    slResponse.Add('<tr><td>Connection</td><td>' + Request.Connection + '</td></tr>');
    slResponse.Add('<tr><td>Content</td><td>' + Request.Content + '</td></tr>');
    slResponse.Add('<tr><td>ContentEncoding</td><td>' + Request.ContentEncoding + '</td></tr>');
    slResponse.Add('<tr><td>ContentType</td><td>' + Request.ContentType + '</td></tr>');
    slResponse.Add('<tr><td>ContentVersion</td><td>' + Request.ContentVersion + '</td></tr>');
    slResponse.Add('<tr><td>Cookie</td><td>' + Request.Cookie + '</td></tr>');
    slResponse.Add('<tr><td>DerivedFrom</td><td>' + Request.DerivedFrom + '</td></tr>');
    slResponse.Add('<tr><td>From</td><td>' + Request.From + '</td></tr>');
    slResponse.Add('<tr><td>Host</td><td>' + Request.Host + '</td></tr>');
    slResponse.Add('<tr><td>InternalPathInfo</td><td>' + Request.InternalPathInfo + '</td></tr>');
    slResponse.Add('<tr><td>InternalScriptName</td><td>' + Request.InternalScriptName + '</td></tr>');
    slResponse.Add('<tr><td>Method</td><td>' + Request.Method + '</td></tr>');
    slResponse.Add('<tr><td>PathInfo</td><td>' + Request.PathInfo + '</td></tr>');
    slResponse.Add('<tr><td>PathTranslated</td><td>' + Request.PathTranslated + '</td></tr>');
    slResponse.Add('<tr><td>ProtocolVersion</td><td>' + Request.ProtocolVersion + '</td></tr>');
    slResponse.Add('<tr><td>Query</td><td>' + Request.Query + '</td></tr>');
    slResponse.Add('<tr><td>Referer</td><td>' + Request.Referer + '</td></tr>');
    slResponse.Add('<tr><td>RemoteAddr</td><td>' + Request.RemoteAddr + '</td></tr>');
    slResponse.Add('<tr><td>RemoteHost</td><td>' + Request.RemoteHost + '</td></tr>');
    slResponse.Add('<tr><td>ScriptName</td><td>' + Request.ScriptName + '</td></tr>');
    slResponse.Add('<tr><td>Title</td><td>' + Request.Title + '</td></tr>');
    slResponse.Add('<tr><td>URL</td><td>' + Request.URL + '</td></tr>');
    slResponse.Add('<tr><td>UserAgent</td><td>' + Request.UserAgent + '</td></tr>');
    slResponse.Add('</table></body></html>');
    Response.Content :=  slResponse.Text;
  except
    on e : Exception do begin
      Response.Content := e.Message;
    end;
  end;
  slResponse.Free;
  sl.Free;
  Handled := true;
end;

fwn 9. Apr 2013 14:13

AW: Anmelden an Webmodul über IdHTTP
 
Hallo!

Zitat:

Zitat von nahpets (Beitrag 1210758)
Hallo,
mir ging es eigentlich garnicht um die Nutzung des HTTPServers sondern nur darum, ob Du eventuell "irgendwo" die Attribute RequestInfo.AuthUsername oder RequestInfo.AuthPassword finden und nutzen kannst.

ah, ok, hatte ich dann falsch verstanden:) Ich habe eben einmal danach gesucht, es sieht nicht so aus als würde ich da dran kommen.

Zitat:

Zitat von nahpets (Beitrag 1210758)
Habe mal ein Webmodul zusammengedaddelt, das alle Zeichenfolgen aus dem Request als HTML-Seite zurückgibt. Eventuell kannst Du ja damit was anfangen oder sehen ob und wo Benutzer und Passwort im Request enthalten sind. Bin mir allerdings nicht sicher, ob diese Informationen überhaupt vom Server an ein Webmodul weitergegeben werden.
Delphi-Quellcode:
procedure TWebModuleRequest.waiRequestAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  sl        : TStringList;
  slResponse : TStringList;
begin
  sl        := TStringList.Create;
  slResponse := TStringList.Create;
  try
    slResponse.Add('<html><head><title>Request-Inhalt</title></head><body>');
    slResponse.Add('<h1>Request-Inhalt</h1><hr />');
    slResponse.Add('<table border="1" cellspacing="3">');
    Request.ExtractContentFields(sl);
    slResponse.Add('<tr><td>ContentFields</td><td>');
    slResponse.AddStrings(sl);
    slResponse.Add('</td></tr>');
    Request.ExtractCookieFields(sl);
    slResponse.Add('<tr><td>CookieFields</td><td>');
    slResponse.AddStrings(sl);
    slResponse.Add('</td></tr>');
    Request.ExtractQueryFields(sl);
    slResponse.Add('<tr><td>QueryFields</td><td>');
    slResponse.AddStrings(sl);
    slResponse.Add('</td></tr>');
    slResponse.Add('<tr><td>Accept</td><td>' + Request.Accept + '</td></tr>');
    slResponse.Add('<tr><td>CacheControl</td><td>' + Request.CacheControl + '</td></tr>');
    slResponse.Add('<tr><td>Connection</td><td>' + Request.Connection + '</td></tr>');
    slResponse.Add('<tr><td>Content</td><td>' + Request.Content + '</td></tr>');
    slResponse.Add('<tr><td>ContentEncoding</td><td>' + Request.ContentEncoding + '</td></tr>');
    slResponse.Add('<tr><td>ContentType</td><td>' + Request.ContentType + '</td></tr>');
    slResponse.Add('<tr><td>ContentVersion</td><td>' + Request.ContentVersion + '</td></tr>');
    slResponse.Add('<tr><td>Cookie</td><td>' + Request.Cookie + '</td></tr>');
    slResponse.Add('<tr><td>DerivedFrom</td><td>' + Request.DerivedFrom + '</td></tr>');
    slResponse.Add('<tr><td>From</td><td>' + Request.From + '</td></tr>');
    slResponse.Add('<tr><td>Host</td><td>' + Request.Host + '</td></tr>');
    slResponse.Add('<tr><td>InternalPathInfo</td><td>' + Request.InternalPathInfo + '</td></tr>');
    slResponse.Add('<tr><td>InternalScriptName</td><td>' + Request.InternalScriptName + '</td></tr>');
    slResponse.Add('<tr><td>Method</td><td>' + Request.Method + '</td></tr>');
    slResponse.Add('<tr><td>PathInfo</td><td>' + Request.PathInfo + '</td></tr>');
    slResponse.Add('<tr><td>PathTranslated</td><td>' + Request.PathTranslated + '</td></tr>');
    slResponse.Add('<tr><td>ProtocolVersion</td><td>' + Request.ProtocolVersion + '</td></tr>');
    slResponse.Add('<tr><td>Query</td><td>' + Request.Query + '</td></tr>');
    slResponse.Add('<tr><td>Referer</td><td>' + Request.Referer + '</td></tr>');
    slResponse.Add('<tr><td>RemoteAddr</td><td>' + Request.RemoteAddr + '</td></tr>');
    slResponse.Add('<tr><td>RemoteHost</td><td>' + Request.RemoteHost + '</td></tr>');
    slResponse.Add('<tr><td>ScriptName</td><td>' + Request.ScriptName + '</td></tr>');
    slResponse.Add('<tr><td>Title</td><td>' + Request.Title + '</td></tr>');
    slResponse.Add('<tr><td>URL</td><td>' + Request.URL + '</td></tr>');
    slResponse.Add('<tr><td>UserAgent</td><td>' + Request.UserAgent + '</td></tr>');
    slResponse.Add('</table></body></html>');
    Response.Content :=  slResponse.Text;
  except
    on e : Exception do begin
      Response.Content := e.Message;
    end;
  end;
  slResponse.Free;
  sl.Free;
  Handled := true;
end;

Vielen Dank für die Mühe :-D
So etwas ähnliches hatte ich auch schon versucht, leider sind die meisten der Felder leer, die anderen enthalten nicht die Login-Informationen. Ich vermute inzwischen, dass ich für die Authentifizierung noch ne zusätzliche Komponente brauche, die ich auf das Webmodul legen muss, ich habe aber bis jetzt nicht die richtige finden können.
Ich arbeite mich jetzt grade durch das Tutorial hier das ich heute gefunden habe. Da mein Server später auch über JSON mit dem Client kommunizieren soll hoffe ich, dass mir das weiterhelfen wird.

Gruß,
Florian

Thom 9. Apr 2013 14:39

AW: Anmelden an Webmodul über IdHTTP
 
Schau mal dort.

Über Request.Authorization kann dieser String ausgelesen werden. Dann das Leerzeichen suchen, alles bis zu diesem Punkt entfernen und den Rest mit TIdDecoderMIME.DecodeString in Klartext zurückverwandeln. Dort wieder der Doppelpunkt suchen und man erhält den übergebene Usernamen sowie das Passwort.

nahpets 9. Apr 2013 14:47

AW: Anmelden an Webmodul über IdHTTP
 
Hallo,

da wirst Du (vermutlich) keine Komponente finden.

Habe vor längerer Zeut mal 'nen Webserver geschrieben, dort komme ich an die Anmeldeinformationen.

In den ISAPI.dll's und CGI-Programmen habe ich bisher keine Möglichkeit gefunden.
Dort mache ich eine Anmeldung immer über das Webmodul, indem es selbst die Anmeldedaten anfordert. D. H.: für jedes Webmodul gibt es eine eigene Anmeldung.

Das Ganze kann man "vereinfachen", wenn man eine entsprechende Klasse hat, die man in jedes Webmodul "hineinsteckt". Die Anmeldedaten habe ich dann nach erfolgreicher Anmeldung per Cookie immer "hin- und hergeschleppt". Erscheint mit suboptimal, aber eine andere Lösung hatte ich seinerzeit nicht gefunden.

Man könnte die Anmeldedaten in einer kleinen Datenbank speichern und gegen diese Username und Passwort prüfen und als Ergebnis die MD5-Summe dieser beiden Werte per Cookie durch die Gegend schieben. Bei jeder Anfrage an das Webmodul muss dieses dann gegen die Datenbank prüfen, ob es die MD5-Summe aus dem Cookie kennt, wenn ja, liegt die Vermutung nahe, dass sie von einem berechtigten Nutzer kommt. Schön ist diese Lösung allerdings nicht. Ok: habe nie professionelle Software über diesen Weg schreiben müssen, sondern nur kleine, nur intern zu nutzende, Anwendungen.

Ansonsten fiele mir nur noch eine Sessionverwaltung ein, bei der zuerst die Anmeldedaten vom Anwender geprüft werden und dann eine SessionID ausgetauscht wird.
Fehlt die, findet keine Kommunikation statt oder es werden die Anmeldedaten angefragt. Als SessionID könnte man dann auch die MD5-Summe nehmen.

Ach, irgendwie habe ich keine vernünftige Idee :-(

Wie forderst Du die Anmeldedaten an?
Muss der Browser den entsprechenden Dialog öffnen, dann müsste Thoms Hinweis umsetzbar sein. Allerdings scheint (bei mir?) Request.Authorization immer leer zu sein.

mjustin 9. Apr 2013 15:22

AW: Anmelden an Webmodul über IdHTTP
 
Hier ist ein passendes Thema mit Sourccode zum Auslesen der Basic Authentication Daten aus einem TWebRequest:

http://www.delphipraxis.net/45200-we...ebrequest.html

Wenn der Client die Basic Auth Parameter setzt wie im Ausgangsartikel beschrieben, sollte das Feld Request.Authorization nicht leer sein und mit dem Code in obigem Link entschlüsselbar seim.

Thom 9. Apr 2013 15:47

AW: Anmelden an Webmodul über IdHTTP
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich hatte das vorhin mit einer Kombination aus einem Programm mit TIdHTTP (Delphi XE3) und einer 64Bit-ISAPI-DLL (Delphi XE2) auf einem Windows Server 2008 ausprobiert:

Server:
Delphi-Quellcode:
procedure TWebModule1.WebModule1TestAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  N: Integer;
  S: String;
begin
  S := Request.Authorization;
  N := Pos(' ',s);
  if N > 0 then
  begin
    Delete(S,1,n);
    S := TIdDecoderMIME.DecodeString(S);
    N := Pos(':',S);
    if N > 0 then
    begin
      Response.Content:=Format('Username: %s'+sLineBreak+'Password: %s',[Copy(S,1,N-1),Copy(S,N+1,Length(S)-N+1)]);
      Exit;
    end;
  end;
  Response.Content:='Error';
end;
Klient:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  HTTP: TIdHTTP;
begin
  HTTP := TIdHTTP.Create;
  try
    HTTP.Request.BasicAuthentication := True;
    HTTP.HandleRedirects := True;
    HTTP.Request.Username := Edit1.Text;
    HTTP.Request.Password := Edit2.Text;
    Memo1.Lines.Text := HTTP.Get('http://maps4delphi.com/test');
  finally
    HTTP.Free;
  end;
end;
Anhang 38927

Hinweis: Der Link zum Server ist nur temporär gültig.

@mjustin:
Hatte ich nicht genau das beschrieben!? :wink:

nahpets 9. Apr 2013 16:44

AW: Anmelden an Webmodul über IdHTTP
 
Hallo,

jetzt fange ich (hoffentlich) an, das Problem zu verstehen (oder eher zu erahnen).

Wenn Client und WebModul mit Indy... erstellt wurden scheint das Verhalten anders zu sein, als bei einer Nutzung von Browser und Webmodul.

Hab' eben mal 'ne Isapi.dll geschrieben, aber (bisher) vom Browser dort keine Anmeldeinformationen erhalten. Auch dann nicht, wenn ich den Webserver so konfiguriere, dass er eine Anmeldung verlangt.

Der Browser zeigt mir dann den Anmeldedialog an und fragt nach Benutzername und Passwort. Der Webserver protokolliert die erfolgreiche Anmeldung, aber in der Isapi.dll kann ich davon nichts finden.

Wenn ich die von Thom geschriebenen Quelltexte nutzte, sowohl in einem neuen Client, als auch in einer neuen ISAPI.dll, so bekomme ich von seiner Seite die Anmeldeinformationen geliefert. In einer mit Delphi 7 erstellten ISAPI.dll bekomme ich bei 1:1 übernommenem Quelltext gegen meinen eigenen Webserver keine Benutzerinformationen. Mein Webserver protokolliert aber die Anmeldedaten, muss sie von daher also kennen. Bei ungültigen Anmeldedaten gibt er den Fehler 401 zurück.

Sollte hier die Funktionalität abhängig von der Delphiversion sein oder vom Webserver?

Das wäre sehr ärgerlich :-(

@Thom

Wie kann ich per Browser von Deiner Seite eine Antwort <> Error erhalten?

Mit Firefox ist theoretisch eine Anmeldung in der Form möglich:
Code:
http://peter:paul@maps4delphi.com/test
Diese funktioniert bei Deiner Seite jedoch nicht, daher gehe ich davon aus, dass die Anmeldeinformationen nicht in der ISAPI.Dll ankommen.

Aber das lenkt jetzt von eigentlichen Problem ab.

Thom 9. Apr 2013 19:41

AW: Anmelden an Webmodul über IdHTTP
 
Hallo nahpets,

ich hatte gerade noch etwas den Quelltext überarbeitet:

Server:
Delphi-Quellcode:
procedure TWebModule1.WebModule1TestAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  N: Integer;
  S: String;
begin
  S := String(Request.Authorization);
  N := Pos(' ',S);
  if N > 0 then
  begin
    Delete(S,1,N);
    S := TIdDecoderMIME.DecodeString(s);
    N := Pos(':',S);
    if N > 0 then
    begin
      Response.Content:=Format('Username: %s<br>Password: %s',[Copy(S,1,N-1),Copy(S,N+1,Length(S)-N+1)]);
      Exit;
    end;
  end;
  Response.WWWAuthenticate := 'Basic';
  Response.StatusCode := 401;
end;
Klient:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  HTTP: TIdHTTP;
begin
  HTTP := TIdHTTP.Create;
  try
    HTTP.Request.BasicAuthentication := True;
    HTTP.HandleRedirects := True;
    HTTP.Request.Username := Edit1.Text;
    HTTP.Request.Password := Edit2.Text;
    Memo1.Lines.Text := StringReplace(HTTP.Get('http://maps4delphi.com/test'),'<br>',sLineBreak,[rfReplaceAll]);
  finally
    HTTP.Free;
  end;
end;
Damit reagiert der Server auch auf Browseranfragen (getestet mit IE9, IE10, Firefox und Google Chrome). Hier erscheint dann wegen des Statuscodes 401 der Eingabedialog für Name und Passwort.
Da ich den Zeilenumbruch in ein "<br>"-Tag umgewandelt habe, wird die Serverantwort auch korrekt im Browser angezeigt. Für die Anzeige im Delphi-Programm wird der Zeilenumbruch durch StringReplace umgewandelt.

Die Übergabe per "Name:Passwort@xyz" funktioniert nicht.

Unter Delphi 7 könnte es eventuell noch Probleme mit der Eigenschaft Request.Authorization geben. Das kann ich momentan leider nicht testen. Du könntest aber mal versuchen, diesen Wert direkt abzufragen:
Delphi-Quellcode:
Request.GetFieldByName('Authorization');


P.S.:
Das Ganze funktioniert natürlich auch über HTTPS (wegen Basic-Authentifikation = unsicher):
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  HTTP: TIdHTTP;
  SSL: TIdSSLIOHandlerSocketOpenSSL;
begin
  HTTP := TIdHTTP.Create;
  try
    SSL := TIdSSLIOHandlerSocketOpenSSL.Create;
    try
      HTTP.IOHandler := SSL;
      HTTP.Request.BasicAuthentication := True;
      HTTP.HandleRedirects := True;
      HTTP.Request.Username := Edit1.Text;
      HTTP.Request.Password := Edit2.Text;
      Memo1.Lines.Text := StringReplace(HTTP.Get('https://maps4delphi.com/test'),'<br>',sLineBreak,[rfReplaceAll]);
    finally
      SSL.Free;
    end;
  finally
    HTTP.Free;
  end;
end;

nahpets 9. Apr 2013 23:22

AW: Anmelden an Webmodul über IdHTTP
 
Hallo Thom,

Code:
http://username:password@maps4delphi.com/test
funktioniert mit dem Firefox, der IE unterstützt dies nicht.

Delphi-Quellcode:
Request.GetFieldByName('Authorization')
liefert mir unter Delphi 7 keinen Wert. Da könnte also ein versionsabhängiges Problem vorliegen.

Thom 10. Apr 2013 01:00

AW: Anmelden an Webmodul über IdHTTP
 
Hallo Stephan,

wieder was dazu gelernt - danke! Mit dem Feuerfuchs funktioniert das tatsächlich. :idea:

Ich werde morgen (oder besser: heute) mal Delphi 7 auf dem Server installieren und die Sache testen. Vielleicht finden wir ja die Ursache für das Problem...

nahpets 10. Apr 2013 12:25

AW: Anmelden an Webmodul über IdHTTP
 
Hallo,

habe mal "weiter gedaddelt"

In meinem (mit Delphi 7 geschriebenen) Webserver kann ich die Anmeldedaten in
Delphi-Quellcode:
RequestInfo.AuthUsername
und
Delphi-Quellcode:
RequestInfo.AuthPassword
finden.

RequestInfo ist vom Typ TIdHTTPRequestInfo abgeleitet von TIdRequestHeaderInfo.

RequestInfo wird an die ISAPI.dlls weitergegeben und steht dort als Request vom Type TWebRequest zur Verfügung.

Die Attribute von RequestInfo auf Serverseite und Request auf DLL-Seite sind aber nicht identisch, es gibt lediglich eine Schnittmenge, welche Username und Password nicht enthält.

Momentan sehe ich keine Lösungsmöglichkeit für dieses Problem.

Thom 10. Apr 2013 13:09

AW: Anmelden an Webmodul über IdHTTP
 
Ich habe die Methode Test mal etwas abgewandelt:
Delphi-Quellcode:
procedure TWebModule1.WebModule1TestAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  N: Integer;
  S: String;
begin
  S := String(Request.Authorization);
  N := Pos(' ',S);
  if N > 0 then
  begin
    Delete(S,1,N);
    S := TIdDecoderMIME.DecodeString(s);
    N := Pos(':',S);
    if N > 0 then
    begin
      Response.Content:=Request.GetFieldByName('ALL_RAW');
      Exit;
    end;
  end;
  Response.WWWAuthenticate := 'Basic';
  Response.StatusCode := 401;
end;
Damit wird jetzt der komplette Header, der vom Browser an den Server übertragen wird, angezeigt:
Code:
Connection: Keep-Alive
Content-Length: 0
Accept: text/html, application/xhtml+xml, */*
Accept-Encoding: gzip, deflate
Accept-Language: de-DE
Authorization: Basic VGVzdDpCbHVi
Cookie: [...]
Host: maps4delphi.com
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
X-Original-URL: /test
Hier kann man schön sehen, daß die Anmeldedaten wirklich im Wert "Authorization" enthalten sind.
Funktioniert das bei Dir in der Delphi 7 Dll?

nahpets 10. Apr 2013 14:38

AW: Anmelden an Webmodul über IdHTTP
 
Hallo Thom,

nö, funktioniert nicht.

Der Datenaustausch zwischen Webserver und DLL erfolgt über den TEXTENSION_CONTROL_BLOCK. In Delphi 7 ist er so definiert:
Delphi-Quellcode:
 TEXTENSION_CONTROL_BLOCK = packed record
    cbSize: DWORD;                   // size of this struct.
    dwVersion: DWORD;                // version info of this spec
    ConnID: HCONN;                   // Context number not to be modified!
    dwHttpStatusCode: DWORD;         // HTTP Status code
             // null terminated log info specific to this Extension DLL
    lpszLogData: array [0..HSE_LOG_BUFFER_LEN-1] of Char;
    lpszMethod: PChar;               // REQUEST_METHOD
    lpszQueryString: PChar;          // QUERY_STRING
    lpszPathInfo: PChar;             // PATH_INFO
    lpszPathTranslated: PChar;       // PATH_TRANSLATED
    cbTotalBytes: DWORD;             // Total bytes indicated from client
    cbAvailable: DWORD;              // Available number of bytes
    lpbData: Pointer;                // pointer to cbAvailable bytes
    lpszContentType: PChar;          // Content type of client data

    GetServerVariable: TGetServerVariableProc;
    WriteClient: TWriteClientProc;
    ReadClient: TReadClientProc;
    ServerSupportFunction: TServerSupportFunctionProc;
  end;
Zu finden in der \source\rtl\win\Isapi2.pas.

Die Werte aus diesem Block werden letztlich mit dieser Routine gelesen:
Delphi-Quellcode:
function TISAPIRequest.GetStringVariable(Index: Integer): string;
begin
  case Index of
    0: Result := ECB.lpszMethod;
    3: Result := ECB.lpszQueryString;
    4: Result := ECB.lpszPathInfo;
    5: Result := ECB.lpszPathTranslated;
    1..2, 6..24, 26..28: Result := GetFieldByName(ServerVariables[Index]);
    25: if ECB.cbAvailable > 0 then
      SetString(Result, PChar(ECB.lpbData), ECB.cbAvailable);
   else
      Result := '';
  end;
end;
Die möglichen, zu lesenden Werte sind:
Delphi-Quellcode:
const
  ServerVariables: array[0..28] of string = (
    '',
    'SERVER_PROTOCOL',
    'URL',
    '',
    '',
    '',
    'HTTP_CACHE_CONTROL',
    'HTTP_DATE',
    'HTTP_ACCEPT',
    'HTTP_FROM',
    'HTTP_HOST',
    'HTTP_IF_MODIFIED_SINCE',
    'HTTP_REFERER',
    'HTTP_USER_AGENT',
    'HTTP_CONTENT_ENCODING',
    'CONTENT_TYPE',
    'CONTENT_LENGTH',
    'HTTP_CONTENT_VERSION',
    'HTTP_DERIVED_FROM',
    'HTTP_EXPIRES',
    'HTTP_TITLE',
    'REMOTE_ADDR',
    'REMOTE_HOST',
    'SCRIPT_NAME',
    'SERVER_PORT',
    '',
    'HTTP_CONNECTION',
    'HTTP_COOKIE',
    'HTTP_AUTHORIZATION');
Es ist mir bisher nicht gelungen, an andere Werte zu kommen.

Ist dieser Kommentar aus der Isapi2.pas eventuell von Bedeutung?
Delphi-Quellcode:
{       Structure definitions and prototypes for the   }
{       version 2.0 HTTP Server Extension interface.   }
Sprich: Hat sich da in der Version was verändert?

Irgendwie weiß ich momentan nicht weiter. Die Anmeldedaten sind in einer DLL wohl sehr geheim ;-)

Thom 10. Apr 2013 16:21

AW: Anmelden an Webmodul über IdHTTP
 
Wahrscheinlich... :lol:

Ich habe jetzt nach etlichen Mühen Delphi 7 unter Windows Server 2008 zum Laufen bekommen. Dummerweise akzeptiert der IIS nur 32- oder 64Bit Dll's, so daß ich den ganzen Rest auch noch mal "schnell" nach 32Bit umsetzen mußte.

Die gute Nachricht: Die Anmeldung funktioniert auch mit einer ISAPI-Dll, die mit Delphi 7 kompiliert wurde. Das kannst Du hier testen.

Die schlechte Nachricht: Ich habe momentan absolut keine Idee, weshalb das bei Dir nicht funktioniert.
Könntest Du eventuell mal Deine Dll (Quelltext) hier posten, damit ich die bei mir ausprobieren kann?

nahpets 10. Apr 2013 17:40

AW: Anmelden an Webmodul über IdHTTP
 
Hallo Thom,

Quelltext und kompilierte DLL als Zip.
Die DLL ist kein Meisterwerk in objektorientierter oder sauberer Programmierung, sondern so dahingedaddelt und teilweise aus Textlisten generiert. Tut halt ;-)

Könnte es sein, dass unterschiedliche Webserver hier die Daten nach "gutdünken" weitergeben?

Nach weiterem Suchen in diversen Quelltexten habe ich herausgefunden, dass ich bei meinem Webserver und meiner DLL den Benutzernamen in der Servervariabel AUTH_NAME und das Passwort in AUTH_PASS finden kann. Ob das aber immer so ist oder so sein muss, kann ich nicht sagen.

Würde mich schon interessieren, ob Du mit dieser DLL die Werte an den gleichen Stellen bekommst oder das mit dem IIS alles irgendwie anders ist. Dann muss ich in meinem Webserver nämlich wohl doch noch ein paar Fehler beheben :-(

Thom 10. Apr 2013 20:54

AW: Anmelden an Webmodul über IdHTTP
 
Hallo Stephan,

ändere mal im Quelltext folgenden Abschnitt:
Delphi-Quellcode:
  [...]
  if N > 0 then begin
    Delete(S,1,n);
    S := TIdDecoderMIME.DecodeString(S);
    N := Pos(':',S);
    if N > 0 then begin
      sAuthorization := Format('Username: %s'+ sLineBreak +'Password: %s',[Copy(S,1,N-1),Copy(S,N+1,Length(S)-N+1)]);
    end;
  end else //<- ab hier zusätzlich
  begin
    Response.WWWAuthenticate := 'Basic';
    Response.StatusCode := 401;
    Exit;
  end;
  [...]
Ansonsten fordert der Server keine Autorisation an und damit wird diese auch nicht angezeigt. Im Feuerfuchs funktioniert das auch mit Username:Password@xyz.

P.S.: Test hier.

nahpets 10. Apr 2013 23:06

AW: Anmelden an Webmodul über IdHTTP
 
Hallo Thom,

Danke für die viele Mühe die Du Dir bei der Probelmlösung machst.

Auf dem IIS hast Du quasi meine DLL eingebunden, die Ergebnisseite ist bei Dir deutlich "besser" mit Informationen gefüllt, als bei mir. D. h.: Mein Webserver gibt (warum auch immer) nicht alle Informationen preis. Da ich für das ganze nur die Indy-Komponenten sowie idRunner components v. 3.4 nutze, muss ich die Ursache (vermutlich) dort irgendwo suchen oder eine Stelle finden, an der ich die Informationen gezielt "einstreuen" kann.

Die Änderung an der DLL bringt bei mir keinen Vorteil, im Gegenteil, die Methode wird immer im neuen Else-Zweig verlassen, so dass ich nie ein Ergebnis zu Gesicht bekomme. Der Webserver fordert aber die Anmeldung an und protokolliert die erfolgreiche Anmeldung.

Das sieht im Protokoll dann so aus:
Code:

HTTPServer | 2013.04.10 23.49.45,453 | 127.000.000.001:4068 | stephan | GET /scripts/webmodul.dll/request
HTTPServer | 2013.04.10 23.49.45,453 | 127.000.000.001 | localhost | erlaubter Zugriff mit IP-Security
HTTPServer | 2013.04.10 23.49.45,500 | Login ok | Benutzername: stephan
HTTPServer | 2013.04.10 23.49.45,625 | 127.000.000.001:4068 | stephan | GET .\scripts\webmodul.dll | 4375 | 200 | text/html
Da mein Webserver nicht aus der großen weiten Welt zu sehen ist, sondern nur lokal genutzt wird, habe ich mal die Ergebnisseite, wie sie sich hier darstellt, drangehängt.

Thom 11. Apr 2013 13:28

AW: Anmelden an Webmodul über IdHTTP
 
Hallo Stephan,

das sieht ja wirklich recht spartanisch aus...

Da ich die idRunner-Komponenten nicht kenne, kann ich leider dazu nichts sagen. Aber irgendwie scheinen die einen großen Teil der Informationen zu verschweigen. Normalerweise sollten alle Informationen, die vom Klienten kommen, auch im Rohformat an die ISAPI-Dll durchgereicht werden, so daß sie über die entsprechenden Anweisungen ausgelesen werden können. Wenn hier schon
Delphi-Quellcode:
Request.GetFieldByName('ALL_RAW');
versagt, stimmt etwas nicht. Insofern scheint das ISAPI nicht vollständig unterstützt zu werden.

Wahrscheinlich hilft nur debuggen, da - so weit ich jetzt gelesen habe - diese Komponenten nicht weiterentwickelt werden.

nahpets 11. Apr 2013 13:56

AW: Anmelden an Webmodul über IdHTTP
 
Hallo Thom,

jo, da muss ich dann nochmal ran, es war schon ein erheblicher Aufwand die Komponenten soweit anzupassen, dass sie nun mit Indy 10 genutzt werden können. Bei den Indy-Komponenten ist wohl irgendwann zwischen Indy 8 und Indy 10 erhebliches geändert worden.

Im Webserver habe ich halt TRequestInfo zur Verfügung mit allen Infos, die Indy liefert. TRequestInfo wird, inhaltlich unverändert, an die IDRunner-Komponente weitergegeben, so dass dort eher nichts verloren gehen dürfte. Im Webmodul für die DLLs steht dann TWebRequest zur Verfügung, hier enthält der Request aber nicht alle Attribute, die TRequestInfo von Indy enthält. Bisher habe ich noch nicht verstanden, wie die Daten nun genau vom Webserver an die DLL weitergereicht werden. Irgendwo in dieser (noch) Blackbox werde ich dann wohl mal suchen müssen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:22 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz