Check username/password in Active Directory from P

2019-08-27 16:29发布

Edit: I modified the code according to Andrei Galatyn's comment and hints that I shall not rely on token being nil when invalid, but it's still not working for PC's that are not part of the domain.


I want to verify if a user entered a username/password combination that is valid in a LDAP server.

Currently I use this code:

function CheckWinUserAccount(Username, Password, Domain : string) : boolean;
var token: THandle;
begin
     result:=False;
     if LogonUser( PChar(Username), PChar(Domain), PChar(Password),
                   LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, token) then
     begin
          CloseHandle(token);
          result:=True;
     end;
end;

It works perfectly if executed on a PC that is part of the LDAP domain, but not on a PC that only uses the LDAP PC as DNS but is not part of the domain.

My data:

  • Domain: graz.local
  • Username: LDTest

I tried entering the username as LDTest, as graz\LDTest and as graz.local\LDTest.

I also tried specifying the domain as graz, graz.local, ldap://graz.local

None of that worked. Any idea?

Btw: I was not sure if this is possible at all (accessing the domain server from a non-domain-PC), but using the LDAP Administrator (by Softerra) this works.

1条回答
叛逆
2楼-- · 2019-08-27 16:53

As noted by Andrei Galatyn use LOGON32_LOGON_NETWORK instead of LOGON32_LOGON_INTERACTIVE when calling "LogonUser". The username should not include the domain name, the domain name can either be the NetBIOS domain name ("graz") or the DNS domain name ("graz.local").

EDIT: Using "LogonUser" only works if the client has already established a connection to the domain.

Here is the code which performs the authentication using LDAP.

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Windows,
  JwaWinLDAP,
  JwaRpcDce;

var
    sUsername, sDomain, sPassword, sDC : String;
    LDAP : PLDAP;
    SWAI : SEC_WINNT_AUTH_IDENTITY;

begin
    if (ParamCount <> 4) then
    begin
        WriteLn ('WinLdapTest [username] [domain] [password] [domain controller]');
        Halt (1);
    end; { if }

    sUsername := ParamStr (1);
    sDomain := ParamStr (2);
    sPassword := ParamStr (3);
    sDC := ParamStr (4);

    LDAP := ldap_openW (PChar (sDC), LDAP_PORT);

    if (Assigned (LDAP)) then
        try
            SWAI.User := PChar (sUserName);
            SWAI.UserLength := Length (sUserName);
            SWAI.Domain := PChar (sDomain);
            SWAI.DomainLength := Length (sDomain);
            SWAI.Password := PChar (sPassword);
            SWAI.PasswordLength := Length (sPassword);
            SWAI.Flags := SEC_WINNT_AUTH_IDENTITY_UNICODE;

            if (ldap_bind_sW (LDAP, PChar (sDC), PChar (@SWAI),
                              LDAP_AUTH_NTLM) = LDAP_SUCCESS) then
                WriteLN ('"ldap_bind" success')
            else WriteLN ('"ldap_bind" failure');

        finally
            ldap_unbind (LDAP);
        end { try / finally }
    else WriteLn ('"ldap_open" failed');
end.

The code uses the JEDI API library and assumes that you're using Delphi 2009 or higher (Unicode strings). To automatically retrieve the DC name you could call DsGetDcName.

查看更多
登录 后发表回答