support LDAP search using multiple base DNs also with paged results, implements #395

This commit is contained in:
Arthur Schiwon 2013-01-04 23:54:42 +01:00
parent 81489ad860
commit ec1caa7d35

View file

@ -534,7 +534,7 @@ abstract class Access {
/**
* @brief executes an LDAP search
* @param $filter the LDAP filter for the search
* @param $base the LDAP subtree that shall be searched
* @param $base an array containing the LDAP subtree(s) that shall be searched
* @param $attr optional, when a certain attribute shall be filtered out
* @returns array with the search result
*
@ -559,7 +559,8 @@ abstract class Access {
$linkResources = array_pad(array(), count($base), $link_resource);
$sr = ldap_search($linkResources, $base, $filter, $attr);
if(!is_array($sr)) {
$error = ldap_errno($link_resource);
if(!is_array($sr) || $error > 0) {
\OCP\Util::writeLog('user_ldap', 'Error when searching: '.ldap_error($link_resource).' code '.ldap_errno($link_resource), \OCP\Util::ERROR);
\OCP\Util::writeLog('user_ldap', 'Attempt for Paging? '.print_r($pagedSearchOK, true), \OCP\Util::ERROR);
return array();
@ -570,9 +571,14 @@ abstract class Access {
}
if($pagedSearchOK) {
\OCP\Util::writeLog('user_ldap', 'Paged search successful', \OCP\Util::INFO);
ldap_control_paged_result_response($link_resource, $sr, $cookie);
\OCP\Util::writeLog('user_ldap', 'Set paged search cookie '.$cookie, \OCP\Util::INFO);
$this->setPagedResultCookie($filter, $limit, $offset, $cookie);
foreach($sr as $key => $res) {
$cookie = null;
if(ldap_control_paged_result_response($link_resource, $res, $cookie)) {
\OCP\Util::writeLog('user_ldap', 'Set paged search cookie', \OCP\Util::INFO);
$this->setPagedResultCookie($base[$key], $filter, $limit, $offset, $cookie);
}
}
//browsing through prior pages to get the cookie for the new one
if($skipHandling) {
return;
@ -582,8 +588,10 @@ abstract class Access {
$this->pagedSearchedSuccessful = true;
}
} else {
if(!is_null($limit)) {
\OCP\Util::writeLog('user_ldap', 'Paged search failed :(', \OCP\Util::INFO);
}
}
// if we're here, probably no connection resource is returned.
// to make ownCloud behave nicely, we simply give back an empty array.
@ -830,18 +838,19 @@ abstract class Access {
/**
* @brief get a cookie for the next LDAP paged search
* @param $base a string with the base DN for the search
* @param $filter the search filter to identify the correct search
* @param $limit the limit (or 'pageSize'), to identify the correct search well
* @param $offset the offset for the new search to identify the correct search really good
* @returns string containing the key or empty if none is cached
*/
private function getPagedResultCookie($filter, $limit, $offset) {
private function getPagedResultCookie($base, $filter, $limit, $offset) {
if($offset == 0) {
return '';
}
$offset -= $limit;
//we work with cache here
$cachekey = 'lc' . dechex(crc32($filter)) . '-' . $limit . '-' . $offset;
$cachekey = 'lc' . dechex(crc32($base)) . '-' . dechex(crc32($filter)) . '-' . $limit . '-' . $offset;
$cookie = $this->connection->getFromCache($cachekey);
if(is_null($cookie)) {
$cookie = '';
@ -851,15 +860,16 @@ abstract class Access {
/**
* @brief set a cookie for LDAP paged search run
* @param $base a string with the base DN for the search
* @param $filter the search filter to identify the correct search
* @param $limit the limit (or 'pageSize'), to identify the correct search well
* @param $offset the offset for the run search to identify the correct search really good
* @param $cookie string containing the cookie returned by ldap_control_paged_result_response
* @return void
*/
private function setPagedResultCookie($filter, $limit, $offset) {
private function setPagedResultCookie($base, $filter, $limit, $offset, $cookie) {
if(!empty($cookie)) {
$cachekey = 'lc' . dechex(crc32($filter)) . '-' . $limit . '-' . $offset;
$cachekey = 'lc' . dechex(crc32($base)) . '-' . dechex(crc32($filter)) . '-' .$limit . '-' . $offset;
$cookie = $this->connection->writeToCache($cachekey, $cookie);
}
}
@ -878,26 +888,28 @@ abstract class Access {
/**
* @brief prepares a paged search, if possible
* @param $filter the LDAP filter for the search
* @param $base the LDAP subtree that shall be searched
* @param $bases an array containing the LDAP subtree(s) that shall be searched
* @param $attr optional, when a certain attribute shall be filtered outside
* @param $limit
* @param $offset
*
*/
private function initPagedSearch($filter, $base, $attr, $limit, $offset) {
private function initPagedSearch($filter, $bases, $attr, $limit, $offset) {
$pagedSearchOK = false;
if($this->connection->hasPagedResultSupport && !is_null($limit)) {
$offset = intval($offset); //can be null
\OCP\Util::writeLog('user_ldap', 'initializing paged search for Filter'.$filter.' base '.$base.' attr '.print_r($attr, true). ' limit ' .$limit.' offset '.$offset, \OCP\Util::DEBUG);
\OCP\Util::writeLog('user_ldap', 'initializing paged search for Filter'.$filter.' base '.print_r($bases, true).' attr '.print_r($attr, true). ' limit ' .$limit.' offset '.$offset, \OCP\Util::INFO);
//get the cookie from the search for the previous search, required by LDAP
$cookie = $this->getPagedResultCookie($filter, $limit, $offset);
foreach($bases as $base) {
$cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset);
if(empty($cookie) && ($offset > 0)) {
//no cookie known, although the offset is not 0. Maybe cache run out. We need to start all over *sigh* (btw, Dear Reader, did you need LDAP paged searching was designed by MSFT?)
$reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit;
//a bit recursive, $offset of 0 is the exit
\OCP\Util::writeLog('user_ldap', 'Looking for cookie L/O '.$limit.'/'.$reOffset, \OCP\Util::INFO);
$this->search($filter, $base, $attr, $limit, $reOffset, true);
$cookie = $this->getPagedResultCookie($filter, $limit, $offset);
$cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset);
//still no cookie? obviously, the server does not like us. Let's skip paging efforts.
//TODO: remember this, probably does not change in the next request...
if(empty($cookie)) {
@ -909,10 +921,15 @@ abstract class Access {
\OCP\Util::writeLog('user_ldap', 'Cookie '.$cookie, \OCP\Util::INFO);
}
$pagedSearchOK = ldap_control_paged_result($this->connection->getConnectionResource(), $limit, false, $cookie);
if(!$pagedSearchOK) {
return false;
}
\OCP\Util::writeLog('user_ldap', 'Ready for a paged search', \OCP\Util::INFO);
} else {
\OCP\Util::writeLog('user_ldap', 'No paged search for us, Cpt., Limit '.$limit.' Offset '.$offset, \OCP\Util::INFO);
}
}
}
return $pagedSearchOK;