Check if user authentication in Active DIrectory
delphi, delphi-10-seattle, ldap
Solution
i would like to know whether a user inputs the correct combination of Domain, User and Password for his Active Directory user.
You can use LogonUser function to validate user login e.g. :
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));
Note: You must use `LogonUser` within a domain machine to be able to use the domain login or the function will always return `The user name or password is incorrect`
The alternative is using TLDAPSend e.g. :
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;
How can i check if the user set the correct password or not in a more reliable way using a similar technique?
Try to use 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);
Problem
i would like to know whether a user inputs the correct combination of Domain, User and Password for his Active Directory user. I tried to make a very simple program that is not able to connect but by reading the error message i can know if the user/password is correct. This is trick based (the logic is on reading the Exception message), anyway i testd this prototype on 2 servers and i noticed that the excpetion messages change from server to server so this is not reliable. ``` 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; ``` The reason why i set "Connected" if the message contain "server" is that on my local machine (on my company ldap server in fact) in case all is fine (domain, user and password) the server replies "The server requires a safer authentication", so the "server" word is in there, while in other cases it says "wrong user or password". SInce this must work on itlian and english servers i set "server" and "pasword" as reliable words. Anyway i tested on another server that gives differente errors. I started from a reply to this question to do the above. How can i check if the user set the correct password or not in a more reliable way using a similar technique? UPDATE (found solution) Thanks to the replies i managed to write this function that does what i need. It seems quite reliable up to now, I write here to share, hoping it can help others: ``` // 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; ```