Env*_*rus 7 php size search ldap limit
我对查询 Microsoft 的 Active Directory 并遇到一些困难很陌生:
AD 的大小限制为每个请求 1000 个元素。我无法更改大小限制。PHP 似乎不支持分页(我使用的是 5.2 版,并且无法更新生产服务器。)
到目前为止,我遇到了两种可能的解决方案:
所以我的问题:
这里最好使用什么方法?
如果是第一个,我如何确保正确处理 objectSid?
还有其他可能吗?我错过了一些明显的东西吗?
更新:
-此相关问题提供了有关“简单分页结果”扩展为何不起作用的信息。
- Web 服务器在 Linux 服务器上运行,因此 COM 对象/adoDB 不是一个选项。
我能够使用ldap_control_paged_result绕过大小限制
ldap_control_paged_result用于通过发送分页控制来启用 LDAP 分页。下面的函数在我的例子中运行得很好。这适用于(PHP 5 >= 5.4.0,PHP 7)
function retrieves_users($conn)
{
$dn = 'ou=,dc=,dc=';
$filter = "(&(objectClass=user)(objectCategory=person)(sn=*))";
$justthese = array();
// enable pagination with a page size of 100.
$pageSize = 100;
$cookie = '';
do {
ldap_control_paged_result($conn, $pageSize, true, $cookie);
$result = ldap_search($conn, $dn, $filter, $justthese);
$entries = ldap_get_entries($conn, $result);
if(!empty($entries)){
for ($i = 0; $i < $entries["count"]; $i++) {
$data['usersLdap'][] = array(
'name' => $entries[$i]["cn"][0],
'username' => $entries[$i]["userprincipalname"][0]
);
}
}
ldap_control_paged_result_response($conn, $result, $cookie);
} while($cookie !== null && $cookie != '');
return $data;
}
Run Code Online (Sandbox Code Playgroud)
如果您现在已经成功更新服务器,那么上面的函数可以获取所有条目。我正在使用此功能来获取我们 AD 中的所有用户。
由于我没有找到任何干净的解决方案,因此我决定采用第一种方法:按 Object-Sids 过滤。
此解决方法有其局限性:
这个想法是首先读取所有可能的对象并挑选出相对 SID 最低的对象。相对 SID 是 SID 中的最后一个块:
S - 1-5-21-3188256696-111411151-3922474875-1158
我们假设这是仅返回“部分搜索结果”的搜索中的最低相对 SID。我们进一步假设大小限制为 1000。
然后程序执行以下操作: 搜索具有 SID 之间的所有对象
S - 1-5-21-3188256696-111411151-3922474875-1158
和
S- 1-5-21-3188256696-111411151-3922474875-0159
然后所有之间
S-1-5-21-3188256696-111411151-3922474875-1158和
S
- 1-5-21-3188256696-111411151-3922474875-2157
依此类推,直到其中一项搜索返回零个对象。
这种方法有几个问题,但足以满足我的目的。
代码:
$filter = '(objectClass=Group)';
$attributes = array('objectsid','cn'); //objectsid needs to be set
$result = array();
$maxPageSize = 1000;
$searchStep = $maxPageSize-1;
$adResult = @$adConn->search($filter,$attributes); //Supress warning for first query (because it exceeds the size limit)
//Read smallest RID from the resultset
$minGroupRID = '';
for($i=0;$i<$adResult['count'];$i++){
$groupRID = unpack('V',substr($adResult[$i]['objectsid'][0],24));
if($minGroupRID == '' || $minGroupRID>$groupRID[1]){
$minGroupRID = $groupRID[1];
}
}
$sidPrefix = substr($adResult[$i-1]['objectsid'][0],0,24); //Read last objectsid and cut off the prefix
$nextStepGroupRID = $minGroupRID;
do{ //Search for all objects with a lower objectsid than minGroupRID
$adResult = $adConn->search('(&'.$filter.'(objectsid<='.preg_replace('/../','\\\\$0',bin2hex($sidPrefix.pack('V',$nextStepGroupRID))).')(objectsid>='.preg_replace('/../','\\\\$0',bin2hex($sidPrefix.pack('V',$nextStepGroupRID-$searchStep))).'))', $attributes);
for($i=0;$i<$adResult['count'];$i++){
$RID = unpack('V',substr($adResult[$i]['objectsid'][0],24)); //Extract the relative SID from the SID
$RIDs[] = $RID[1];
$resultSet = array();
foreach($attributes as $attribute){
$resultSet[$attribute] = $adResult[$i][$attribute][0];
}
$result[$RID[1]] = $resultSet;
}
$nextStepGroupRID = $nextStepGroupRID-$searchStep;
}while($adResult['count']>1);
$nextStepGroupRID = $minGroupRID;
do{ //Search for all object with a higher objectsid than minGroupRID
$adResult = $adConn->search('(&'.$filter.'(objectsid>='.preg_replace('/../','\\\\$0',bin2hex($sidPrefix.pack('V',$nextStepGroupRID))).')(objectsid<='.preg_replace('/../','\\\\$0',bin2hex($sidPrefix.pack('V',$nextStepGroupRID+$searchStep))).'))', $attributes);
for($i=0;$i<$adResult['count'];$i++){
$RID = unpack('V',substr($adResult[$i]['objectsid'][0],24)); //Extract the relative SID from the SID
$RIDs[] = $RID[1];
$resultSet = array();
foreach($attributes as $attribute){
$resultSet[$attribute] = $adResult[$i][$attribute][0];
}
$result[$RID[1]] = $resultSet;
}
$nextStepGroupRID = $nextStepGroupRID+$searchStep;
}while($adResult['count']>1);
var_dump($result);
Run Code Online (Sandbox Code Playgroud)
$adConn->search 方法如下所示:
function search($filter, $attributes = false, $base_dn = null) {
if(!isset($base_dn)){
$base_dn = $this->baseDN;
}
$entries = false;
if (is_string($filter) && $this->bind) {
if (is_array($attributes)) {
$search = ldap_search($this->resource, $base_dn, $filter, $attributes);
} else {
$search = ldap_search($this->resource, $base_dn, $filter);
}
if ($search !== false) {
$entries = ldap_get_entries($this->resource, $search);
}
}
return $entries;
}
Run Code Online (Sandbox Code Playgroud)