使用 pre-Windows 2000 域名获取 Active Directory 中的用户详细信息
Get user details in Active Directory using pre-Windows 2000 domain name
我不熟悉 LDAP,但我正在将我的应用程序用户与 Active Directory 集成。我想完成两件事:
- 验证用户名和密码。
- 获取用户详细信息。
不管正确与否,第一部分似乎有效:
$ldap = ldap_connect('ldap:foo.example.local ldap:bar.example.local');
if(!$ldap){
throw new RuntimeException();
}
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
$is_valid_user = ldap_bind($ldap, 'john.doe@example.local', 'passw0rd');
$is_valid_user = ldap_bind($ldap, 'example\john.doe', 'passw0rd');
不幸的是,如果我使用 Windows 2000 域名格式,第二部分只能检索结果,example.local
:
$results = ldap_search($ldap, 'DC=example,DC=local', '(sAMAccountName=john.doe)');
if(!$results){
return new RuntimeException();
}
ldap_sort($ldap, $results, 'sn');
$info = ldap_get_entries($ldap, $results);
ldap_close($ldap);
使用前Windows 2000 个域名(即仅使用 'DC=example'
作为 ldap_search
的第二个参数)ldap_get_entries()
函数 returns:
array (
'count' => 0,
)
我知道我们现在是 2019 年,但我希望我的 class 尽可能通用。
我可以做一个简单的更改来使我的代码与两种格式兼容吗?
因此,如果您在 Active Directory 用户和计算机中查看用户的 "Account" 选项卡,"User logon name" 对应于用户的 userPrincipalName
attribute. The "User logon name (pre-Windows 2000)" is a combination of the NetBIOS domain name (the "short" domain name) and the sAMAccountName
属性。
其中任何一个都可以用来登录。如您的代码所示,您只需要其中一行,因为它们都做同样的事情。
$is_valid_user = ldap_bind($ldap, 'john.doe@example.local', 'passw0rd');
$is_valid_user = ldap_bind($ldap, 'example\john.doe', 'passw0rd');
在第二个中,您实际上可以删除 example\
,只要用户 john.doe
与您连接的域相同。如果用户凭据来自不同的域(如果您在域之间有信任,这是可能的),您只需要提供域名。
指定userPrincipalName
时必须包含@example.local
,因为那实际上是属性的全部部分,@
之后的部分不一定需要匹配域名.
这个:
$results = ldap_search($ldap, 'DC=example,DC=local', '(sAMAccountName=john.doe)');
只有当您 "use the Windows 2000 domain name format" 时才有效,因为这就是您要搜索的全部内容。如果您想匹配任何一种格式,您也需要匹配 userPrincipalName
。您可以使用 OR 运算符 |
:
$results = ldap_search($ldap, 'DC=example,DC=local', '(|(sAMAccountName=john.doe)(userPrincipalName=john.doe))');
然后您的用户可以给您任何一种格式,您应该能够找到该帐户。
With pre-Windows 2000 domain names (i.e., using just 'DC=example'
as second argument for ldap_search
)
那将永远行不通,因为 ldap_search
中的第二个参数是 "base DN"。这是您要搜索的容器的 distinguishedName
。这通常是域的顶级。顶级域的 distinguishedName
将是 DC=example,DC=local'. But you could also put the DN of an OU there if you only want to look in that OU, like:
OU=Users,DC=example,DC=local'
我已经用 编写了一个概念证明(他提供了很好的信息,错误是我的):
<?php
$ldap = ldap_connect('ldap:foo.example.local ldap:bar.example.local');
if(!$ldap){
throw new RuntimeException();
}
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
if(!ldap_bind($ldap, 'example\lookup.user', 'passw0rd')){
throw new RuntimeException();
}
$result = ldap_read($ldap, '', '(objectClass=*)', ['defaultNamingContext']);
$info = ldap_get_entries($ldap, $result);
if(isset($info[0]['defaultnamingcontext'][0])){
$base_dn = $info[0]['defaultnamingcontext'][0]; // E.g. 'DC=example,DC=local'
}else{
throw new RuntimeException();
}
$results = ldap_search($ldap, $base_dn, '(|(sAMAccountName=john.doe)(userPrincipalName=john.doe))');
if(!$results){
return new RuntimeException();
}
$info = ldap_get_entries($ldap, $results);
var_dump($info);
ldap_close($ldap);
我不熟悉 LDAP,但我正在将我的应用程序用户与 Active Directory 集成。我想完成两件事:
- 验证用户名和密码。
- 获取用户详细信息。
不管正确与否,第一部分似乎有效:
$ldap = ldap_connect('ldap:foo.example.local ldap:bar.example.local');
if(!$ldap){
throw new RuntimeException();
}
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
$is_valid_user = ldap_bind($ldap, 'john.doe@example.local', 'passw0rd');
$is_valid_user = ldap_bind($ldap, 'example\john.doe', 'passw0rd');
不幸的是,如果我使用 Windows 2000 域名格式,第二部分只能检索结果,example.local
:
$results = ldap_search($ldap, 'DC=example,DC=local', '(sAMAccountName=john.doe)');
if(!$results){
return new RuntimeException();
}
ldap_sort($ldap, $results, 'sn');
$info = ldap_get_entries($ldap, $results);
ldap_close($ldap);
使用前Windows 2000 个域名(即仅使用 'DC=example'
作为 ldap_search
的第二个参数)ldap_get_entries()
函数 returns:
array (
'count' => 0,
)
我知道我们现在是 2019 年,但我希望我的 class 尽可能通用。
我可以做一个简单的更改来使我的代码与两种格式兼容吗?
因此,如果您在 Active Directory 用户和计算机中查看用户的 "Account" 选项卡,"User logon name" 对应于用户的 userPrincipalName
attribute. The "User logon name (pre-Windows 2000)" is a combination of the NetBIOS domain name (the "short" domain name) and the sAMAccountName
属性。
其中任何一个都可以用来登录。如您的代码所示,您只需要其中一行,因为它们都做同样的事情。
$is_valid_user = ldap_bind($ldap, 'john.doe@example.local', 'passw0rd');
$is_valid_user = ldap_bind($ldap, 'example\john.doe', 'passw0rd');
在第二个中,您实际上可以删除 example\
,只要用户 john.doe
与您连接的域相同。如果用户凭据来自不同的域(如果您在域之间有信任,这是可能的),您只需要提供域名。
指定userPrincipalName
时必须包含@example.local
,因为那实际上是属性的全部部分,@
之后的部分不一定需要匹配域名.
这个:
$results = ldap_search($ldap, 'DC=example,DC=local', '(sAMAccountName=john.doe)');
只有当您 "use the Windows 2000 domain name format" 时才有效,因为这就是您要搜索的全部内容。如果您想匹配任何一种格式,您也需要匹配 userPrincipalName
。您可以使用 OR 运算符 |
:
$results = ldap_search($ldap, 'DC=example,DC=local', '(|(sAMAccountName=john.doe)(userPrincipalName=john.doe))');
然后您的用户可以给您任何一种格式,您应该能够找到该帐户。
With pre-Windows 2000 domain names (i.e., using just
'DC=example'
as second argument forldap_search
)
那将永远行不通,因为 ldap_search
中的第二个参数是 "base DN"。这是您要搜索的容器的 distinguishedName
。这通常是域的顶级。顶级域的 distinguishedName
将是 DC=example,DC=local'. But you could also put the DN of an OU there if you only want to look in that OU, like:
OU=Users,DC=example,DC=local'
我已经用
<?php
$ldap = ldap_connect('ldap:foo.example.local ldap:bar.example.local');
if(!$ldap){
throw new RuntimeException();
}
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
if(!ldap_bind($ldap, 'example\lookup.user', 'passw0rd')){
throw new RuntimeException();
}
$result = ldap_read($ldap, '', '(objectClass=*)', ['defaultNamingContext']);
$info = ldap_get_entries($ldap, $result);
if(isset($info[0]['defaultnamingcontext'][0])){
$base_dn = $info[0]['defaultnamingcontext'][0]; // E.g. 'DC=example,DC=local'
}else{
throw new RuntimeException();
}
$results = ldap_search($ldap, $base_dn, '(|(sAMAccountName=john.doe)(userPrincipalName=john.doe))');
if(!$results){
return new RuntimeException();
}
$info = ldap_get_entries($ldap, $results);
var_dump($info);
ldap_close($ldap);