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;
/** @var IUserManager */
private $ncUserManager;
/** @var ILogger */
private $logger;
public function __construct(
Connection $connection,
@ -113,6 +115,7 @@ class Access extends LDAPUtility {
$this->helper = $helper;
$this->config = $config;
$this->ncUserManager = $ncUserManager;
$this->logger = \OC::$server->getLogger();
}
/**
@ -258,27 +261,18 @@ class Access extends LDAPUtility {
* @param string $attribute
* @param string $filter
* @param int $maxResults
* @return array|bool false if there was any error, true if an exists check
* was performed and the requested DN found, array with the
* returned data on a successful usual operation
* @return array|bool false if there was any error
* @throws ServerNotAvailableException
*/
public function executeRead($cr, $dn, $attribute, $filter, $maxResults) {
$this->initPagedSearch($filter, array($dn), array($attribute), $maxResults, 0);
public function executeRead($cr, string $dn, string $attribute, string $filter, int $maxResults) {
$this->initPagedSearch($filter, $dn, [$attribute], $maxResults, 0);
$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 ($attribute !== '') {
//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
$this->logger->debug('readAttribute failed for DN {dn}', ['app' => 'user_ldap', 'dn' => $dn]);
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);
if (!$this->ldap->isResource($er)) {
//did not match the filter, return false
@ -291,6 +285,25 @@ class Access extends LDAPUtility {
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
* data if present.
@ -474,11 +487,9 @@ class Access extends LDAPUtility {
* filter by doing read operations against the group entries. Returns an
* array of DNs that match the filter.
*
* @param string[] $groupDNs
* @return string[]
* @throws ServerNotAvailableException
*/
public function groupsMatchFilter($groupDNs) {
public function groupsMatchFilter(array $groupDNs): array {
$validGroupDNs = [];
foreach($groupDNs as $dn) {
$cacheKey = 'groupsMatchFilter-'.$dn;
@ -497,8 +508,7 @@ class Access extends LDAPUtility {
continue;
}
$result = $this->readAttribute($dn, '', $this->connection->ldapGroupFilter);
if(is_array($result)) {
if($this->isRecordOnLDAP($dn, $this->connection->ldapGroupFilter)) {
$this->connection->writeToCache($cacheKey, true);
$validGroupDNs[] = $dn;
} else {
@ -966,18 +976,18 @@ class Access extends LDAPUtility {
/**
* executes an LDAP search, optimized for Users
*
* @param string $filter the LDAP filter for the search
* @param string|string[] $attr optional, when a certain attribute shall be filtered out
* @param integer $limit
* @param integer $offset
* @return array with the search result
*
* Executes an LDAP search
* @throws ServerNotAvailableException
*/
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 = [];
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;
}
@ -987,12 +997,13 @@ class Access extends LDAPUtility {
* @param string|string[] $attr
* @param int $limit
* @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;
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;
}
return $result;
@ -1000,6 +1011,7 @@ class Access extends LDAPUtility {
/**
* executes an LDAP search, optimized for Groups
*
* @param string $filter the LDAP filter for the search
* @param string|string[] $attr optional, when a certain attribute shall be filtered out
* @param integer $limit
@ -1007,27 +1019,26 @@ class Access extends LDAPUtility {
* @return array with the search result
*
* 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 = [];
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;
}
/**
* 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
* @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;
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;
}
return $result;
@ -1036,14 +1047,14 @@ class Access extends LDAPUtility {
/**
* returns the number of available objects on the base DN
*
* @param int|null $limit
* @param int|null $offset
* @return int|bool
* @throws ServerNotAvailableException
*/
public function countObjects($limit = null, $offset = null) {
public function countObjects(int $limit = null, int $offset = null) {
$result = false;
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;
}
return $result;
@ -1073,27 +1084,26 @@ class Access extends LDAPUtility {
if ($command == 'controlPagedResultResponse') {
throw new \InvalidArgumentException('Invoker does not support controlPagedResultResponse, call LDAP Wrapper directly instead.');
} else {
return call_user_func_array(array($this->ldap, $command), $arguments);
return call_user_func_array([$this->ldap, $command], $arguments);
}
};
try {
$ret = $doMethod();
} catch (ServerNotAvailableException $e) {
} /** @noinspection PhpRedundantCatchClauseInspection */
catch (ServerNotAvailableException $e) {
/* Server connection lost, attempt to reestablish it
* Maybe implement exponential backoff?
* 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();
$cr = $this->connection->getConnectionResource();
if(!$this->ldap->isResource($cr)) {
// Seems like we didn't find any resource.
\OCP\Util::writeLog('user_ldap', "Could not $command, because resource is missing.", ILogger::DEBUG);
$this->logger->debug('Could not {command}, because resource is missing', ['app' => 'user_ldap', 'command' => $command]);
throw $e;
}
$arguments[0] = array_pad([], count($arguments[0]), $cr);
$ret = $doMethod();
}
return $ret;
@ -1102,8 +1112,8 @@ class Access extends LDAPUtility {
/**
* retrieved. Results will according to the order in the array.
*
* @param $filter
* @param $base
* @param string $filter
* @param string $base
* @param string[]|string|null $attr
* @param int $limit optional, maximum results to be counted
* @param int $offset optional, a starting point
@ -1111,9 +1121,9 @@ class Access extends LDAPUtility {
* second | false if not successful
* @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)) {
$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
@ -1121,30 +1131,30 @@ class Access extends LDAPUtility {
if(!$this->ldap->isResource($cr)) {
// Seems like we didn't find any resource.
// 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;
}
//check whether paged search should be attempted
$pagedSearchOK = $this->initPagedSearch($filter, $base, $attr, (int)$limit, $offset);
$linkResources = array_pad(array(), count($base), $cr);
$sr = $this->invokeLDAPMethod('search', $linkResources, $base, $filter, $attr);
$sr = $this->invokeLDAPMethod('search', $cr, $base, $filter, $attr);
// cannot use $cr anymore, might have changed in the previous call!
$error = $this->ldap->errno($this->connection->getConnectionResource());
if(!is_array($sr) || $error !== 0) {
\OCP\Util::writeLog('user_ldap', 'Attempt for Paging? '.print_r($pagedSearchOK, true), ILogger::ERROR);
if(!$this->ldap->isResource($sr) || $error !== 0) {
$this->logger->debug('Attempt for Paging? {status}', ['app' => 'user_ldap', 'status' => $pagedSearchOK]);
return false;
}
return array($sr, $pagedSearchOK);
return [$sr, $pagedSearchOK];
}
/**
* 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 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 $limit maximum results to be counted
* @param int $offset a starting point
@ -1152,15 +1162,14 @@ class Access extends LDAPUtility {
* @param bool $skipHandling required for paged search when cookies to
* prior results need to be gained
* @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;
if($pagedSearchOK) {
$cr = $this->connection->getConnectionResource();
foreach($sr as $key => $res) {
if($this->ldap->controlPagedResultResponse($cr, $res, $cookie)) {
$this->setPagedResultCookie($base[$key], $filter, $limit, $offset, $cookie);
}
if($this->ldap->controlPagedResultResponse($cr, $sr, $cookie)) {
$this->setPagedResultCookie($base, $filter, $limit, $offset, $cookie);
}
//browsing through prior pages to get the cookie for the new one
@ -1175,10 +1184,7 @@ class Access extends LDAPUtility {
}
} else {
if(!is_null($limit) && (int)$this->connection->ldapPagingSize !== 0) {
\OC::$server->getLogger()->debug(
'Paged search was not available',
[ 'app' => 'user_ldap' ]
);
$this->logger->debug('Paged search was not available', ['app' => 'user_ldap']);
}
}
/* ++ 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
* @throws ServerNotAvailableException
*/
private function count($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) {
\OCP\Util::writeLog('user_ldap', 'Count filter: '.print_r($filter, true), ILogger::DEBUG);
private function count(string $filter, string $base, $attr = null, int $limit = null, int $offset = null, bool $skipHandling = false) {
$this->logger->debug('Count filter: {filter}', ['app' => 'user_ldap', 'filter' => $filter]);
$limitPerPage = (int)$this->connection->ldapPagingSize;
if(!is_null($limit) && $limit < $limitPerPage && $limit > 0) {
@ -1268,7 +1274,7 @@ class Access extends LDAPUtility {
* @return array with the search result
* @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;
if(!is_null($limit) && $limit < $limitPerPage && $limit > 0) {
$limitPerPage = $limit;
@ -1281,7 +1287,7 @@ class Access extends LDAPUtility {
* $findings['count'] < $limit
*/
$findings = [];
$savedoffset = $offset;
$savedOffset = $offset;
do {
$search = $this->executeSearch($filter, $base, $attr, $limitPerPage, $offset);
if($search === false) {
@ -1297,7 +1303,7 @@ class Access extends LDAPUtility {
$this->processPagedSearchStatus($sr, $filter, $base, 1, $limitPerPage,
$offset, $pagedSearchOK,
$skipHandling);
return array();
return [];
}
$iFoundItems = 0;
@ -1312,13 +1318,13 @@ class Access extends LDAPUtility {
$skipHandling);
$offset += $limitPerPage;
} while ($continue && $pagedSearchOK && ($limit === null || count($findings) < $limit));
// reseting offset
$offset = $savedoffset;
// resetting offset
$offset = $savedOffset;
// if we're here, probably no connection resource is returned.
// to make Nextcloud behave nicely, we simply give back an empty array.
if(is_null($findings)) {
return array();
return [];
}
if(!is_null($attr)) {
@ -1951,14 +1957,8 @@ class Access extends LDAPUtility {
/**
* 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
if(!empty($cookie) || $cookie === '0') {
$cacheKey = 'lc' . crc32($base) . '-' . crc32($filter) . '-' . (int)$limit . '-' . (int)$offset;
@ -1979,55 +1979,55 @@ class Access extends LDAPUtility {
/**
* 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
* @param string[] $attr optional, when a certain attribute shall be filtered outside
* @param int $limit
* @param int $offset
* @return bool|true
*
* @throws ServerNotAvailableException
*/
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;
if ($limit !== 0) {
$offset = (int)$offset; //can be null
\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,
ILogger::DEBUG);
$this->logger->debug(
'initializing paged search for Filter {filter} base {base} attr {attr} limit {limit} offset {offset}',
[
'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
foreach($bases as $base) {
$cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset);
if(empty($cookie) && $cookie !== "0" && ($offset > 0)) {
// no cookie known from a potential previous search. We need
// to start from 0 to come to the desired page. cookie value
// of '0' is valid, because 389ds
$reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit;
$this->search($filter, $base, $attr, $limit, $reOffset, true);
$cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset);
if(empty($cookie) && $cookie !== "0" && ($offset > 0)) {
// no cookie known from a potential previous search. We need
// to start from 0 to come to the desired page. cookie value
// of '0' is valid, because 389ds
$reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit;
$this->search($filter, array($base), $attr, $limit, $reOffset, true);
$cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset);
//still no cookie? obviously, the server does not like us. Let's skip paging efforts.
// '0' is valid, because 389ds
//TODO: remember this, probably does not change in the next request...
if(empty($cookie) && $cookie !== '0') {
$cookie = null;
}
//still no cookie? obviously, the server does not like us. Let's skip paging efforts.
// '0' is valid, because 389ds
//TODO: remember this, probably does not change in the next request...
if(empty($cookie) && $cookie !== '0') {
$cookie = null;
}
if(!is_null($cookie)) {
//since offset = 0, this is a new search. We abandon other searches that might be ongoing.
$this->abandonPagedSearch();
$pagedSearchOK = $this->invokeLDAPMethod('controlPagedResult',
$this->connection->getConnectionResource(), $limit,
false, $cookie);
if(!$pagedSearchOK) {
return false;
}
\OCP\Util::writeLog('user_ldap', 'Ready for a paged search', ILogger::DEBUG);
} else {
$e = new \Exception('No paged search possible, Limit '.$limit.' Offset '.$offset);
\OC::$server->getLogger()->logException($e, ['level' => ILogger::DEBUG]);
}
}
if(!is_null($cookie)) {
//since offset = 0, this is a new search. We abandon other searches that might be ongoing.
$this->abandonPagedSearch();
$pagedSearchOK = $this->invokeLDAPMethod('controlPagedResult',
$this->connection->getConnectionResource(), $limit,
false, $cookie);
if(!$pagedSearchOK) {
return false;
}
$this->logger->debug('Ready for a paged search', ['app' => 'user_ldap']);
} else {
$e = new \Exception('No paged search possible, Limit '.$limit.' Offset '.$offset);
$this->logger->logException($e, ['app' => 'user_ldap', 'level' => ILogger::DEBUG]);
}
/* ++ Fixing RHDS searches with pages with zero results ++
* We coudn't get paged searches working with our RHDS for login ($limit = 0),
* due to pages with zero results.

View File

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

View File

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

View File

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

View File

@ -620,8 +620,11 @@ class User {
* called by a post_login hook to handle password expiry
*
* @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;
if (empty($ppolicyDN) || ((int)$this->connection->turnOnPasswordChange !== 1)) {
return;//password expiry handling disabled
@ -629,8 +632,8 @@ class User {
$uid = $params['uid'];
if(isset($uid) && $uid === $this->getUsername()) {
//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])) {
$pwdPolicySubentry = $result[0]['pwdpolicysubentry'];
if($pwdPolicySubentry && (count($pwdPolicySubentry) > 0)){
@ -646,7 +649,7 @@ class User {
$cacheKey = 'ppolicyAttributes' . $ppolicyDN;
$result = $this->connection->getFromCache($cacheKey);
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);
}
@ -662,10 +665,10 @@ class User {
&&($pwdGraceUseTimeCount < (int)$pwdGraceAuthNLimit[0])) { //at least one more grace login available?
$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
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
header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
'user_ldap.renewPassword.showLoginFormInvalidPassword', array('user' => $uid)));
'user_ldap.renewPassword.showLoginFormInvalidPassword', ['user' => $uid]));
}
exit();
}
@ -673,7 +676,7 @@ class User {
if($pwdReset && (count($pwdReset) > 0) && $pwdReset[0] === 'TRUE') { //user must change his password
$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
'user_ldap.renewPassword.showRenewPasswordForm', array('user' => $uid)));
'user_ldap.renewPassword.showRenewPasswordForm', ['user' => $uid]));
exit();
}
//handle password expiry warning

View File

@ -309,7 +309,7 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
* @throws \Exception
* @throws \OC\ServerNotAvailableException
*/
public function userExistsOnLDAP($user) {
public function userExistsOnLDAP($user): bool {
if(is_string($user)) {
$user = $this->access->userManager->get($user);
}
@ -319,7 +319,7 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
$dn = $user->getDN();
//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 {
$uuid = $this->access->getUserMapper()->getUUIDByDN($dn);
if (!$uuid) {
@ -327,7 +327,7 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
}
$newDn = $this->access->getUserDnByUuid($uuid);
//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;
}
$this->access->getUserMapper()->setDNbyUUID($newDn, $uuid);

View File

@ -131,11 +131,15 @@ class Wizard extends LDAPUtility {
return (string)$count;
}
/**
* @return bool|WizardResult
* @throws \Exception
*/
public function countGroups() {
$filter = $this->configuration->ldapGroupFilter;
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);
return $this->result;
}
@ -195,27 +199,28 @@ class Wizard extends LDAPUtility {
/**
* counts users with a specified attribute
* @param string $attr
* @param bool $existsCheck
*
* @return int|bool
* @throws ServerNotAvailableException
*/
public function countUsersWithAttribute($attr, $existsCheck = false) {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapBase',
'ldapUserFilter',
))) {
public function countUsersWithAttribute(string $attr, bool $existsCheck = false) {
if(!$this->checkRequirements([
'ldapHost',
'ldapPort',
'ldapBase',
'ldapUserFilter',
])) {
return false;
}
$filter = $this->access->combineFilterWithAnd(array(
$filter = $this->access->combineFilterWithAnd([
$this->configuration->ldapUserFilter,
$attr . '=*'
));
]);
$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
*/
public function detectUserDisplayNameAttribute() {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapBase',
'ldapUserFilter',
))) {
if(!$this->checkRequirements([
'ldapHost',
'ldapPort',
'ldapBase',
'ldapUserFilter',
])) {
return false;
}
@ -247,7 +253,8 @@ class Wizard extends LDAPUtility {
}
// first attribute that has at least one result wins
$displayNameAttrs = array('displayname', 'cn');
/** @noinspection SpellCheckingInspection */
$displayNameAttrs = ['displayname', 'cn'];
foreach ($displayNameAttrs as $attr) {
$count = (int)$this->countUsersWithAttribute($attr, true);
@ -267,26 +274,26 @@ class Wizard extends LDAPUtility {
* @return WizardResult|bool
*/
public function detectEmailAttribute() {
if(!$this->checkRequirements(array('ldapHost',
'ldapPort',
'ldapBase',
'ldapUserFilter',
))) {
if(!$this->checkRequirements([
'ldapHost',
'ldapPort',
'ldapBase',
'ldapUserFilter',
])) {
return false;
}
$attr = $this->configuration->ldapEmailAttribute;
$writeLog = false;
if ($attr !== '') {
$count = (int)$this->countUsersWithAttribute($attr, true);
if($count > 0) {
return false;
}
$writeLog = true;
} else {
$writeLog = false;
}
$emailAttributes = array('mail', 'mailPrimaryAddress');
$emailAttributes = ['mail', 'mailPrimaryAddress'];
$winner = '';
$maxUsers = 0;
foreach($emailAttributes as $attr) {
@ -300,9 +307,10 @@ class Wizard extends LDAPUtility {
if($winner !== '') {
$this->applyFind('ldap_email_attr', $winner);
if($writeLog) {
\OCP\Util::writeLog('user_ldap', 'The mail attribute has ' .
'automatically been reset, because the original value ' .
'did not return any results.', ILogger::INFO);
\OC::$server->getLogger()->info(
'The mail attribute has automatically been reset, because the original value did not return any results',
['app' => 'user_ldap']
);
}
}
@ -627,15 +635,14 @@ class Wizard extends LDAPUtility {
/**
* @return bool|WizardResult
* @param string $loginName
* @throws \Exception
*/
public function testLoginName($loginName) {
if(!$this->checkRequirements(array('ldapHost',
public function testLoginName(string $loginName) {
if(!$this->checkRequirements(['ldapHost',
'ldapPort',
'ldapBase',
'ldapLoginFilter',
))) {
])) {
return false;
}
@ -654,6 +661,7 @@ class Wizard extends LDAPUtility {
throw new \Exception($this->ldap->error($cr));
}
$filter = str_replace('%uid', $loginName, $this->access->connection->ldapLoginFilter);
/** @noinspection SpellCheckingInspection */
$this->result->addChange('ldap_test_loginname', $users);
$this->result->addChange('ldap_test_effective_filter', $filter);
return $this->result;
@ -832,11 +840,9 @@ class Wizard extends LDAPUtility {
/**
* 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
*/
private function testBaseDN($base) {
private function testBaseDN(string $base): bool {
$cr = $this->getConnection();
if(!$cr) {
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
//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)) {
$errorNo = $this->ldap->errno($cr);
$errorMsg = $this->ldap->error($cr);
\OCP\Util::writeLog('user_ldap', 'Wiz: Could not search base '.$base.
' Error '.$errorNo.': '.$errorMsg, ILogger::INFO);
\OC::$server->getLogger()->info(
'Wiz: Could not search base {base}, Error {errno}: {error}',
['app' => 'user_ldap', 'base' => $base, 'errno' => $errorNo, 'error' => $errorMsg]
);
return false;
}
$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
* memberOf does work.
*
* @return bool true if it does, false otherwise
* @throws ServerNotAvailableException
* @throws \Exception
*/
private function testMemberOf() {
private function testMemberOf(): bool {
$cr = $this->getConnection();
if(!$cr) {
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) {
return true;
}
@ -1131,9 +1139,9 @@ class Wizard extends LDAPUtility {
* yields most result entries
* @return array|false an array with the values on success, false otherwise
*/
public function cumulativeSearchOnAttribute($filters, $attr, $dnReadLimit = 3, &$maxF = null) {
$dnRead = array();
$foundItems = array();
public function cumulativeSearchOnAttribute(array $filters, string $attr, int $dnReadLimit = 3, string &$maxF = null) {
$dnRead = [];
$foundItems = [];
$maxEntries = 0;
if(!is_array($this->configuration->ldapBase)
|| !isset($this->configuration->ldapBase[0])) {
@ -1154,7 +1162,7 @@ class Wizard extends LDAPUtility {
continue;
}
// 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)) {
continue;
}
@ -1178,7 +1186,7 @@ class Wizard extends LDAPUtility {
if($dn === false || in_array($dn, $dnRead)) {
continue;
}
$newItems = array();
$newItems = [];
$state = $this->getAttributeValuesFromEntry($attributes,
$attr,
$newItems);
@ -1249,15 +1257,7 @@ class Wizard extends LDAPUtility {
return $availableFeatures;
}
/**
* 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) {
private function getAttributeValuesFromEntry(array $result, string $attribute, array &$known): int {
if(!is_array($result)
|| !isset($result['count'])
|| !$result['count'] > 0) {

View File

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

View File

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

View File

@ -545,7 +545,7 @@ class UserTest extends \Test\TestCase {
}
public function testUpdateAvatarThumbnailPhotoProvided() {
$this->access->expects($this->any())
$this->access->expects($this->atLeastOnce())
->method('readAttribute')
->willReturnCallback(function($dn, $attr) {
if($dn === $this->dn
@ -599,7 +599,7 @@ class UserTest extends \Test\TestCase {
}
public function testUpdateAvatarCorruptPhotoProvided() {
$this->access->expects($this->any())
$this->access->expects($this->atLeastOnce())
->method('readAttribute')
->willReturnCallback(function($dn, $attr) {
if($dn === $this->dn
@ -645,7 +645,7 @@ class UserTest extends \Test\TestCase {
}
public function testUpdateAvatarUnsupportedThumbnailPhotoProvided() {
$this->access->expects($this->any())
$this->access->expects($this->atLeastOnce())
->method('readAttribute')
->willReturnCallback(function($dn, $attr) {
if($dn === $this->dn
@ -700,7 +700,7 @@ class UserTest extends \Test\TestCase {
}
public function testUpdateAvatarNotProvided() {
$this->access->expects($this->any())
$this->access->expects($this->atLeastOnce())
->method('readAttribute')
->willReturnCallback(function($dn, $attr) {
if($dn === $this->dn
@ -962,7 +962,7 @@ class UserTest extends \Test\TestCase {
->with($this->equalTo('homeFolderNamingRule'))
->will($this->returnValue('attr:foobar'));
$this->access->expects($this->once())
$this->access->expects($this->atLeastOnce())
->method('readAttribute')
->will($this->returnValue(false));
@ -984,7 +984,7 @@ class UserTest extends \Test\TestCase {
->with($this->equalTo('homeFolderNamingRule'))
->will($this->returnValue('attr:foobar'));
$this->access->expects($this->once())
$this->access->expects($this->atLeastOnce())
->method('readAttribute')
->will($this->returnValue(false));
@ -1066,7 +1066,7 @@ class UserTest extends \Test\TestCase {
$this->access->expects($this->any())
->method('search')
->will($this->returnCallback(function($filter, $base) {
if($base === [$this->dn]) {
if($base === $this->dn) {
return [
[
'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 [
[
'pwdmaxage' => ['2592000'],
@ -1129,7 +1129,7 @@ class UserTest extends \Test\TestCase {
$this->access->expects($this->any())
->method('search')
->will($this->returnCallback(function($filter, $base) {
if($base === [$this->dn]) {
if($base === $this->dn) {
return [
[
'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 [
[
'pwdmaxage' => ['2592000'],

View File

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