Delphi 从不属于域的PC检查Active Directory中的用户名/密码

Delphi 从不属于域的PC检查Active Directory中的用户名/密码,delphi,ldap,delphi-2010,Delphi,Ldap,Delphi 2010,编辑:我根据Andrei Galattyn的评论和提示修改了代码,提示我不应依赖无效时为零的令牌,但它仍然不适用于不属于域的PC 我想验证用户输入的用户名/密码组合是否在LDAP服务器中有效 目前我使用以下代码: function CheckWinUserAccount(Username, Password, Domain : string) : boolean; var token: THandle; begin result:=False; if LogonUser(

编辑:我根据Andrei Galattyn的评论和提示修改了代码,提示我不应依赖无效时为零的令牌,但它仍然不适用于不属于域的PC


我想验证用户输入的用户名/密码组合是否在LDAP服务器中有效

目前我使用以下代码:

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;
如果在作为LDAP域一部分的PC上执行,而不是在仅将LDAP PC用作DNS但不属于该域一部分的PC上执行,则它可以完美地工作

我的数据:

  • 域名:graz.local
  • 用户名:LDTest
我尝试输入用户名为
LDTest
、作为
graz\LDTest
和作为
graz.local\LDTest

我还尝试将域指定为
graz
graz.local
ldap://graz.local

这些都不管用。有什么想法吗

顺便说一句:我不确定这是否可行(从非域PC访问域服务器),但使用LDAP管理员(Softerra)这是可行的。

正如Andrei Galatyn所指出的,使用LOGON32\u登录\u网络而不是 LOGON32\u LOGON\u调用“LogonUser”时进行交互。用户名 不应包括域名,域名可以是 NetBIOS域名(“graz”)或DNS域名(“graz.local”)

编辑:仅当客户端已建立到域的连接时,使用“LogonUser”才有效

下面是使用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.
{$APPTYPE控制台}
使用
SysUtils,
窗户,
JwaWinLDAP,
jcdce;
变量
sUsername、sDomain、sPassword、sDC:字符串;
LDAP:PLDAP;
SWAI:SEC_WINNT_AUTH_IDENTITY;
开始
如果(参数4),则
开始
WriteLn('WinLdapTest[username][domain][password][domain controller]”);
暂停(1);
结束;{if}
sUsername:=ParamStr(1);
sDomain:=ParamStr(2);
sPassword:=ParamStr(3);
sDC:=ParamStr(4);
LDAP:=LDAP_openW(PChar(sDC),LDAP_端口);
如果(已分配(LDAP)),则
尝试
SWAI.User:=PChar(sUserName);
SWAI.UserLength:=长度(sUserName);
SWAI.Domain:=PChar(sDomain);
SWAI.DomainLength:=长度(sDomain);
SWAI.Password:=PChar(sPassword);
SWAI.PasswordLength:=长度(sPassword);
SWAI.Flags:=SEC_WINNT_AUTH_IDENTITY_UNICODE;
如果(ldap、PChar(sDC)、PChar(@SWAI),
LDAP_AUTH_NTLM)=LDAP_成功)然后
WriteLN(''ldap_bind“success')
else WriteLN(''ldap_bind“failure');
最后
ldap_unbind(ldap);
结束{try/finally}
else WriteLn(“'ldap_open”失败”);
结束。
代码使用,并假设您使用的是Delphi 2009或更高版本(Unicode字符串)。要自动检索您可以调用的DC名称。

如Andrei Galattyn所述,请使用LOGON32\u LOGON\u网络,而不是 LOGON32\u LOGON\u调用“LogonUser”时进行交互。用户名 不应包括域名,域名可以是 NetBIOS域名(“graz”)或DNS域名(“graz.local”)

编辑:仅当客户端已建立到域的连接时,使用“LogonUser”才有效

下面是使用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.
{$APPTYPE控制台}
使用
SysUtils,
窗户,
JwaWinLDAP,
jcdce;
变量
sUsername、sDomain、sPassword、sDC:字符串;
LDAP:PLDAP;
SWAI:SEC_WINNT_AUTH_IDENTITY;
开始
如果(参数4),则
开始
WriteLn('WinLdapTest[username][domain][password][domain controller]”);
暂停(1);
结束;{if}
sUsername:=ParamStr(1);
sDomain:=ParamStr(2);
sPassword:=ParamStr(3);
sDC:=ParamStr(4);
LDAP:=LDAP_openW(PChar(sDC),LDAP_端口);
如果(已分配(LDAP)),则
尝试
SWAI.User:=PChar(sUserName);
SWAI.UserLength:=长度(sUserName);
SWAI.Domain:=PChar(sDomain);
SWAI.DomainLength:=长度(sDomain);
SWAI.Password:=PChar(sPassword);
SWAI.PasswordLength:=长度(sPassword);
SWAI.Flags:=SEC_WINNT_AUTH_IDENTITY_UNICODE;
如果(ldap、PChar(sDC)、PChar(@SWAI),
LDAP_AUTH_NTLM)=LDAP_成功)然后
WriteLN(''ldap_bind“success')
else WriteLN(''ldap_bind“failure');
最后
ldap_unbind(ldap);
结束{try/finally}
else WriteLn(“'ldap_open”失败”);
结束。

代码使用,并假设您使用的是Delphi 2009或更高版本(Unicode字符串)。自动检索您可以调用的DC名称。

AFAIK,当结合域+用户名时,它应该是反斜杠(`\`),而不是正斜杠(`/`)。尝试登录32\u LOGON\u NETWORK,而不是LOGON32\u LOGON\u INTERACTIVE(这似乎是此类任务的错误参数)。感谢您的评论,我在帖子中提到了这一点,但是代码仍然只在属于域的计算机上工作。好吧,当结合域+用户名时,它应该是反斜杠(`\``),而不是正斜杠(`/`)。尝试登录32\u LOGON\u NETWORK而不是LOGON32\u LOGON\u INTERACTIVE(这似乎是此类任务的错误参数)。感谢您的评论,我在文章中提到了这一点,但代码仍然只在属于域的计算机上工作。非常感谢您的代码,这是一种可能的方式,因为LogonUser不适用于我,即使我使用LOGON32\u LOGON\u网络。。DsGetDcName方法似乎需要大量参数。我尝试了NetGetAnyDCName(nil,domainname,buf),它返回“\\LDAPSERVER”。看来我需要去掉反斜杠了。将DC=“LDAPSERVER”添加到您的方法可以工作,但完全忽略sDomain。)这不重要