检查活动目录中的用户身份验证

LaB*_*cca 7 delphi ldap delphi-10-seattle

我想知道用户是否为其 Active Directory 用户输入了域、用户和密码的正确组合。

我试图制作一个无法连接的非常简单的程序,但通过阅读错误消息,我可以知道用户/密码是否正确。

这是基于技巧的(逻辑是读取异常消息),无论如何我在 2 个服务器上测试了这个原型,我注意到 excpetion 消息从服务器到服务器发生变化,所以这是不可靠的。

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;
Run Code Online (Sandbox Code Playgroud)

如果消息包含“服务器”,我设置“已连接”的原因是在我的本地机器上(实际上是在我公司的 ldap 服务器上),以防万一(域、用户和密码)服务器回复“服务器需要一个更安全的身份验证”,因此“服务器”一词就在其中,而在其他情况下,它表示“用户或密码错误”。因为这必须在意大利语和英语服务器上工作,所以我将“服务器”和“密码”设置为可靠的词。无论如何,我在另一台出现不同错误的服务器上进行了测试。

我从回答这个问题开始做上面的。

如何使用类似技术以更可靠的方式检查用户是否设置了正确的密码?

更新(找到解决方案)

多亏了答复,我才设法编写了满足我需要的功能。目前看来还是挺靠谱的,写到这里分享一下,希望能帮到大家:

// 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;
Run Code Online (Sandbox Code Playgroud)

Rep*_*til 2

我想知道用户是否为其 Active Directory 用户输入了正确的域、用户和密码组合。

您可以使用LogonUser函数来验证用户登录,例如:

  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));
Run Code Online (Sandbox Code Playgroud)

注意:您必须LogonUser在域计算机内使用才能使用域登录,否则该函数将始终返回The user name or password is incorrect

另一种方法是使用TLDAPSend例如:

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;
Run Code Online (Sandbox Code Playgroud)

我如何使用类似的技术以更可靠的方式检查用户是否设置了正确的密码?

尝试使用FormatMessage函数

 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);
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用“SysErrorMessage(myResult)”代替“FormatMessage()”,无论如何您都不会释放分配的缓冲区。老实说,我不明白答案的这一部分。可能是我看错问题了... (2认同)
  • @SertacAkyuz,你没有误读这个问题。`FormatMessage` 在这里无关紧要。 (2认同)