Php 使用Windows 2000以前版本的域名在Active Directory中获取用户详细信息
我不熟悉LDAP,但我正在将我的应用程序用户与Active Directory集成。我想完成两件事:Php 使用Windows 2000以前版本的域名在Active Directory中获取用户详细信息,php,active-directory,ldap,Php,Active Directory,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_VERS
$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\u search
的第二个参数),ldap\u get\u entries()函数返回:
array (
'count' => 0,
)
我知道我们是在2019年,但我想让我的类尽可能通用
是否有一个简单的更改可以使我的代码与这两种格式兼容?因此,如果您在Active Directory用户和计算机中查看用户的“帐户”选项卡,“用户登录名”对应于该属性。“用户登录名(Windows 2000之前)”是NetBIOS域名(“短”域名)和用户属性的组合
其中任何一个都可以用于登录。如代码所示,您只需要这些行中的一行,因为它们都做相同的事情
$is\u valid\u user=ldap\u bind($ldap,'john。doe@example.local","passw0rd",;
$is_valid_user=ldap_bind($ldap,'example\\john.doe','passw0rd');
在第二个示例中,只要用户john.doe
与您连接的域相同,您就可以实际删除example\
。仅当用户凭据来自不同的域时,才需要提供域名(如果域之间存在信任,则可以这样做)
在指定userPrincipalName
时,必须包含@示例.local
,因为这实际上是属性的全部部分,@
后面的部分不一定需要与域名匹配
这:
$results=ldap_search($ldap,'DC=example,DC=local','(sAMAccountName=john.doe)');
只有在“使用Windows 2000域名格式”时才有效,因为这就是您要搜索的全部内容。如果要匹配任何一种格式,还需要匹配userPrincipalName
。您可以使用OR运算符|
:
$results=ldap_search($ldap,'DC=example,DC=local','(|(sAMAccountName=john.doe)(userPrincipalName=john.doe)));
然后你的用户可以给你任何一种格式,你应该能够找到帐户
使用Windows 2000之前的域名(即,仅使用'DC=example'
作为ldap\u搜索的第二个参数)
这永远不会起作用,因为ldap\u search
中的第二个参数是“基本DN”。这是要搜索的容器的区分名称。这通常是域的顶级。域顶级的discriminatedname
将是DC=example,DC=local'。但是,如果您只想查看某个OU,也可以将该OU的DN放在那里,例如:
OU=Users,DC=example,DC=local'我已经编写了一个概念证明(他的信息很棒,我的错误):
如果我问了一些愚蠢的问题,很抱歉,但这是我的LDAP速成课程。您的意思是我绝对需要知道完整的Windows 2000域名(示例.local
)才能搜索用户,因为NetBIOS名称(示例
)不包含足够的信息来标识基本DN?大多数支持LDAP的应用程序都要求基本DN,因为这允许您将范围限制为OU,你可能会想要的。但是,您可以通过查询的defaultNamingContext
属性找到域的基本DN。这里有一个如何在PHP中实现这一点的示例。该示例读取supportedcontrol
属性,因此只需将其替换为defaultNamingContext
。我认为(|(sAMAccountName=john.doe)(userPrincipalName=john.doe))中存在错误。
。至少对于我的Windows域控制器,字段userPrincipalName
的值为john。doe@example.com
,而不是john.doe
@DanielMarschall在那个特定的案例中你是对的。但这是指使用用户的输入并对sAMAccountName
或userPrincipalName
进行匹配。因此,如果用户给你john.doe
作为他们的用户名,那么是的,搜索查询将与之完全相同,并且它将与sAMAccountName
匹配。但是如果用户提供了john。doe@example.com
,则查询将是(|)(sAMAccountName=john)。doe@example.com)(userPrincipalName=john。doe@example.com))
并且它最终会与userPrincipalName
匹配。因此在实际使用中,john.doe
不会被硬编码,我认为(|(sAMAccountName=john.doe)(userPrincipalName=john.doe))中有一个错误。至少对于我的Windows域控制器,字段userPrincipalName
的值为john。doe@example.com
,而不是john.doe
@DanielMarschall当用户没有提供完全限定的用户名时,可以使用一个默认的(或通常只有一个)域。但这只是一个概念的快速证明,我并没有真正的多域设置来测试。
<?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);