take out support for parallel search

* it is undocumented in PHP documentation
* since it does not work with paged search, we do not take advantage of it
  as of c868892d2d

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
This commit is contained in:
Arthur Schiwon 2019-02-08 01:41:10 +01:00
parent 21671d5cb5
commit f5cd138768
No known key found for this signature in database
GPG Key ID: 7424F1874854DF23
11 changed files with 379 additions and 360 deletions

View File

@ -97,6 +97,8 @@ class Access extends LDAPUtility {
private $config; private $config;
/** @var IUserManager */ /** @var IUserManager */
private $ncUserManager; private $ncUserManager;
/** @var ILogger */
private $logger;
public function __construct( public function __construct(
Connection $connection, Connection $connection,
@ -113,6 +115,7 @@ class Access extends LDAPUtility {
$this->helper = $helper; $this->helper = $helper;
$this->config = $config; $this->config = $config;
$this->ncUserManager = $ncUserManager; $this->ncUserManager = $ncUserManager;
$this->logger = \OC::$server->getLogger();
} }
/** /**
@ -258,27 +261,18 @@ class Access extends LDAPUtility {
* @param string $attribute * @param string $attribute
* @param string $filter * @param string $filter
* @param int $maxResults * @param int $maxResults
* @return array|bool false if there was any error, true if an exists check * @return array|bool false if there was any error
* was performed and the requested DN found, array with the
* returned data on a successful usual operation
* @throws ServerNotAvailableException * @throws ServerNotAvailableException
*/ */
public function executeRead($cr, $dn, $attribute, $filter, $maxResults) { public function executeRead($cr, string $dn, string $attribute, string $filter, int $maxResults) {
$this->initPagedSearch($filter, array($dn), array($attribute), $maxResults, 0); $this->initPagedSearch($filter, $dn, [$attribute], $maxResults, 0);
$dn = $this->helper->DNasBaseParameter($dn); $dn = $this->helper->DNasBaseParameter($dn);
$rr = @$this->invokeLDAPMethod('read', $cr, $dn, $filter, array($attribute)); $rr = @$this->invokeLDAPMethod('read', $cr, $dn, $filter, [$attribute]);
if (!$this->ldap->isResource($rr)) { if (!$this->ldap->isResource($rr)) {
if ($attribute !== '') { $this->logger->debug('readAttribute failed for DN {dn}', ['app' => 'user_ldap', 'dn' => $dn]);
//do not throw this message on userExists check, irritates
\OCP\Util::writeLog('user_ldap', 'readAttribute failed for DN ' . $dn, ILogger::DEBUG);
}
//in case an error occurs , e.g. object does not exist
return false; return false;
} }
if ($attribute === '' && ($filter === 'objectclass=*' || $this->invokeLDAPMethod('countEntries', $cr, $rr) === 1)) {
\OCP\Util::writeLog('user_ldap', 'readAttribute: ' . $dn . ' found', ILogger::DEBUG);
return true;
}
$er = $this->invokeLDAPMethod('firstEntry', $cr, $rr); $er = $this->invokeLDAPMethod('firstEntry', $cr, $rr);
if (!$this->ldap->isResource($er)) { if (!$this->ldap->isResource($er)) {
//did not match the filter, return false //did not match the filter, return false
@ -291,6 +285,25 @@ class Access extends LDAPUtility {
return $result; return $result;
} }
/**
* checks whether a record identified by a DN is present on LDAP
*
* @throws ServerNotAvailableException
*/
public function isRecordOnLDAP(string $dn, string $filter = 'objectclass=*'): bool {
$this->abandonPagedSearch();
$attribute = ['']; // best suited for existence checks
$this->initPagedSearch($filter, $dn, $attribute, 1, 0);
$dn = $this->helper->DNasBaseParameter($dn);
$rr = @$this->invokeLDAPMethod('read', $this->connection->getConnectionResource(), $dn, $filter, $attribute);
$isAvailable = $this->ldap->isResource($rr);
$this->logger->debug(
'existence check for DN {dn} resulted in {result}',
['app' => 'user_ldap', 'dn' => $dn, 'result' => $isAvailable]
);
return $isAvailable;
}
/** /**
* Normalizes a result grom getAttributes(), i.e. handles DNs and binary * Normalizes a result grom getAttributes(), i.e. handles DNs and binary
* data if present. * data if present.
@ -474,11 +487,9 @@ class Access extends LDAPUtility {
* filter by doing read operations against the group entries. Returns an * filter by doing read operations against the group entries. Returns an
* array of DNs that match the filter. * array of DNs that match the filter.
* *
* @param string[] $groupDNs
* @return string[]
* @throws ServerNotAvailableException * @throws ServerNotAvailableException
*/ */
public function groupsMatchFilter($groupDNs) { public function groupsMatchFilter(array $groupDNs): array {
$validGroupDNs = []; $validGroupDNs = [];
foreach($groupDNs as $dn) { foreach($groupDNs as $dn) {
$cacheKey = 'groupsMatchFilter-'.$dn; $cacheKey = 'groupsMatchFilter-'.$dn;
@ -497,8 +508,7 @@ class Access extends LDAPUtility {
continue; continue;
} }
$result = $this->readAttribute($dn, '', $this->connection->ldapGroupFilter); if($this->isRecordOnLDAP($dn, $this->connection->ldapGroupFilter)) {
if(is_array($result)) {
$this->connection->writeToCache($cacheKey, true); $this->connection->writeToCache($cacheKey, true);
$validGroupDNs[] = $dn; $validGroupDNs[] = $dn;
} else { } else {
@ -966,18 +976,18 @@ class Access extends LDAPUtility {
/** /**
* executes an LDAP search, optimized for Users * executes an LDAP search, optimized for Users
*
* @param string $filter the LDAP filter for the search * @param string $filter the LDAP filter for the search
* @param string|string[] $attr optional, when a certain attribute shall be filtered out * @param string|string[] $attr optional, when a certain attribute shall be filtered out
* @param integer $limit * @param integer $limit
* @param integer $offset * @param integer $offset
* @return array with the search result * @return array with the search result
* * @throws ServerNotAvailableException
* Executes an LDAP search
*/ */
public function searchUsers($filter, $attr = null, $limit = null, $offset = null) { public function searchUsers(string $filter, $attr = null, int $limit = null, int $offset = null): array {
$result = []; $result = [];
foreach($this->connection->ldapBaseUsers as $base) { foreach($this->connection->ldapBaseUsers as $base) {
$result = array_merge($result, $this->search($filter, [$base], $attr, $limit, $offset)); $result = array_merge($result, $this->search($filter, $base, $attr, $limit, $offset));
} }
return $result; return $result;
} }
@ -987,12 +997,13 @@ class Access extends LDAPUtility {
* @param string|string[] $attr * @param string|string[] $attr
* @param int $limit * @param int $limit
* @param int $offset * @param int $offset
* @return false|int * @return bool|int
* @throws ServerNotAvailableException
*/ */
public function countUsers($filter, $attr = array('dn'), $limit = null, $offset = null) { public function countUsers(string $filter, $attr = ['dn'], int $limit = null, int $offset = null) {
$result = false; $result = false;
foreach($this->connection->ldapBaseUsers as $base) { foreach($this->connection->ldapBaseUsers as $base) {
$count = $this->count($filter, [$base], $attr, $limit, $offset); $count = $this->count($filter, $base, $attr, $limit, $offset);
$result = is_int($count) ? (int)$result + $count : $result; $result = is_int($count) ? (int)$result + $count : $result;
} }
return $result; return $result;
@ -1000,6 +1011,7 @@ class Access extends LDAPUtility {
/** /**
* executes an LDAP search, optimized for Groups * executes an LDAP search, optimized for Groups
*
* @param string $filter the LDAP filter for the search * @param string $filter the LDAP filter for the search
* @param string|string[] $attr optional, when a certain attribute shall be filtered out * @param string|string[] $attr optional, when a certain attribute shall be filtered out
* @param integer $limit * @param integer $limit
@ -1007,27 +1019,26 @@ class Access extends LDAPUtility {
* @return array with the search result * @return array with the search result
* *
* Executes an LDAP search * Executes an LDAP search
* @throws ServerNotAvailableException
*/ */
public function searchGroups($filter, $attr = null, $limit = null, $offset = null) { public function searchGroups(string $filter, $attr = null, int $limit = null, int $offset = null): array {
$result = []; $result = [];
foreach($this->connection->ldapBaseGroups as $base) { foreach($this->connection->ldapBaseGroups as $base) {
$result = array_merge($result, $this->search($filter, [$base], $attr, $limit, $offset)); $result = array_merge($result, $this->search($filter, $base, $attr, $limit, $offset));
} }
return $result; return $result;
} }
/** /**
* returns the number of available groups * returns the number of available groups
* @param string $filter the LDAP search filter *
* @param string[] $attr optional
* @param int|null $limit
* @param int|null $offset
* @return int|bool * @return int|bool
* @throws ServerNotAvailableException
*/ */
public function countGroups($filter, $attr = array('dn'), $limit = null, $offset = null) { public function countGroups(string $filter, array $attr = ['dn'], int $limit = null, int $offset = null) {
$result = false; $result = false;
foreach($this->connection->ldapBaseGroups as $base) { foreach($this->connection->ldapBaseGroups as $base) {
$count = $this->count($filter, [$base], $attr, $limit, $offset); $count = $this->count($filter, $base, $attr, $limit, $offset);
$result = is_int($count) ? (int)$result + $count : $result; $result = is_int($count) ? (int)$result + $count : $result;
} }
return $result; return $result;
@ -1036,14 +1047,14 @@ class Access extends LDAPUtility {
/** /**
* returns the number of available objects on the base DN * returns the number of available objects on the base DN
* *
* @param int|null $limit
* @param int|null $offset
* @return int|bool * @return int|bool
* @throws ServerNotAvailableException
*/ */
public function countObjects($limit = null, $offset = null) { public function countObjects(int $limit = null, int $offset = null) {
$result = false; $result = false;
foreach($this->connection->ldapBase as $base) { foreach($this->connection->ldapBase as $base) {
$count = $this->count('objectclass=*', [$base], ['dn'], $limit, $offset); /** @noinspection SpellCheckingInspection */
$count = $this->count('objectclass=*', $base, ['dn'], $limit, $offset);
$result = is_int($count) ? (int)$result + $count : $result; $result = is_int($count) ? (int)$result + $count : $result;
} }
return $result; return $result;
@ -1073,27 +1084,26 @@ class Access extends LDAPUtility {
if ($command == 'controlPagedResultResponse') { if ($command == 'controlPagedResultResponse') {
throw new \InvalidArgumentException('Invoker does not support controlPagedResultResponse, call LDAP Wrapper directly instead.'); throw new \InvalidArgumentException('Invoker does not support controlPagedResultResponse, call LDAP Wrapper directly instead.');
} else { } else {
return call_user_func_array(array($this->ldap, $command), $arguments); return call_user_func_array([$this->ldap, $command], $arguments);
} }
}; };
try { try {
$ret = $doMethod(); $ret = $doMethod();
} catch (ServerNotAvailableException $e) { } /** @noinspection PhpRedundantCatchClauseInspection */
catch (ServerNotAvailableException $e) {
/* Server connection lost, attempt to reestablish it /* Server connection lost, attempt to reestablish it
* Maybe implement exponential backoff? * Maybe implement exponential backoff?
* This was enough to get solr indexer working which has large delays between LDAP fetches. * This was enough to get solr indexer working which has large delays between LDAP fetches.
*/ */
\OCP\Util::writeLog('user_ldap', "Connection lost on $command, attempting to reestablish.", ILogger::DEBUG); $this->logger->debug('Connection lost on {command}, , attempting to reestablish', ['app' => 'user_ldap', 'command' => $command]);
$this->connection->resetConnectionResource(); $this->connection->resetConnectionResource();
$cr = $this->connection->getConnectionResource(); $cr = $this->connection->getConnectionResource();
if(!$this->ldap->isResource($cr)) { if(!$this->ldap->isResource($cr)) {
// Seems like we didn't find any resource. $this->logger->debug('Could not {command}, because resource is missing', ['app' => 'user_ldap', 'command' => $command]);
\OCP\Util::writeLog('user_ldap', "Could not $command, because resource is missing.", ILogger::DEBUG);
throw $e; throw $e;
} }
$arguments[0] = array_pad([], count($arguments[0]), $cr);
$ret = $doMethod(); $ret = $doMethod();
} }
return $ret; return $ret;
@ -1102,8 +1112,8 @@ class Access extends LDAPUtility {
/** /**
* retrieved. Results will according to the order in the array. * retrieved. Results will according to the order in the array.
* *
* @param $filter * @param string $filter
* @param $base * @param string $base
* @param string[]|string|null $attr * @param string[]|string|null $attr
* @param int $limit optional, maximum results to be counted * @param int $limit optional, maximum results to be counted
* @param int $offset optional, a starting point * @param int $offset optional, a starting point
@ -1111,9 +1121,9 @@ class Access extends LDAPUtility {
* second | false if not successful * second | false if not successful
* @throws ServerNotAvailableException * @throws ServerNotAvailableException
*/ */
private function executeSearch($filter, $base, &$attr = null, $limit = null, $offset = null) { private function executeSearch(string $filter, string $base, &$attr = null, int $limit = null, int $offset = null) {
if(!is_null($attr) && !is_array($attr)) { if(!is_null($attr) && !is_array($attr)) {
$attr = array(mb_strtolower($attr, 'UTF-8')); $attr = [mb_strtolower($attr, 'UTF-8')];
} }
// See if we have a resource, in case not cancel with message // See if we have a resource, in case not cancel with message
@ -1121,30 +1131,30 @@ class Access extends LDAPUtility {
if(!$this->ldap->isResource($cr)) { if(!$this->ldap->isResource($cr)) {
// Seems like we didn't find any resource. // Seems like we didn't find any resource.
// Return an empty array just like before. // Return an empty array just like before.
\OCP\Util::writeLog('user_ldap', 'Could not search, because resource is missing.', ILogger::DEBUG); $this->logger->debug('Could not search, because resource is missing', ['app' => 'user_ldap']);
return false; return false;
} }
//check whether paged search should be attempted //check whether paged search should be attempted
$pagedSearchOK = $this->initPagedSearch($filter, $base, $attr, (int)$limit, $offset); $pagedSearchOK = $this->initPagedSearch($filter, $base, $attr, (int)$limit, $offset);
$linkResources = array_pad(array(), count($base), $cr); $sr = $this->invokeLDAPMethod('search', $cr, $base, $filter, $attr);
$sr = $this->invokeLDAPMethod('search', $linkResources, $base, $filter, $attr);
// cannot use $cr anymore, might have changed in the previous call! // cannot use $cr anymore, might have changed in the previous call!
$error = $this->ldap->errno($this->connection->getConnectionResource()); $error = $this->ldap->errno($this->connection->getConnectionResource());
if(!is_array($sr) || $error !== 0) { if(!$this->ldap->isResource($sr) || $error !== 0) {
\OCP\Util::writeLog('user_ldap', 'Attempt for Paging? '.print_r($pagedSearchOK, true), ILogger::ERROR); $this->logger->debug('Attempt for Paging? {status}', ['app' => 'user_ldap', 'status' => $pagedSearchOK]);
return false; return false;
} }
return array($sr, $pagedSearchOK); return [$sr, $pagedSearchOK];
} }
/** /**
* processes an LDAP paged search operation * processes an LDAP paged search operation
* @param array $sr the array containing the LDAP search resources *
* @param resource $sr the array containing the LDAP search resources
* @param string $filter the LDAP filter for the search * @param string $filter the LDAP filter for the search
* @param array $base an array containing the LDAP subtree(s) that shall be searched * @param string $base an array containing the LDAP subtree(s) that shall be searched
* @param int $iFoundItems number of results in the single search operation * @param int $iFoundItems number of results in the single search operation
* @param int $limit maximum results to be counted * @param int $limit maximum results to be counted
* @param int $offset a starting point * @param int $offset a starting point
@ -1152,15 +1162,14 @@ class Access extends LDAPUtility {
* @param bool $skipHandling required for paged search when cookies to * @param bool $skipHandling required for paged search when cookies to
* prior results need to be gained * prior results need to be gained
* @return bool cookie validity, true if we have more pages, false otherwise. * @return bool cookie validity, true if we have more pages, false otherwise.
* @throws ServerNotAvailableException
*/ */
private function processPagedSearchStatus($sr, $filter, $base, $iFoundItems, $limit, $offset, $pagedSearchOK, $skipHandling) { private function processPagedSearchStatus($sr, string $filter, string $base, int $iFoundItems, int $limit, $offset, bool $pagedSearchOK, bool $skipHandling): bool {
$cookie = null; $cookie = null;
if($pagedSearchOK) { if($pagedSearchOK) {
$cr = $this->connection->getConnectionResource(); $cr = $this->connection->getConnectionResource();
foreach($sr as $key => $res) { if($this->ldap->controlPagedResultResponse($cr, $sr, $cookie)) {
if($this->ldap->controlPagedResultResponse($cr, $res, $cookie)) { $this->setPagedResultCookie($base, $filter, $limit, $offset, $cookie);
$this->setPagedResultCookie($base[$key], $filter, $limit, $offset, $cookie);
}
} }
//browsing through prior pages to get the cookie for the new one //browsing through prior pages to get the cookie for the new one
@ -1175,10 +1184,7 @@ class Access extends LDAPUtility {
} }
} else { } else {
if(!is_null($limit) && (int)$this->connection->ldapPagingSize !== 0) { if(!is_null($limit) && (int)$this->connection->ldapPagingSize !== 0) {
\OC::$server->getLogger()->debug( $this->logger->debug('Paged search was not available', ['app' => 'user_ldap']);
'Paged search was not available',
[ 'app' => 'user_ldap' ]
);
} }
} }
/* ++ Fixing RHDS searches with pages with zero results ++ /* ++ Fixing RHDS searches with pages with zero results ++
@ -1203,8 +1209,8 @@ class Access extends LDAPUtility {
* @return int|false Integer or false if the search could not be initialized * @return int|false Integer or false if the search could not be initialized
* @throws ServerNotAvailableException * @throws ServerNotAvailableException
*/ */
private function count($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) { private function count(string $filter, string $base, $attr = null, int $limit = null, int $offset = null, bool $skipHandling = false) {
\OCP\Util::writeLog('user_ldap', 'Count filter: '.print_r($filter, true), ILogger::DEBUG); $this->logger->debug('Count filter: {filter}', ['app' => 'user_ldap', 'filter' => $filter]);
$limitPerPage = (int)$this->connection->ldapPagingSize; $limitPerPage = (int)$this->connection->ldapPagingSize;
if(!is_null($limit) && $limit < $limitPerPage && $limit > 0) { if(!is_null($limit) && $limit < $limitPerPage && $limit > 0) {
@ -1268,7 +1274,7 @@ class Access extends LDAPUtility {
* @return array with the search result * @return array with the search result
* @throws ServerNotAvailableException * @throws ServerNotAvailableException
*/ */
public function search($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) { public function search(string $filter, string $base, $attr = null, int $limit = null, int $offset = null, bool $skipHandling = false): array {
$limitPerPage = (int)$this->connection->ldapPagingSize; $limitPerPage = (int)$this->connection->ldapPagingSize;
if(!is_null($limit) && $limit < $limitPerPage && $limit > 0) { if(!is_null($limit) && $limit < $limitPerPage && $limit > 0) {
$limitPerPage = $limit; $limitPerPage = $limit;
@ -1281,7 +1287,7 @@ class Access extends LDAPUtility {
* $findings['count'] < $limit * $findings['count'] < $limit
*/ */
$findings = []; $findings = [];
$savedoffset = $offset; $savedOffset = $offset;
do { do {
$search = $this->executeSearch($filter, $base, $attr, $limitPerPage, $offset); $search = $this->executeSearch($filter, $base, $attr, $limitPerPage, $offset);
if($search === false) { if($search === false) {
@ -1297,7 +1303,7 @@ class Access extends LDAPUtility {
$this->processPagedSearchStatus($sr, $filter, $base, 1, $limitPerPage, $this->processPagedSearchStatus($sr, $filter, $base, 1, $limitPerPage,
$offset, $pagedSearchOK, $offset, $pagedSearchOK,
$skipHandling); $skipHandling);
return array(); return [];
} }
$iFoundItems = 0; $iFoundItems = 0;
@ -1312,13 +1318,13 @@ class Access extends LDAPUtility {
$skipHandling); $skipHandling);
$offset += $limitPerPage; $offset += $limitPerPage;
} while ($continue && $pagedSearchOK && ($limit === null || count($findings) < $limit)); } while ($continue && $pagedSearchOK && ($limit === null || count($findings) < $limit));
// reseting offset // resetting offset
$offset = $savedoffset; $offset = $savedOffset;
// if we're here, probably no connection resource is returned. // if we're here, probably no connection resource is returned.
// to make Nextcloud behave nicely, we simply give back an empty array. // to make Nextcloud behave nicely, we simply give back an empty array.
if(is_null($findings)) { if(is_null($findings)) {
return array(); return [];
} }
if(!is_null($attr)) { if(!is_null($attr)) {
@ -1951,14 +1957,8 @@ class Access extends LDAPUtility {
/** /**
* set a cookie for LDAP paged search run * set a cookie for LDAP paged search run
* @param string $base a string with the base DN for the search
* @param string $filter the search filter to identify the correct search
* @param int $limit the limit (or 'pageSize'), to identify the correct search well
* @param int $offset the offset for the run search to identify the correct search really good
* @param string $cookie string containing the cookie returned by ldap_control_paged_result_response
* @return void
*/ */
private function setPagedResultCookie($base, $filter, $limit, $offset, $cookie) { private function setPagedResultCookie(string $base, string $filter, int $limit, int $offset, string $cookie): void {
// allow '0' for 389ds // allow '0' for 389ds
if(!empty($cookie) || $cookie === '0') { if(!empty($cookie) || $cookie === '0') {
$cacheKey = 'lc' . crc32($base) . '-' . crc32($filter) . '-' . (int)$limit . '-' . (int)$offset; $cacheKey = 'lc' . crc32($base) . '-' . crc32($filter) . '-' . (int)$limit . '-' . (int)$offset;
@ -1979,31 +1979,32 @@ class Access extends LDAPUtility {
/** /**
* Prepares a paged search, if possible * Prepares a paged search, if possible
* @param string $filter the LDAP filter for the search *
* @param string[] $bases an array containing the LDAP subtree(s) that shall be searched * @throws ServerNotAvailableException
* @param string[] $attr optional, when a certain attribute shall be filtered outside
* @param int $limit
* @param int $offset
* @return bool|true
*/ */
private function initPagedSearch($filter, $bases, $attr, $limit, $offset) { private function initPagedSearch(string $filter, string $base, array $attr = null, int $limit = null, int $offset = null): bool {
$pagedSearchOK = false; $pagedSearchOK = false;
if ($limit !== 0) { if ($limit !== 0) {
$offset = (int)$offset; //can be null $offset = (int)$offset; //can be null
\OCP\Util::writeLog('user_ldap', $this->logger->debug(
'initializing paged search for Filter '.$filter.' base '.print_r($bases, true) 'initializing paged search for Filter {filter} base {base} attr {attr} limit {limit} offset {offset}',
.' attr '.print_r($attr, true). ' limit ' .$limit.' offset '.$offset, [
ILogger::DEBUG); 'app' => 'user_ldap',
'filter' => $filter,
'base' => $base,
'attr' => $attr,
'limit' => $limit,
'offset' => $offset,
]
);
//get the cookie from the search for the previous search, required by LDAP //get the cookie from the search for the previous search, required by LDAP
foreach($bases as $base) {
$cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset); $cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset);
if(empty($cookie) && $cookie !== "0" && ($offset > 0)) { if(empty($cookie) && $cookie !== "0" && ($offset > 0)) {
// no cookie known from a potential previous search. We need // no cookie known from a potential previous search. We need
// to start from 0 to come to the desired page. cookie value // to start from 0 to come to the desired page. cookie value
// of '0' is valid, because 389ds // of '0' is valid, because 389ds
$reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit; $reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit;
$this->search($filter, array($base), $attr, $limit, $reOffset, true); $this->search($filter, $base, $attr, $limit, $reOffset, true);
$cookie = $this->getPagedResultCookie($base, $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. //still no cookie? obviously, the server does not like us. Let's skip paging efforts.
// '0' is valid, because 389ds // '0' is valid, because 389ds
@ -2021,13 +2022,12 @@ class Access extends LDAPUtility {
if(!$pagedSearchOK) { if(!$pagedSearchOK) {
return false; return false;
} }
\OCP\Util::writeLog('user_ldap', 'Ready for a paged search', ILogger::DEBUG); $this->logger->debug('Ready for a paged search', ['app' => 'user_ldap']);
} else { } else {
$e = new \Exception('No paged search possible, Limit '.$limit.' Offset '.$offset); $e = new \Exception('No paged search possible, Limit '.$limit.' Offset '.$offset);
\OC::$server->getLogger()->logException($e, ['level' => ILogger::DEBUG]); $this->logger->logException($e, ['app' => 'user_ldap', 'level' => ILogger::DEBUG]);
} }
}
/* ++ Fixing RHDS searches with pages with zero results ++ /* ++ Fixing RHDS searches with pages with zero results ++
* We coudn't get paged searches working with our RHDS for login ($limit = 0), * We coudn't get paged searches working with our RHDS for login ($limit = 0),
* due to pages with zero results. * due to pages with zero results.

View File

@ -36,6 +36,11 @@ namespace OCA\User_LDAP;
/** /**
* @property int ldapPagingSize holds an integer * @property int ldapPagingSize holds an integer
* @property string ldapUserAvatarRule * @property string ldapUserAvatarRule
* @property string ldapEmailAttribute
* @property string ldapUserDisplayName
* @property string ldapUserFilter
* @property string ldapGroupFilter
* @property string[] ldapBase
*/ */
class Configuration { class Configuration {
const AVATAR_PREFIX_DEFAULT = 'default'; const AVATAR_PREFIX_DEFAULT = 'default';

View File

@ -45,12 +45,18 @@ use OCP\ILogger;
* *
* @property string ldapHost * @property string ldapHost
* @property string ldapPort holds the port number * @property string ldapPort holds the port number
* @property string ldapLoginFilter
* @property string ldapUserFilter * @property string ldapUserFilter
* @property string ldapUserDisplayName * @property string ldapUserDisplayName
* @property string ldapUserDisplayName2 * @property string ldapUserDisplayName2
* @property string ldapUserAvatarRule * @property string ldapUserAvatarRule
* @property string ldapGroupFilter
* @property string ldapGidNumber
* @property string ldapDynamicGroupMemberURL
* @property boolean turnOnPasswordChange * @property boolean turnOnPasswordChange
* @property string[] ldapBase
* @property string[] ldapBaseUsers * @property string[] ldapBaseUsers
* @property string[] ldapBaseGroups
* @property int|null ldapPagingSize holds an integer * @property int|null ldapPagingSize holds an integer
* @property bool|mixed|void ldapGroupMemberAssocAttr * @property bool|mixed|void ldapGroupMemberAssocAttr
* @property string ldapUuidUserAttribute * @property string ldapUuidUserAttribute
@ -60,6 +66,7 @@ use OCP\ILogger;
* @property string ldapQuotaAttribute * @property string ldapQuotaAttribute
* @property string ldapQuotaDefault * @property string ldapQuotaDefault
* @property string ldapEmailAttribute * @property string ldapEmailAttribute
* @property string ldapDefaultPPolicyDN
*/ */
class Connection extends LDAPUtility { class Connection extends LDAPUtility {
private $ldapConnectionRes = null; private $ldapConnectionRes = null;

View File

@ -45,7 +45,7 @@ use OC\Cache\CappedMemoryCache;
use OCP\GroupInterface; use OCP\GroupInterface;
use OCP\ILogger; use OCP\ILogger;
class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLDAP { class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP {
protected $enabled = false; protected $enabled = false;
/** /**
@ -165,20 +165,18 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
} }
/** /**
* @param string $dnGroup
* @return array
*
* For a group that has user membership defined by an LDAP search url attribute returns the users * For a group that has user membership defined by an LDAP search url attribute returns the users
* that match the search url otherwise returns an empty array. * that match the search url otherwise returns an empty array.
* @throws \OC\ServerNotAvailableException
*/ */
public function getDynamicGroupMembers($dnGroup) { public function getDynamicGroupMembers(string $dnGroup): array {
$dynamicGroupMemberURL = strtolower($this->access->connection->ldapDynamicGroupMemberURL); $dynamicGroupMemberURL = strtolower($this->access->connection->ldapDynamicGroupMemberURL);
if (empty($dynamicGroupMemberURL)) { if (empty($dynamicGroupMemberURL)) {
return array(); return [];
} }
$dynamicMembers = array(); $dynamicMembers = [];
$memberURLs = $this->access->readAttribute( $memberURLs = $this->access->readAttribute(
$dnGroup, $dnGroup,
$dynamicGroupMemberURL, $dynamicGroupMemberURL,
@ -186,6 +184,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
); );
if ($memberURLs !== false) { if ($memberURLs !== false) {
// this group has the 'memberURL' attribute so this is a dynamic group // this group has the 'memberURL' attribute so this is a dynamic group
/** @noinspection SpellCheckingInspection */
// example 1: ldap:///cn=users,cn=accounts,dc=dcsubbase,dc=dcbase??one?(o=HeadOffice) // example 1: ldap:///cn=users,cn=accounts,dc=dcsubbase,dc=dcbase??one?(o=HeadOffice)
// example 2: ldap:///cn=users,cn=accounts,dc=dcsubbase,dc=dcbase??one?(&(o=HeadOffice)(uidNumber>=500)) // example 2: ldap:///cn=users,cn=accounts,dc=dcsubbase,dc=dcbase??one?(&(o=HeadOffice)(uidNumber>=500))
$pos = strpos($memberURLs[0], '('); $pos = strpos($memberURLs[0], '(');
@ -197,8 +196,10 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
$dynamicMembers[$value['dn'][0]] = 1; $dynamicMembers[$value['dn'][0]] = 1;
} }
} else { } else {
\OCP\Util::writeLog('user_ldap', 'No search filter found on member url '. \OC::$server->getLogger()->debug(
'of group ' . $dnGroup, ILogger::DEBUG); 'No search filter found on member url of group {dn}',
['app' => 'user_ldap', 'dn' => $dnGroup]
);
} }
} }
return $dynamicMembers; return $dynamicMembers;
@ -279,11 +280,13 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
/** /**
* translates a gidNumber into an ownCloud internal name * translates a gidNumber into an ownCloud internal name
*
* @param string $gid as given by gidNumber on POSIX LDAP * @param string $gid as given by gidNumber on POSIX LDAP
* @param string $dn a DN that belongs to the same domain as the group * @param string $dn a DN that belongs to the same domain as the group
* @return string|bool * @return string|bool
* @throws \OC\ServerNotAvailableException
*/ */
public function gidNumber2Name($gid, $dn) { public function gidNumber2Name(string $gid, string $dn) {
$cacheKey = 'gidNumberToName' . $gid; $cacheKey = 'gidNumberToName' . $gid;
$groupName = $this->access->connection->getFromCache($cacheKey); $groupName = $this->access->connection->getFromCache($cacheKey);
if(!is_null($groupName) && isset($groupName)) { if(!is_null($groupName) && isset($groupName)) {
@ -296,7 +299,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
'objectClass=posixGroup', 'objectClass=posixGroup',
$this->access->connection->ldapGidNumber . '=' . $gid $this->access->connection->ldapGidNumber . '=' . $gid
]); ]);
$result = $this->access->searchGroups($filter, array('dn'), 1); $result = $this->access->searchGroups($filter, ['dn'], 1);
if(empty($result)) { if(empty($result)) {
return false; return false;
} }
@ -401,14 +404,8 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
/** /**
* returns the number of users that have the given group as gid number * returns the number of users that have the given group as gid number
*
* @param string $groupDN
* @param string $search
* @param int $limit
* @param int $offset
* @return int
*/ */
public function countUsersInGidNumber($groupDN, $search = '', $limit = -1, $offset = 0) { public function countUsersInGidNumber(string $groupDN, string $search = '', int $limit = -1, int $offset = 0): int {
try { try {
$filter = $this->prepareFilterForUsersHasGidNumber($groupDN, $search); $filter = $this->prepareFilterForUsersHasGidNumber($groupDN, $search);
$users = $this->access->countUsers($filter, ['dn'], $limit, $offset); $users = $this->access->countUsers($filter, ['dn'], $limit, $offset);
@ -437,11 +434,13 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
/** /**
* translates a primary group ID into an Nextcloud internal name * translates a primary group ID into an Nextcloud internal name
*
* @param string $gid as given by primaryGroupID on AD * @param string $gid as given by primaryGroupID on AD
* @param string $dn a DN that belongs to the same domain as the group * @param string $dn a DN that belongs to the same domain as the group
* @return string|bool * @return string|bool
* @throws \OC\ServerNotAvailableException
*/ */
public function primaryGroupID2Name($gid, $dn) { public function primaryGroupID2Name(string $gid, string $dn) {
$cacheKey = 'primaryGroupIDtoName'; $cacheKey = 'primaryGroupIDtoName';
$groupNames = $this->access->connection->getFromCache($cacheKey); $groupNames = $this->access->connection->getFromCache($cacheKey);
if(!is_null($groupNames) && isset($groupNames[$gid])) { if(!is_null($groupNames) && isset($groupNames[$gid])) {
@ -454,11 +453,12 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
} }
//we need to get the DN from LDAP //we need to get the DN from LDAP
$filter = $this->access->combineFilterWithAnd(array( /** @noinspection SpellCheckingInspection */
$filter = $this->access->combineFilterWithAnd([
$this->access->connection->ldapGroupFilter, $this->access->connection->ldapGroupFilter,
'objectsid=' . $domainObjectSid . '-' . $gid 'objectsid=' . $domainObjectSid . '-' . $gid
)); ]);
$result = $this->access->searchGroups($filter, array('dn'), 1); $result = $this->access->searchGroups($filter, ['dn'], 1);
if(empty($result)) { if(empty($result)) {
return false; return false;
} }
@ -563,17 +563,11 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
/** /**
* returns the number of users that have the given group as primary group * returns the number of users that have the given group as primary group
*
* @param string $groupDN
* @param string $search
* @param int $limit
* @param int $offset
* @return int
*/ */
public function countUsersInPrimaryGroup($groupDN, $search = '', $limit = -1, $offset = 0) { public function countUsersInPrimaryGroup(string $groupDN, string $search = '', int $limit = -1, int $offset = 0): int {
try { try {
$filter = $this->prepareFilterForUsersInPrimaryGroup($groupDN, $search); $filter = $this->prepareFilterForUsersInPrimaryGroup($groupDN, $search);
$users = $this->access->countUsers($filter, array('dn'), $limit, $offset); $users = $this->access->countUsers($filter, ['dn'], $limit, $offset);
return (int)$users; return (int)$users;
} catch (\Exception $e) { } catch (\Exception $e) {
return 0; return 0;
@ -861,11 +855,14 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
/** /**
* returns the number of users in a group, who match the search term * returns the number of users in a group, who match the search term
*
* @param string $gid the internal group name * @param string $gid the internal group name
* @param string $search optional, a search string * @param string $search optional, a search string
* @return int|bool * @return int|bool
* @throws \OC\ServerNotAvailableException
* @throws \Exception
*/ */
public function countUsersInGroup($gid, $search = '') { public function countUsersInGroup(string $gid, string $search = '') {
if ($this->groupPluginManager->implementsActions(GroupInterface::COUNT_USERS)) { if ($this->groupPluginManager->implementsActions(GroupInterface::COUNT_USERS)) {
return $this->groupPluginManager->countUsersInGroup($gid, $search); return $this->groupPluginManager->countUsersInGroup($gid, $search);
} }
@ -900,6 +897,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
return $groupUsers; return $groupUsers;
} }
$search = $this->access->escapeFilterPart($search, true); $search = $this->access->escapeFilterPart($search, true);
/** @noinspection SpellCheckingInspection */
$isMemberUid = $isMemberUid =
(strtolower($this->access->connection->ldapGroupMemberAssocAttr) (strtolower($this->access->connection->ldapGroupMemberAssocAttr)
=== 'memberuid'); === 'memberuid');
@ -912,14 +910,14 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
// and let it count. // and let it count.
//For now this is not important, because the only use of this method //For now this is not important, because the only use of this method
//does not supply a search string //does not supply a search string
$groupUsers = array(); $groupUsers = [];
foreach($members as $member) { foreach($members as $member) {
if($isMemberUid) { if($isMemberUid) {
//we got uids, need to get their DNs to 'translate' them to user names //we got UIDs, need to get their DNs to 'translate' them to user names
$filter = $this->access->combineFilterWithAnd(array( $filter = $this->access->combineFilterWithAnd([
str_replace('%uid', $member, $this->access->connection->ldapLoginFilter), str_replace('%uid', $member, $this->access->connection->ldapLoginFilter),
$this->access->getFilterPartForUserSearch($search) $this->access->getFilterPartForUserSearch($search)
)); ]);
$ldap_users = $this->access->fetchListOfUsers($filter, 'dn', 1); $ldap_users = $this->access->fetchListOfUsers($filter, 'dn', 1);
if(count($ldap_users) < 1) { if(count($ldap_users) < 1) {
continue; continue;
@ -933,8 +931,8 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
continue; continue;
} }
// dn2username will also check if the users belong to the allowed base // dn2username will also check if the users belong to the allowed base
if($ocname = $this->access->dn2username($member)) { if($ncName = $this->access->dn2username($member)) {
$groupUsers[] = $ocname; $groupUsers[] = $ncName;
} }
} }
} }
@ -1044,8 +1042,10 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
/** /**
* check if a group exists * check if a group exists
*
* @param string $gid * @param string $gid
* @return bool * @return bool
* @throws \OC\ServerNotAvailableException
*/ */
public function groupExists($gid) { public function groupExists($gid) {
$groupExists = $this->access->connection->getFromCache('groupExists'.$gid); $groupExists = $this->access->connection->getFromCache('groupExists'.$gid);
@ -1061,8 +1061,8 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD
return false; return false;
} }
//if group really still exists, we will be able to read its objectclass //if group really still exists, we will be able to read its objectClass
if(!is_array($this->access->readAttribute($dn, ''))) { if(!$this->access->isRecordOnLDAP($dn)) {
$this->access->connection->writeToCache('groupExists'.$gid, false); $this->access->connection->writeToCache('groupExists'.$gid, false);
return false; return false;
} }

View File

@ -620,8 +620,11 @@ class User {
* called by a post_login hook to handle password expiry * called by a post_login hook to handle password expiry
* *
* @param array $params * @param array $params
* @throws \OC\ServerNotAvailableException
* @throws \OCP\PreConditionNotMetException
* @throws \Exception
*/ */
public function handlePasswordExpiry($params) { public function handlePasswordExpiry(array $params): void {
$ppolicyDN = $this->connection->ldapDefaultPPolicyDN; $ppolicyDN = $this->connection->ldapDefaultPPolicyDN;
if (empty($ppolicyDN) || ((int)$this->connection->turnOnPasswordChange !== 1)) { if (empty($ppolicyDN) || ((int)$this->connection->turnOnPasswordChange !== 1)) {
return;//password expiry handling disabled return;//password expiry handling disabled
@ -629,7 +632,7 @@ class User {
$uid = $params['uid']; $uid = $params['uid'];
if(isset($uid) && $uid === $this->getUsername()) { if(isset($uid) && $uid === $this->getUsername()) {
//retrieve relevant user attributes //retrieve relevant user attributes
$result = $this->access->search('objectclass=*', array($this->dn), ['pwdpolicysubentry', 'pwdgraceusetime', 'pwdreset', 'pwdchangedtime']); $result = $this->access->search('objectclass=*', $this->dn, ['pwdpolicysubentry', 'pwdgraceusetime', 'pwdreset', 'pwdchangedtime']);
if(array_key_exists('pwdpolicysubentry', $result[0])) { if(array_key_exists('pwdpolicysubentry', $result[0])) {
$pwdPolicySubentry = $result[0]['pwdpolicysubentry']; $pwdPolicySubentry = $result[0]['pwdpolicysubentry'];
@ -646,7 +649,7 @@ class User {
$cacheKey = 'ppolicyAttributes' . $ppolicyDN; $cacheKey = 'ppolicyAttributes' . $ppolicyDN;
$result = $this->connection->getFromCache($cacheKey); $result = $this->connection->getFromCache($cacheKey);
if(is_null($result)) { if(is_null($result)) {
$result = $this->access->search('objectclass=*', array($ppolicyDN), ['pwdgraceauthnlimit', 'pwdmaxage', 'pwdexpirewarning']); $result = $this->access->search('objectclass=*', $ppolicyDN, ['pwdgraceauthnlimit', 'pwdmaxage', 'pwdexpirewarning']);
$this->connection->writeToCache($cacheKey, $result); $this->connection->writeToCache($cacheKey, $result);
} }
@ -662,10 +665,10 @@ class User {
&&($pwdGraceUseTimeCount < (int)$pwdGraceAuthNLimit[0])) { //at least one more grace login available? &&($pwdGraceUseTimeCount < (int)$pwdGraceAuthNLimit[0])) { //at least one more grace login available?
$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true'); $this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute( header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid))); 'user_ldap.renewPassword.showRenewPasswordForm', ['user' => $uid]));
} else { //no more grace login available } else { //no more grace login available
header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute( header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
'user_ldap.renewPassword.showLoginFormInvalidPassword', array('user' => $uid))); 'user_ldap.renewPassword.showLoginFormInvalidPassword', ['user' => $uid]));
} }
exit(); exit();
} }
@ -673,7 +676,7 @@ class User {
if($pwdReset && (count($pwdReset) > 0) && $pwdReset[0] === 'TRUE') { //user must change his password if($pwdReset && (count($pwdReset) > 0) && $pwdReset[0] === 'TRUE') { //user must change his password
$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true'); $this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute( header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid))); 'user_ldap.renewPassword.showRenewPasswordForm', ['user' => $uid]));
exit(); exit();
} }
//handle password expiry warning //handle password expiry warning

View File

@ -309,7 +309,7 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
* @throws \Exception * @throws \Exception
* @throws \OC\ServerNotAvailableException * @throws \OC\ServerNotAvailableException
*/ */
public function userExistsOnLDAP($user) { public function userExistsOnLDAP($user): bool {
if(is_string($user)) { if(is_string($user)) {
$user = $this->access->userManager->get($user); $user = $this->access->userManager->get($user);
} }
@ -319,7 +319,7 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
$dn = $user->getDN(); $dn = $user->getDN();
//check if user really still exists by reading its entry //check if user really still exists by reading its entry
if(!is_array($this->access->readAttribute($dn, '', $this->access->connection->ldapUserFilter))) { if(!$this->access->isRecordOnLDAP($dn, $this->access->connection->ldapUserFilter)) {
try { try {
$uuid = $this->access->getUserMapper()->getUUIDByDN($dn); $uuid = $this->access->getUserMapper()->getUUIDByDN($dn);
if (!$uuid) { if (!$uuid) {
@ -327,7 +327,7 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
} }
$newDn = $this->access->getUserDnByUuid($uuid); $newDn = $this->access->getUserDnByUuid($uuid);
//check if renamed user is still valid by reapplying the ldap filter //check if renamed user is still valid by reapplying the ldap filter
if ($newDn === $dn || !is_array($this->access->readAttribute($newDn, '', $this->access->connection->ldapUserFilter))) { if ($newDn === $dn || !$this->access->isRecordOnLDAP($newDn, $this->access->connection->ldapUserFilter)) {
return false; return false;
} }
$this->access->getUserMapper()->setDNbyUUID($newDn, $uuid); $this->access->getUserMapper()->setDNbyUUID($newDn, $uuid);

View File

@ -131,11 +131,15 @@ class Wizard extends LDAPUtility {
return (string)$count; return (string)$count;
} }
/**
* @return bool|WizardResult
* @throws \Exception
*/
public function countGroups() { public function countGroups() {
$filter = $this->configuration->ldapGroupFilter; $filter = $this->configuration->ldapGroupFilter;
if(empty($filter)) { if(empty($filter)) {
$output = self::$l->n('%s group found', '%s groups found', 0, array(0)); $output = self::$l->n('%s group found', '%s groups found', 0, [0]);
$this->result->addChange('ldap_group_count', $output); $this->result->addChange('ldap_group_count', $output);
return $this->result; return $this->result;
} }
@ -195,27 +199,28 @@ class Wizard extends LDAPUtility {
/** /**
* counts users with a specified attribute * counts users with a specified attribute
* @param string $attr *
* @param bool $existsCheck
* @return int|bool * @return int|bool
* @throws ServerNotAvailableException
*/ */
public function countUsersWithAttribute($attr, $existsCheck = false) { public function countUsersWithAttribute(string $attr, bool $existsCheck = false) {
if(!$this->checkRequirements(array('ldapHost', if(!$this->checkRequirements([
'ldapHost',
'ldapPort', 'ldapPort',
'ldapBase', 'ldapBase',
'ldapUserFilter', 'ldapUserFilter',
))) { ])) {
return false; return false;
} }
$filter = $this->access->combineFilterWithAnd(array( $filter = $this->access->combineFilterWithAnd([
$this->configuration->ldapUserFilter, $this->configuration->ldapUserFilter,
$attr . '=*' $attr . '=*'
)); ]);
$limit = ($existsCheck === false) ? null : 1; $limit = ($existsCheck === false) ? null : 1;
return $this->access->countUsers($filter, array('dn'), $limit); return $this->access->countUsers($filter, ['dn'], $limit);
} }
/** /**
@ -225,11 +230,12 @@ class Wizard extends LDAPUtility {
* @throws \Exception * @throws \Exception
*/ */
public function detectUserDisplayNameAttribute() { public function detectUserDisplayNameAttribute() {
if(!$this->checkRequirements(array('ldapHost', if(!$this->checkRequirements([
'ldapHost',
'ldapPort', 'ldapPort',
'ldapBase', 'ldapBase',
'ldapUserFilter', 'ldapUserFilter',
))) { ])) {
return false; return false;
} }
@ -247,7 +253,8 @@ class Wizard extends LDAPUtility {
} }
// first attribute that has at least one result wins // first attribute that has at least one result wins
$displayNameAttrs = array('displayname', 'cn'); /** @noinspection SpellCheckingInspection */
$displayNameAttrs = ['displayname', 'cn'];
foreach ($displayNameAttrs as $attr) { foreach ($displayNameAttrs as $attr) {
$count = (int)$this->countUsersWithAttribute($attr, true); $count = (int)$this->countUsersWithAttribute($attr, true);
@ -267,26 +274,26 @@ class Wizard extends LDAPUtility {
* @return WizardResult|bool * @return WizardResult|bool
*/ */
public function detectEmailAttribute() { public function detectEmailAttribute() {
if(!$this->checkRequirements(array('ldapHost', if(!$this->checkRequirements([
'ldapHost',
'ldapPort', 'ldapPort',
'ldapBase', 'ldapBase',
'ldapUserFilter', 'ldapUserFilter',
))) { ])) {
return false; return false;
} }
$attr = $this->configuration->ldapEmailAttribute; $attr = $this->configuration->ldapEmailAttribute;
$writeLog = false;
if ($attr !== '') { if ($attr !== '') {
$count = (int)$this->countUsersWithAttribute($attr, true); $count = (int)$this->countUsersWithAttribute($attr, true);
if($count > 0) { if($count > 0) {
return false; return false;
} }
$writeLog = true; $writeLog = true;
} else {
$writeLog = false;
} }
$emailAttributes = array('mail', 'mailPrimaryAddress'); $emailAttributes = ['mail', 'mailPrimaryAddress'];
$winner = ''; $winner = '';
$maxUsers = 0; $maxUsers = 0;
foreach($emailAttributes as $attr) { foreach($emailAttributes as $attr) {
@ -300,9 +307,10 @@ class Wizard extends LDAPUtility {
if($winner !== '') { if($winner !== '') {
$this->applyFind('ldap_email_attr', $winner); $this->applyFind('ldap_email_attr', $winner);
if($writeLog) { if($writeLog) {
\OCP\Util::writeLog('user_ldap', 'The mail attribute has ' . \OC::$server->getLogger()->info(
'automatically been reset, because the original value ' . 'The mail attribute has automatically been reset, because the original value did not return any results',
'did not return any results.', ILogger::INFO); ['app' => 'user_ldap']
);
} }
} }
@ -627,15 +635,14 @@ class Wizard extends LDAPUtility {
/** /**
* @return bool|WizardResult * @return bool|WizardResult
* @param string $loginName
* @throws \Exception * @throws \Exception
*/ */
public function testLoginName($loginName) { public function testLoginName(string $loginName) {
if(!$this->checkRequirements(array('ldapHost', if(!$this->checkRequirements(['ldapHost',
'ldapPort', 'ldapPort',
'ldapBase', 'ldapBase',
'ldapLoginFilter', 'ldapLoginFilter',
))) { ])) {
return false; return false;
} }
@ -654,6 +661,7 @@ class Wizard extends LDAPUtility {
throw new \Exception($this->ldap->error($cr)); throw new \Exception($this->ldap->error($cr));
} }
$filter = str_replace('%uid', $loginName, $this->access->connection->ldapLoginFilter); $filter = str_replace('%uid', $loginName, $this->access->connection->ldapLoginFilter);
/** @noinspection SpellCheckingInspection */
$this->result->addChange('ldap_test_loginname', $users); $this->result->addChange('ldap_test_loginname', $users);
$this->result->addChange('ldap_test_effective_filter', $filter); $this->result->addChange('ldap_test_effective_filter', $filter);
return $this->result; return $this->result;
@ -832,11 +840,9 @@ class Wizard extends LDAPUtility {
/** /**
* Checks whether for a given BaseDN results will be returned * Checks whether for a given BaseDN results will be returned
* @param string $base the BaseDN to test
* @return bool true on success, false otherwise
* @throws \Exception * @throws \Exception
*/ */
private function testBaseDN($base) { private function testBaseDN(string $base): bool {
$cr = $this->getConnection(); $cr = $this->getConnection();
if(!$cr) { if(!$cr) {
throw new \Exception('Could not connect to LDAP'); throw new \Exception('Could not connect to LDAP');
@ -844,12 +850,14 @@ class Wizard extends LDAPUtility {
//base is there, let's validate it. If we search for anything, we should //base is there, let's validate it. If we search for anything, we should
//get a result set > 0 on a proper base //get a result set > 0 on a proper base
$rr = $this->ldap->search($cr, $base, 'objectClass=*', array('dn'), 0, 1); $rr = $this->ldap->search($cr, $base, 'objectClass=*', ['dn'], 0, 1);
if(!$this->ldap->isResource($rr)) { if(!$this->ldap->isResource($rr)) {
$errorNo = $this->ldap->errno($cr); $errorNo = $this->ldap->errno($cr);
$errorMsg = $this->ldap->error($cr); $errorMsg = $this->ldap->error($cr);
\OCP\Util::writeLog('user_ldap', 'Wiz: Could not search base '.$base. \OC::$server->getLogger()->info(
' Error '.$errorNo.': '.$errorMsg, ILogger::INFO); 'Wiz: Could not search base {base}, Error {errno}: {error}',
['app' => 'user_ldap', 'base' => $base, 'errno' => $errorNo, 'error' => $errorMsg]
);
return false; return false;
} }
$entries = $this->ldap->countEntries($cr, $rr); $entries = $this->ldap->countEntries($cr, $rr);
@ -862,15 +870,15 @@ class Wizard extends LDAPUtility {
* a configured objectClass. I.e. not necessarily for all available groups * a configured objectClass. I.e. not necessarily for all available groups
* memberOf does work. * memberOf does work.
* *
* @return bool true if it does, false otherwise * @throws ServerNotAvailableException
* @throws \Exception * @throws \Exception
*/ */
private function testMemberOf() { private function testMemberOf(): bool {
$cr = $this->getConnection(); $cr = $this->getConnection();
if(!$cr) { if(!$cr) {
throw new \Exception('Could not connect to LDAP'); throw new \Exception('Could not connect to LDAP');
} }
$result = $this->access->countUsers('memberOf=*', array('memberOf'), 1); $result = $this->access->countUsers('memberOf=*', ['memberOf'], 1);
if(is_int($result) && $result > 0) { if(is_int($result) && $result > 0) {
return true; return true;
} }
@ -1131,9 +1139,9 @@ class Wizard extends LDAPUtility {
* yields most result entries * yields most result entries
* @return array|false an array with the values on success, false otherwise * @return array|false an array with the values on success, false otherwise
*/ */
public function cumulativeSearchOnAttribute($filters, $attr, $dnReadLimit = 3, &$maxF = null) { public function cumulativeSearchOnAttribute(array $filters, string $attr, int $dnReadLimit = 3, string &$maxF = null) {
$dnRead = array(); $dnRead = [];
$foundItems = array(); $foundItems = [];
$maxEntries = 0; $maxEntries = 0;
if(!is_array($this->configuration->ldapBase) if(!is_array($this->configuration->ldapBase)
|| !isset($this->configuration->ldapBase[0])) { || !isset($this->configuration->ldapBase[0])) {
@ -1154,7 +1162,7 @@ class Wizard extends LDAPUtility {
continue; continue;
} }
// 20k limit for performance and reason // 20k limit for performance and reason
$rr = $this->ldap->search($cr, $base, $filter, array($attr), 0, 20000); $rr = $this->ldap->search($cr, $base, $filter, [$attr], 0, 20000);
if(!$this->ldap->isResource($rr)) { if(!$this->ldap->isResource($rr)) {
continue; continue;
} }
@ -1178,7 +1186,7 @@ class Wizard extends LDAPUtility {
if($dn === false || in_array($dn, $dnRead)) { if($dn === false || in_array($dn, $dnRead)) {
continue; continue;
} }
$newItems = array(); $newItems = [];
$state = $this->getAttributeValuesFromEntry($attributes, $state = $this->getAttributeValuesFromEntry($attributes,
$attr, $attr,
$newItems); $newItems);
@ -1249,15 +1257,7 @@ class Wizard extends LDAPUtility {
return $availableFeatures; return $availableFeatures;
} }
/** private function getAttributeValuesFromEntry(array $result, string $attribute, array &$known): int {
* appends a list of values fr
* @param resource $result the return value from ldap_get_attributes
* @param string $attribute the attribute values to look for
* @param array &$known new values will be appended here
* @return int, state on of the class constants LRESULT_PROCESSED_OK,
* LRESULT_PROCESSED_INVALID or LRESULT_PROCESSED_SKIP
*/
private function getAttributeValuesFromEntry($result, $attribute, &$known) {
if(!is_array($result) if(!is_array($result)
|| !isset($result['count']) || !isset($result['count'])
|| !$result['count'] > 0) { || !$result['count'] > 0) {

View File

@ -559,7 +559,7 @@ class AccessTest extends TestCase {
->method('search') ->method('search')
->willReturn([$fakeSearchResultResource]); ->willReturn([$fakeSearchResultResource]);
$this->ldap $this->ldap
->expects($this->exactly(count($base))) ->expects($this->exactly(1))
->method('getEntries') ->method('getEntries')
->willReturn($fakeLdapEntries); ->willReturn($fakeLdapEntries);
@ -571,7 +571,7 @@ class AccessTest extends TestCase {
public function testSearchNoPagedSearch() { public function testSearchNoPagedSearch() {
// scenario: no pages search, 1 search base // scenario: no pages search, 1 search base
$filter = 'objectClass=nextcloudUser'; $filter = 'objectClass=nextcloudUser';
$base = ['ou=zombies,dc=foobar,dc=nextcloud,dc=com']; $base = 'ou=zombies,dc=foobar,dc=nextcloud,dc=com';
$fakeConnection = new \stdClass(); $fakeConnection = new \stdClass();
$fakeSearchResultResource = new \stdClass(); $fakeSearchResultResource = new \stdClass();

View File

@ -105,9 +105,13 @@ class Group_LDAPTest extends TestCase {
->method('groupname2dn') ->method('groupname2dn')
->will($this->returnValue('cn=group,dc=foo,dc=bar')); ->will($this->returnValue('cn=group,dc=foo,dc=bar'));
$access->expects($this->any()) $access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->will($this->returnValue(array('u11', 'u22', 'u33', 'u34'))); ->will($this->returnValue(['u11', 'u22', 'u33', 'u34']));
$access->expects($this->atLeastOnce())
->method('isRecordOnLDAP')
->with($this->anything())
->willReturn(true);
// for primary groups // for primary groups
$access->expects($this->once()) $access->expects($this->once())
@ -132,9 +136,9 @@ class Group_LDAPTest extends TestCase {
$access->expects($this->any()) $access->expects($this->any())
->method('fetchListOfUsers') ->method('fetchListOfUsers')
->will($this->returnValue(array())); ->will($this->returnValue([]));
$access->expects($this->any()) $access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->will($this->returnCallback(function($name) { ->will($this->returnCallback(function($name) {
//the search operation will call readAttribute, thus we need //the search operation will call readAttribute, thus we need
@ -145,14 +149,21 @@ class Group_LDAPTest extends TestCase {
if(strpos($name, 'u') === 0) { if(strpos($name, 'u') === 0) {
return strpos($name, '3'); return strpos($name, '3');
} }
return array('u11', 'u22', 'u33', 'u34'); return ['u11', 'u22', 'u33', 'u34'];
})); }));
$access->expects($this->atLeastOnce())
->method('isRecordOnLDAP')
->with($this->anything())
->willReturn(true);
$access->expects($this->any()) $access->expects($this->any())
->method('dn2username') ->method('dn2username')
->will($this->returnCallback(function() { ->will($this->returnCallback(function() {
return 'foobar' . \OC::$server->getSecureRandom()->generate(7); return 'foobar' . \OC::$server->getSecureRandom()->generate(7);
})); }));
$access->expects($this->any())
->method('escapeFilterPart')
->willReturnArgument(0);
$groupBackend = new GroupLDAP($access,$pluginManager); $groupBackend = new GroupLDAP($access,$pluginManager);
$users = $groupBackend->countUsersInGroup('group', '3'); $users = $groupBackend->countUsersInGroup('group', '3');
@ -262,10 +273,10 @@ class Group_LDAPTest extends TestCase {
$dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar'; $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
$attr = 'gidNumber'; $attr = 'gidNumber';
$access->expects($this->once()) $access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->with($dn, $attr) ->with($dn, $attr)
->will($this->returnValue(array('3117'))); ->will($this->returnValue(['3117']));
$groupBackend = new GroupLDAP($access, $pluginManager); $groupBackend = new GroupLDAP($access, $pluginManager);
@ -283,7 +294,7 @@ class Group_LDAPTest extends TestCase {
$dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar'; $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
$attr = 'gidNumber'; $attr = 'gidNumber';
$access->expects($this->once()) $access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->with($dn, $attr) ->with($dn, $attr)
->will($this->returnValue(false)); ->will($this->returnValue(false));
@ -416,10 +427,10 @@ class Group_LDAPTest extends TestCase {
$dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar'; $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
$attr = 'primaryGroupToken'; $attr = 'primaryGroupToken';
$access->expects($this->once()) $access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->with($dn, $attr) ->with($dn, $attr)
->will($this->returnValue(array('3117'))); ->will($this->returnValue(['3117']));
$groupBackend = new GroupLDAP($access, $pluginManager); $groupBackend = new GroupLDAP($access, $pluginManager);
@ -439,7 +450,7 @@ class Group_LDAPTest extends TestCase {
$dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar'; $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
$attr = 'primaryGroupToken'; $attr = 'primaryGroupToken';
$access->expects($this->once()) $access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->with($dn, $attr) ->with($dn, $attr)
->will($this->returnValue(false)); ->will($this->returnValue(false));
@ -506,16 +517,20 @@ class Group_LDAPTest extends TestCase {
$access->connection->expects($this->any()) $access->connection->expects($this->any())
->method('getFromCache') ->method('getFromCache')
->will($this->returnValue(null)); ->will($this->returnValue(null));
$access->expects($this->any()) $access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) { ->will($this->returnCallback(function($dn, $attr) {
if($attr === 'primaryGroupToken') { if($attr === 'primaryGroupToken') {
return array(1337); return [1337];
} else if($attr === 'gidNumber') { } else if($attr === 'gidNumber') {
return [4211]; return [4211];
} }
return array(); return [];
})); }));
$access->expects($this->atLeastOnce())
->method('isRecordOnLDAP')
->with($this->anything())
->willReturn(true);
$access->expects($this->any()) $access->expects($this->any())
->method('groupname2dn') ->method('groupname2dn')
->will($this->returnValue('cn=foobar,dc=foo,dc=bar')); ->will($this->returnValue('cn=foobar,dc=foo,dc=bar'));
@ -543,20 +558,24 @@ class Group_LDAPTest extends TestCase {
$access->connection->expects($this->any()) $access->connection->expects($this->any())
->method('getFromCache') ->method('getFromCache')
->will($this->returnValue(null)); ->will($this->returnValue(null));
$access->expects($this->any()) $access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) { ->will($this->returnCallback(function($dn, $attr) {
if($attr === 'primaryGroupToken') { if($attr === 'primaryGroupToken') {
return array(1337); return [1337];
} }
return array(); return [];
})); }));
$access->expects($this->atLeastOnce())
->method('isRecordOnLDAP')
->with($this->anything())
->willReturn(true);
$access->expects($this->any()) $access->expects($this->any())
->method('groupname2dn') ->method('groupname2dn')
->will($this->returnValue('cn=foobar,dc=foo,dc=bar')); ->will($this->returnValue('cn=foobar,dc=foo,dc=bar'));
$access->expects($this->once()) $access->expects($this->once())
->method('nextcloudUserNames') ->method('nextcloudUserNames')
->will($this->returnValue(array('lisa', 'bart', 'kira', 'brad'))); ->will($this->returnValue(['lisa', 'bart', 'kira', 'brad']));
$access->userManager = $this->createMock(Manager::class); $access->userManager = $this->createMock(Manager::class);
$groupBackend = new GroupLDAP($access, $pluginManager); $groupBackend = new GroupLDAP($access, $pluginManager);
@ -579,15 +598,20 @@ class Group_LDAPTest extends TestCase {
->method('getFromCache') ->method('getFromCache')
->will($this->returnValue(null)); ->will($this->returnValue(null));
$access->expects($this->any()) $access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) { ->will($this->returnCallback(function($dn, $attr) {
if($attr === 'primaryGroupToken') { if($attr === 'primaryGroupToken') {
return array(1337); return [1337];
} }
return array(); return [];
})); }));
$access->expects($this->atLeastOnce())
->method('isRecordOnLDAP')
->with($this->anything())
->willReturn(true);
$access->expects($this->any()) $access->expects($this->any())
->method('groupname2dn') ->method('groupname2dn')
->will($this->returnValue('cn=foobar,dc=foo,dc=bar')); ->will($this->returnValue('cn=foobar,dc=foo,dc=bar'));
@ -1018,7 +1042,7 @@ class Group_LDAPTest extends TestCase {
*/ */
public function testGroupMembers($groupDN, $expectedMembers, $groupsInfo = null) { public function testGroupMembers($groupDN, $expectedMembers, $groupsInfo = null) {
$access = $this->getAccessMock(); $access = $this->getAccessMock();
$access->expects($this->any()) $access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->willReturnCallback(function($group) use ($groupDN, $expectedMembers, $groupsInfo) { ->willReturnCallback(function($group) use ($groupDN, $expectedMembers, $groupsInfo) {
if(isset($groupsInfo[$group])) { if(isset($groupsInfo[$group])) {

View File

@ -545,7 +545,7 @@ class UserTest extends \Test\TestCase {
} }
public function testUpdateAvatarThumbnailPhotoProvided() { public function testUpdateAvatarThumbnailPhotoProvided() {
$this->access->expects($this->any()) $this->access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->willReturnCallback(function($dn, $attr) { ->willReturnCallback(function($dn, $attr) {
if($dn === $this->dn if($dn === $this->dn
@ -599,7 +599,7 @@ class UserTest extends \Test\TestCase {
} }
public function testUpdateAvatarCorruptPhotoProvided() { public function testUpdateAvatarCorruptPhotoProvided() {
$this->access->expects($this->any()) $this->access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->willReturnCallback(function($dn, $attr) { ->willReturnCallback(function($dn, $attr) {
if($dn === $this->dn if($dn === $this->dn
@ -645,7 +645,7 @@ class UserTest extends \Test\TestCase {
} }
public function testUpdateAvatarUnsupportedThumbnailPhotoProvided() { public function testUpdateAvatarUnsupportedThumbnailPhotoProvided() {
$this->access->expects($this->any()) $this->access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->willReturnCallback(function($dn, $attr) { ->willReturnCallback(function($dn, $attr) {
if($dn === $this->dn if($dn === $this->dn
@ -700,7 +700,7 @@ class UserTest extends \Test\TestCase {
} }
public function testUpdateAvatarNotProvided() { public function testUpdateAvatarNotProvided() {
$this->access->expects($this->any()) $this->access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->willReturnCallback(function($dn, $attr) { ->willReturnCallback(function($dn, $attr) {
if($dn === $this->dn if($dn === $this->dn
@ -962,7 +962,7 @@ class UserTest extends \Test\TestCase {
->with($this->equalTo('homeFolderNamingRule')) ->with($this->equalTo('homeFolderNamingRule'))
->will($this->returnValue('attr:foobar')); ->will($this->returnValue('attr:foobar'));
$this->access->expects($this->once()) $this->access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->will($this->returnValue(false)); ->will($this->returnValue(false));
@ -984,7 +984,7 @@ class UserTest extends \Test\TestCase {
->with($this->equalTo('homeFolderNamingRule')) ->with($this->equalTo('homeFolderNamingRule'))
->will($this->returnValue('attr:foobar')); ->will($this->returnValue('attr:foobar'));
$this->access->expects($this->once()) $this->access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->will($this->returnValue(false)); ->will($this->returnValue(false));
@ -1066,7 +1066,7 @@ class UserTest extends \Test\TestCase {
$this->access->expects($this->any()) $this->access->expects($this->any())
->method('search') ->method('search')
->will($this->returnCallback(function($filter, $base) { ->will($this->returnCallback(function($filter, $base) {
if($base === [$this->dn]) { if($base === $this->dn) {
return [ return [
[ [
'pwdchangedtime' => [(new \DateTime())->sub(new \DateInterval('P28D'))->format('Ymdhis').'Z'], 'pwdchangedtime' => [(new \DateTime())->sub(new \DateInterval('P28D'))->format('Ymdhis').'Z'],
@ -1074,7 +1074,7 @@ class UserTest extends \Test\TestCase {
], ],
]; ];
} }
if($base === ['cn=default,ou=policies,dc=foo,dc=bar']) { if($base === 'cn=default,ou=policies,dc=foo,dc=bar') {
return [ return [
[ [
'pwdmaxage' => ['2592000'], 'pwdmaxage' => ['2592000'],
@ -1129,7 +1129,7 @@ class UserTest extends \Test\TestCase {
$this->access->expects($this->any()) $this->access->expects($this->any())
->method('search') ->method('search')
->will($this->returnCallback(function($filter, $base) { ->will($this->returnCallback(function($filter, $base) {
if($base === [$this->dn]) { if($base === $this->dn) {
return [ return [
[ [
'pwdpolicysubentry' => ['cn=custom,ou=policies,dc=foo,dc=bar'], 'pwdpolicysubentry' => ['cn=custom,ou=policies,dc=foo,dc=bar'],
@ -1138,7 +1138,7 @@ class UserTest extends \Test\TestCase {
] ]
]; ];
} }
if($base === ['cn=custom,ou=policies,dc=foo,dc=bar']) { if($base === 'cn=custom,ou=policies,dc=foo,dc=bar') {
return [ return [
[ [
'pwdmaxage' => ['2592000'], 'pwdmaxage' => ['2592000'],

View File

@ -494,14 +494,11 @@ class User_LDAPTest extends TestCase {
->method('getDN') ->method('getDN')
->willReturn('dnOfRoland,dc=test'); ->willReturn('dnOfRoland,dc=test');
$this->access->expects($this->any()) $this->access->expects($this->atLeastOnce())
->method('readAttribute') ->method('isRecordOnLDAP')
->will($this->returnCallback(function($dn) { ->with('dnOfRoland,dc=test')
if($dn === 'dnOfRoland,dc=test') { ->willReturn(true);
return array();
}
return false;
}));
$this->userManager->expects($this->atLeastOnce()) $this->userManager->expects($this->atLeastOnce())
->method('get') ->method('get')
->willReturn($user); ->willReturn($user);
@ -509,6 +506,15 @@ class User_LDAPTest extends TestCase {
->method('getUserMapper') ->method('getUserMapper')
->willReturn($this->createMock(UserMapping::class)); ->willReturn($this->createMock(UserMapping::class));
$this->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'ldapUserFilter') {
return 'objectclass=inetorgperson';
}
return null;
}));
//test for existing user //test for existing user
/** @noinspection PhpUnhandledExceptionInspection */ /** @noinspection PhpUnhandledExceptionInspection */
$result = $backend->userExists('gunslinger'); $result = $backend->userExists('gunslinger');
@ -525,14 +531,6 @@ class User_LDAPTest extends TestCase {
->with('dnOfFormerUser,dc=test') ->with('dnOfFormerUser,dc=test')
->willReturn('45673458748'); ->willReturn('45673458748');
$this->access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland,dc=test') {
return array();
}
return false;
}));
$this->access->expects($this->any()) $this->access->expects($this->any())
->method('getUserMapper') ->method('getUserMapper')
->willReturn($mapper); ->willReturn($mapper);
@ -549,6 +547,16 @@ class User_LDAPTest extends TestCase {
->method('get') ->method('get')
->willReturn($user); ->willReturn($user);
$this->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'ldapUserFilter') {
return 'objectclass=inetorgperson';
}
return null;
}));
//test for deleted user //test for deleted user
$this->assertFalse($backend->userExists('formerUser')); $this->assertFalse($backend->userExists('formerUser'));
} }
@ -557,15 +565,6 @@ class User_LDAPTest extends TestCase {
$backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager);
$this->prepareMockForUserExists(); $this->prepareMockForUserExists();
$this->access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland,dc=test') {
return array();
}
return false;
}));
//test for never-existing user //test for never-existing user
/** @noinspection PhpUnhandledExceptionInspection */ /** @noinspection PhpUnhandledExceptionInspection */
$result = $backend->userExists('mallory'); $result = $backend->userExists('mallory');
@ -582,14 +581,11 @@ class User_LDAPTest extends TestCase {
->method('getDN') ->method('getDN')
->willReturn('dnOfRoland,dc=test'); ->willReturn('dnOfRoland,dc=test');
$this->access->expects($this->any()) $this->access->expects($this->atLeastOnce())
->method('readAttribute') ->method('isRecordOnLDAP')
->will($this->returnCallback(function($dn) { ->with('dnOfRoland,dc=test')
if($dn === 'dnOfRoland,dc=test') { ->willReturn(true);
return array();
}
return false;
}));
$this->userManager->expects($this->atLeastOnce()) $this->userManager->expects($this->atLeastOnce())
->method('get') ->method('get')
->willReturn($user); ->willReturn($user);
@ -597,6 +593,16 @@ class User_LDAPTest extends TestCase {
->method('getUserMapper') ->method('getUserMapper')
->willReturn($this->createMock(UserMapping::class)); ->willReturn($this->createMock(UserMapping::class));
$this->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'ldapUserFilter') {
return 'objectclass=inetorgperson';
}
return null;
}));
//test for existing user //test for existing user
$result = \OC::$server->getUserManager()->userExists('gunslinger'); $result = \OC::$server->getUserManager()->userExists('gunslinger');
$this->assertTrue($result); $this->assertTrue($result);
@ -613,14 +619,6 @@ class User_LDAPTest extends TestCase {
->with('dnOfFormerUser,dc=test') ->with('dnOfFormerUser,dc=test')
->willReturn('45673458748'); ->willReturn('45673458748');
$this->access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland,dc=test') {
return array();
}
return false;
}));
$this->access->expects($this->any()) $this->access->expects($this->any())
->method('getUserMapper') ->method('getUserMapper')
->willReturn($mapper); ->willReturn($mapper);
@ -637,6 +635,16 @@ class User_LDAPTest extends TestCase {
->method('get') ->method('get')
->willReturn($user); ->willReturn($user);
$this->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'ldapUserFilter') {
return 'objectclass=inetorgperson';
}
return null;
}));
//test for deleted user //test for deleted user
$this->assertFalse(\OC::$server->getUserManager()->userExists('formerUser')); $this->assertFalse(\OC::$server->getUserManager()->userExists('formerUser'));
} }
@ -646,15 +654,6 @@ class User_LDAPTest extends TestCase {
$this->prepareMockForUserExists(); $this->prepareMockForUserExists();
\OC_User::useBackend($backend); \OC_User::useBackend($backend);
$this->access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland,dc=test') {
return array();
}
return false;
}));
//test for never-existing user //test for never-existing user
$result = \OC::$server->getUserManager()->userExists('mallory'); $result = \OC::$server->getUserManager()->userExists('mallory');
$this->assertFalse($result); $this->assertFalse($result);
@ -677,24 +676,16 @@ class User_LDAPTest extends TestCase {
->will($this->returnCallback(function($name) { ->will($this->returnCallback(function($name) {
if($name === 'homeFolderNamingRule') { if($name === 'homeFolderNamingRule') {
return 'attr:testAttribute'; return 'attr:testAttribute';
} elseif ($name === 'ldapUserFilter') {
return 'objectclass=inetorgperson';
} }
return null; return null;
})); }));
$this->access->expects($this->any()) $this->access->expects($this->atLeastOnce())
->method('readAttribute') ->method('isRecordOnLDAP')
->will($this->returnCallback(function($dn, $attr) { ->with('dnOfRoland,dc=test')
switch ($dn) { ->willReturn(true);
case 'dnOfRoland,dc=test':
if($attr === 'testAttribute') {
return array('/tmp/rolandshome/');
}
return array();
break;
default:
return false;
}
}));
$user = $this->createMock(User::class); $user = $this->createMock(User::class);
$user->expects($this->any()) $user->expects($this->any())
@ -729,24 +720,16 @@ class User_LDAPTest extends TestCase {
->will($this->returnCallback(function($name) { ->will($this->returnCallback(function($name) {
if($name === 'homeFolderNamingRule') { if($name === 'homeFolderNamingRule') {
return 'attr:testAttribute'; return 'attr:testAttribute';
} else if ($name === 'ldapUserFilter') {
return 'objectclass=inetorgperson';
} }
return null; return null;
})); }));
$this->access->expects($this->any()) $this->access->expects($this->atLeastOnce())
->method('readAttribute') ->method('isRecordOnLDAP')
->will($this->returnCallback(function($dn, $attr) { ->with('dnOfLadyOfShadows,dc=test')
switch ($dn) { ->willReturn(true);
case 'dnOfLadyOfShadows,dc=test':
if($attr === 'testAttribute') {
return array('susannah/');
}
return array();
break;
default:
return false;
}
}));
$user = $this->createMock(User::class); $user = $this->createMock(User::class);
$user->expects($this->any()) $user->expects($this->any())
@ -775,22 +758,6 @@ class User_LDAPTest extends TestCase {
$backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager);
$this->prepareMockForUserExists(); $this->prepareMockForUserExists();
$this->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'homeFolderNamingRule') {
return 'attr:testAttribute';
}
return null;
}));
$this->access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) {
switch ($dn) {
default:
return false;
}
}));
$this->access->connection->expects($this->any()) $this->access->connection->expects($this->any())
->method('getFromCache') ->method('getFromCache')
->willReturnCallback(function($key) { ->willReturnCallback(function($key) {
@ -835,10 +802,6 @@ class User_LDAPTest extends TestCase {
return null; return null;
})); }));
$this->access->expects($this->any())
->method('readAttribute')
->will($this->returnValue([]));
$userMapper = $this->createMock(UserMapping::class); $userMapper = $this->createMock(UserMapping::class);
$this->access->expects($this->any()) $this->access->expects($this->any())
@ -886,11 +849,13 @@ class User_LDAPTest extends TestCase {
->will($this->returnCallback(function($name) { ->will($this->returnCallback(function($name) {
if($name === 'ldapUserDisplayName') { if($name === 'ldapUserDisplayName') {
return 'displayname'; return 'displayname';
} elseif ($name === 'ldapUserFilter') {
return 'objectclass=inetorgperson';
} }
return null; return null;
})); }));
$this->access->expects($this->any()) $this->access->expects($this->atLeastOnce())
->method('readAttribute') ->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) { ->will($this->returnCallback(function($dn, $attr) {
switch ($dn) { switch ($dn) {
@ -957,6 +922,10 @@ class User_LDAPTest extends TestCase {
->method('getUserDnByUuid') ->method('getUserDnByUuid')
->willReturnCallback(function($uuid) { return $uuid . '1'; }); ->willReturnCallback(function($uuid) { return $uuid . '1'; });
$this->access->expects($this->atLeastOnce())
->method('isRecordOnLDAP')
->willReturn(true);
//with displayName //with displayName
$result = $backend->getDisplayName('gunslinger'); $result = $backend->getDisplayName('gunslinger');
$this->assertEquals('Roland Deschain', $result); $this->assertEquals('Roland Deschain', $result);
@ -996,6 +965,14 @@ class User_LDAPTest extends TestCase {
->will($this->returnCallback(function() { ->will($this->returnCallback(function() {
return true; return true;
})); }));
$this->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'ldapUserFilter') {
return 'objectclass=inetorgperson';
}
return null;
}));
\OC_User::useBackend($backend); \OC_User::useBackend($backend);
@ -1035,6 +1012,9 @@ class User_LDAPTest extends TestCase {
$this->access->expects($this->any()) $this->access->expects($this->any())
->method('getUserDnByUuid') ->method('getUserDnByUuid')
->willReturnCallback(function($uuid) { return $uuid . '1'; }); ->willReturnCallback(function($uuid) { return $uuid . '1'; });
$this->access->expects($this->atLeastOnce())
->method('isRecordOnLDAP')
->willReturn(true);
//with displayName //with displayName
$result = \OC::$server->getUserManager()->get('gunslinger')->getDisplayName(); $result = \OC::$server->getUserManager()->get('gunslinger')->getDisplayName();