2017-05-10 1 views
3

ich möchte wissen, ob ein Benutzer die richtige Kombination aus Domäne, Benutzer und Kennwort für seinen Active Directory-Benutzer eingibt.Überprüfen Sie, ob die Benutzerauthentifizierung in Active DIrectory

Ich habe versucht, ein sehr einfaches Programm zu erstellen, das keine Verbindung herstellen kann, aber durch das Lesen der Fehlermeldung kann ich wissen, ob der Benutzer/das Passwort korrekt ist.

Dies ist Trick basiert (die Logik ist auf das Lesen der Ausnahme Nachricht), jedenfalls habe ich diesen Prototyp auf 2 Servern getestet und ich bemerkte, dass die Exception Nachrichten von Server zu Server ändern, so dass dies nicht zuverlässig ist.

uses adshlp, ActiveDs_TLB; 
// 3 TEdit and a TButton 

procedure TForm4.Button1Click(Sender: TObject); 
Var 
aUser : IAdsUser; 
pDomain, pUser, pPassword : string; 
myResult : HRESULT; 
Counter: integer; 
begin 
    pDomain := edtDomain.Text; 
    pUser:= edtUser.Text; 
    pPassword := edtPwd.Text; 
    Counter := GetTickCount; 


Try 
    myResult := ADsOpenObject(Format('LDAP://%s',[pDomain]),Format('%s\%s',[pDomain,pUser]),pPassword, 
    ADS_READONLY_SERVER, 
    IAdsUser,aUser); 
except 
    On E : EOleException do 
    begin 
    if (GetTickCount - Counter > 3000) then ShowMessage ('Problem with connection') else 
    if Pos('password',E.Message) > 0 then ShowMessage ('wrong username or password') else 
    if Pos('server',E.Message) > 0 then ShowMessage ('Connected') else 
    ShowMessage('Unhandled case'); 
    memLog.Lines.Add(E.Message); 
    end; 

end 
end; 

Der Grund, warum ich „Connected“, wenn die Meldung „Server“ gesetzt enthalten ist, dass auf meinen lokalen Rechnern (auf meinem Firma LDAP-Server in der Tat), falls alles in Ordnung ist (Domäne, Benutzer und Passwort) Der Server antwortet: "Der Server benötigt eine sicherere Authentifizierung", also ist das Wort "Server" dort, während in anderen Fällen "falscher Benutzer oder falsches Passwort" steht. Wenn dies auf itlianischen und englischen Servern funktionieren soll, setze ich "server" und "pasword" als zuverlässige Wörter. Jedenfalls habe ich auf einem anderen Server getestet, der verschiedene Fehler gibt.

Ich begann von einer Antwort auf this question, um das obige zu tun.

Wie kann ich überprüfen, ob der Benutzer mit einer ähnlichen Technik das richtige Passwort richtig eingegeben hat oder nicht?

UPDATE (gefunden Lösung)

Dank der Antworten gelang es mir, diese Funktion zu schreiben, die das tut, was ich brauche. Es scheint recht zuverlässig bis jetzt, ich schreibe hier zu teilen, in der Hoffnung es andere helfen kann:

// This function returns True if the provided parameters are correct 
// login credentials for a user in the specified Domain 
// From empirical tests it seems reliable 
function UserCanLogin(aDomain, aUser, aPassword: string): Boolean; 
var 
    hToken: THandle; 
begin 
    Result := False; 
    if (LogonUser(pChar(aUser), pChar(aDomain), pChar(aPassword), LOGON32_LOGON_INTERACTIVE, 
    LOGON32_PROVIDER_DEFAULT, hToken)) then 
    begin 
    CloseHandle(hToken); 
    Result := True; 
    end; 
end; 

Antwort

1

ich möchte wissen, ob ein Benutzer gibt die richtige Kombination von Domain, Benutzer und Kennwort für seine Active Directory-Benutzer.

Sie können die Funktion LogonUser verwenden, um die Benutzeranmeldung zu überprüfen, z. :

if (LogonUser(pChar(_Username), pChar(_ADServer), pChar(_Password), LOGON32_LOGON_INTERACTIVE, 
    LOGON32_PROVIDER_DEFAULT, hToken)) then 
    begin 
    CloseHandle(hToken); 
    //... 
    //DoSomething 
    end 
    else raise Exception.Create(SysErrorMessage(GetLastError)); 

Hinweis: Sie müssen LogonUser innerhalb einer Domäne Maschine verwenden zu können, die Domain-Anmeldung oder die Funktion verwenden, wird immer wieder zurückkehren The user name or password is incorrect

Die Alternative verwendet wird TLDAPSend z.B. :

function _IsAuthenticated(const lpszUsername, lpszDomain, lpszPassword: string): Boolean; 
var 
    LDAP : TLDAPSend; 
begin 
    Result := False; 
    if ((Length(lpszUsername) = 0) or (Length(lpszPassword) = 0))then Exit; 
    LDAP := TLDAPSend.Create; 
    try 
    LDAP.TargetHost := lpszDomain; 
    LDAP.TargetPort := '389'; 
    .... 
    LDAP.UserName := lpszUsername + #64 + lpszDomain;; 
    LDAP.Password := lpszPassword; 
    Result := LDAP.Login; 
    finally 
    LDAP.Free; 
    end; 
end; 

Wie kann ich überprüfen, ob das das richtige Passwort oder nicht in einer zuverlässigen Art und Weise eine ähnliche Technik gesetzt Benutzer?

Versuchen zu verwenden FormatMessage function

FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM, 
       nil, 
       myResult, 
       LANG_ENGLISH or SUBLANG_ENGLISH_US, 
       lpMsg, 
       0, 
       nil); 
MessageBox(0, lpMsg, 'Msg', 0); 
+0

Danke, mit LogonUser konnte ich mein Ergebnis erreichen (ich aktualisiere jetzt meine Frage, um die einfache Funktion zu teilen, die ich schrieb). LogonUser löst keine Ausnahme wie ADsOpenObject. Ich habe meine Funktion auf 3 verschiedenen Servern (mit 3 verschiedenen Domänencontrollern) ausprobiert und es scheint zu funktionieren. – LaBracca

+0

Morevoer die Lösung mit LogonUser ist einfacher als adshlp, ActiveDs_TLB wird nicht benötigt – LaBracca

+2

Sie können 'SysErrorMessage (myResult)' anstelle von 'FormatMessage()' verwenden, die Sie den zugewiesenen Puffer sowieso nicht freigeben. Ehrlich gesagt verstehe ich diesen Teil der Antwort nicht. Wahrscheinlich habe ich die Frage falsch gelesen ... –

1

ich (HRESULT) 0x8007052e (2147943726) „unbekannter Benutzername oder falsches Kennwort“ wenn ich ein falsches Passwort verwenden . Und da kein EOleException, versuchen:

 hr := ADsOpenObject('LDAP://'+ ADomain + '/OU=Domain Controllers,' + APath, 
         AUser, APwd, 
         ADS_SECURE_AUTHENTICATION or ADS_READONLY_SERVER, 
         IID_IADs, pObject); 
    if (hr=HRESULT(2147943726)) then ShowMessage ('wrong username or password') 
+0

Leider habe ich immer EOleException, so dass ich myResult immer 0 ist, da die Ausnahme das ADsOpenObject nicht erlaubt, einen Wert an MyResult zurückzugeben. Wie kann ich? Ich fing an, E.Message zu benutzen, weil ich es lesen kann. bitte schlagen Sie – LaBracca

+0

@ user193655 vor, ich habe die Antwort mit dem, was funktioniert, aktualisiert und auf DCs 2003 bis 2016 getestet worden. – FredS

3

benötigen Sie den Fehlercode, der ADsOpenObject kehrt zu überprüfen. Basieren Sie Ihre Fehlerprüfung nicht auf der zurückgegebenen Ausnahme Nachrichten.

, wenn die Funktion gelang es S_OK zurückkehren, sonst müssen Sie ADSI Error Codes beziehen, insbesondere die LDAP error codes for ADSI

Wenn ein LDAP-Server einen Fehler erzeugt und übergibt den Fehler an den Client ist der Fehler dann vom LDAP-Client in eine Zeichenfolge übersetzt.

Diese Methode ähnelt den Win32-Fehlercodes für ADSI. In diesem Beispiel der Client-Fehlercode ist der WIN32-Fehler 0x80072020.

Um den LDAP-Fehlercodes für ADSI bestimmen

  1. die 8007 aus dem Fehlercode WIN32 fallen. Im Beispiel ist der verbleibende Hexadezimalwert 2020.
  2. Konvertieren Sie den verbleibenden Hexadezimalwert in einen Dezimalwert. Im Beispiel wird der verbleibende Hexwert 2020 in den Dezimalwert 8224 umgerechnet.
  3. Suchen Sie in der Datei WinError.h nach der Definition des Dezimalwerts. In dem Beispiel entspricht 8224L dem Fehler ERROR_DS_OPERATIONS_ERROR.
  4. Ersetzen Sie das Präfix ERROR_DS mit LDAP_. In diesem Beispiel lautet die neue Definition LDAP_OPERATIONS_ERROR.
  5. Suchen Sie in der Datei Winldap.h nach dem Wert der LDAP-Fehlerdefinition. Im Beispiel ist der Wert LDAP_OPERATIONS_ERROR in der Winldap.h-Datei 0x01.

Für ein 0x8007052e Ergebnis (0x052e = 1326) zum Beispiel Sie ERROR_LOGON_FAILURE


Von Ihrem Kommentar erhalten:

Da die Funktion immer eine Ausnahme auslöst ich nicht bin in der Lage zu lesen der Code

Sie erhalten eine EOleException, weil Ihre ADsOpenObject-Funktion mit safecall Aufrufkonvention definiert ist. während andere Implementierungen möglicherweise stdcall verwenden. Bei Verwendung von safecall wird Delphi eine EOleException auslösen und die HResult wird in der EOleException.ErrorCode reflektiert, andernfalls (stdcall) wird keine Ausnahme ausgelöst und die HResult wird von der Funktion zurückgegeben.

+0

Da die Funktion immer eine Ausnahme auslöst, kann ich den Code nicht lesen, trotzdem konnte ich mein Problem, wie in der Frage beschrieben, dank der akzeptierten Antwort lösen. Vielen Dank für Hilfe! – LaBracca

+0

@ user193655, siehe meine Bearbeitung der Ausnahme. – kobik