aboutsummaryrefslogtreecommitdiffstats
path: root/apps/user_ldap/lib/User_LDAP.php
diff options
context:
space:
mode:
Diffstat (limited to 'apps/user_ldap/lib/User_LDAP.php')
-rw-r--r--apps/user_ldap/lib/User_LDAP.php251
1 files changed, 124 insertions, 127 deletions
diff --git a/apps/user_ldap/lib/User_LDAP.php b/apps/user_ldap/lib/User_LDAP.php
index 79f230ae00b..c3f56f5ff9b 100644
--- a/apps/user_ldap/lib/User_LDAP.php
+++ b/apps/user_ldap/lib/User_LDAP.php
@@ -1,81 +1,40 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Daniel Kesselberg <mail@danielkesselberg.de>
- * @author Dominik Schmidt <dev@dominik-schmidt.de>
- * @author felixboehm <felix@webhippie.de>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Roger Szabo <roger.szabo@web.de>
- * @author root <root@localhost.localdomain>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Tom Needham <tom@owncloud.com>
- * @author Victor Dubiniuk <dubiniuk@owncloud.com>
- * @author Vinicius Cubas Brand <vinicius@eita.org.br>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
namespace OCA\User_LDAP;
use OC\ServerNotAvailableException;
use OC\User\Backend;
use OC\User\NoUserException;
use OCA\User_LDAP\Exceptions\NotOnLDAP;
+use OCA\User_LDAP\User\DeletedUsersIndex;
use OCA\User_LDAP\User\OfflineUser;
use OCA\User_LDAP\User\User;
-use OCP\IConfig;
-use OCP\ILogger;
-use OCP\IUserSession;
+use OCP\IUserBackend;
use OCP\Notification\IManager as INotificationManager;
-use OCP\Util;
-
-class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserInterface, IUserLDAP {
- /** @var \OCP\IConfig */
- protected $ocConfig;
-
- /** @var INotificationManager */
- protected $notificationManager;
-
- /** @var UserPluginManager */
- protected $userPluginManager;
-
- /**
- * @param Access $access
- * @param \OCP\IConfig $ocConfig
- * @param \OCP\Notification\IManager $notificationManager
- * @param IUserSession $userSession
- */
- public function __construct(Access $access, IConfig $ocConfig, INotificationManager $notificationManager, IUserSession $userSession, UserPluginManager $userPluginManager) {
+use OCP\User\Backend\ICountMappedUsersBackend;
+use OCP\User\Backend\ILimitAwareCountUsersBackend;
+use OCP\User\Backend\IProvideEnabledStateBackend;
+use OCP\UserInterface;
+use Psr\Log\LoggerInterface;
+
+class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, IUserLDAP, ILimitAwareCountUsersBackend, ICountMappedUsersBackend, IProvideEnabledStateBackend {
+ public function __construct(
+ Access $access,
+ protected INotificationManager $notificationManager,
+ protected UserPluginManager $userPluginManager,
+ protected LoggerInterface $logger,
+ protected DeletedUsersIndex $deletedUsersIndex,
+ ) {
parent::__construct($access);
- $this->ocConfig = $ocConfig;
- $this->notificationManager = $notificationManager;
- $this->userPluginManager = $userPluginManager;
}
/**
- * checks whether the user is allowed to change his avatar in Nextcloud
+ * checks whether the user is allowed to change their avatar in Nextcloud
*
* @param string $uid the Nextcloud user name
* @return boolean either the user can or cannot
@@ -108,11 +67,12 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
* @return string|false
* @throws \Exception
*/
- public function loginName2UserName($loginName) {
+ public function loginName2UserName($loginName, bool $forceLdapRefetch = false) {
$cacheKey = 'loginName2UserName-' . $loginName;
$username = $this->access->connection->getFromCache($cacheKey);
- if ($username !== null) {
+ $ignoreCache = ($username === false && $forceLdapRefetch);
+ if ($username !== null && !$ignoreCache) {
return $username;
}
@@ -127,13 +87,16 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
}
$username = $user->getUsername();
$this->access->connection->writeToCache($cacheKey, $username);
+ if ($forceLdapRefetch) {
+ $user->processAttributes($ldapRecord);
+ }
return $username;
} catch (NotOnLDAP $e) {
$this->access->connection->writeToCache($cacheKey, false);
return false;
}
}
-
+
/**
* returns the username for the given LDAP DN, if available
*
@@ -156,8 +119,8 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
$attrs = $this->access->userManager->getAttributes();
$users = $this->access->fetchUsersByLoginName($loginName, $attrs);
if (count($users) < 1) {
- throw new NotOnLDAP('No user available for the given login name on ' .
- $this->access->connection->ldapHost . ':' . $this->access->connection->ldapPort);
+ throw new NotOnLDAP('No user available for the given login name on '
+ . $this->access->connection->ldapHost . ':' . $this->access->connection->ldapPort);
}
return $users[0];
}
@@ -170,20 +133,19 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
* @return false|string
*/
public function checkPassword($uid, $password) {
- try {
- $ldapRecord = $this->getLDAPUserByLoginName($uid);
- } catch (NotOnLDAP $e) {
- \OC::$server->getLogger()->logException($e, ['app' => 'user_ldap', 'level' => ILogger::DEBUG]);
+ $username = $this->loginName2UserName($uid, true);
+ if ($username === false) {
return false;
}
- $dn = $ldapRecord['dn'][0];
+ $dn = $this->access->username2dn($username);
$user = $this->access->userManager->get($dn);
if (!$user instanceof User) {
- Util::writeLog('user_ldap',
- 'LDAP Login: Could not get user object for DN ' . $dn .
- '. Maybe the LDAP entry has no set display name attribute?',
- ILogger::WARN);
+ $this->logger->warning(
+ 'LDAP Login: Could not get user object for DN ' . $dn
+ . '. Maybe the LDAP entry has no set display name attribute?',
+ ['app' => 'user_ldap']
+ );
return false;
}
if ($user->getUsername() !== false) {
@@ -193,7 +155,6 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
}
$this->access->cacheUserExists($user->getUsername());
- $user->processAttributes($ldapRecord);
$user->markLogin();
return $user->getUsername();
@@ -216,8 +177,8 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
$user = $this->access->userManager->get($uid);
if (!$user instanceof User) {
- throw new \Exception('LDAP setPassword: Could not get user object for uid ' . $uid .
- '. Maybe the LDAP entry has no set display name attribute?');
+ throw new \Exception('LDAP setPassword: Could not get user object for uid ' . $uid
+ . '. Maybe the LDAP entry has no set display name attribute?');
}
if ($user->getUsername() !== false && $this->access->setPassword($user->getDN(), $password)) {
$ldapDefaultPPolicyDN = $this->access->connection->ldapDefaultPPolicyDN;
@@ -247,7 +208,7 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
*/
public function getUsers($search = '', $limit = 10, $offset = 0) {
$search = $this->access->escapeFilterPart($search, true);
- $cachekey = 'getUsers-'.$search.'-'.$limit.'-'.$offset;
+ $cachekey = 'getUsers-' . $search . '-' . $limit . '-' . $offset;
//check if users are cached, if so return
$ldap_users = $this->access->connection->getFromCache($cachekey);
@@ -266,16 +227,20 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
$this->access->getFilterPartForUserSearch($search)
]);
- Util::writeLog('user_ldap',
- 'getUsers: Options: search '.$search.' limit '.$limit.' offset '.$offset.' Filter: '.$filter,
- ILogger::DEBUG);
+ $this->logger->debug(
+ 'getUsers: Options: search ' . $search . ' limit ' . $limit . ' offset ' . $offset . ' Filter: ' . $filter,
+ ['app' => 'user_ldap']
+ );
//do the search and translate results to Nextcloud names
$ldap_users = $this->access->fetchListOfUsers(
$filter,
$this->access->userManager->getAttributes(true),
$limit, $offset);
$ldap_users = $this->access->nextcloudUserNames($ldap_users);
- Util::writeLog('user_ldap', 'getUsers: '.count($ldap_users). ' Users found', ILogger::DEBUG);
+ $this->logger->debug(
+ 'getUsers: ' . count($ldap_users) . ' Users found',
+ ['app' => 'user_ldap']
+ );
$this->access->connection->writeToCache($cachekey, $ldap_users);
return $ldap_users;
@@ -284,13 +249,12 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
/**
* checks whether a user is still available on LDAP
*
- * @param string|\OCA\User_LDAP\User\User $user either the Nextcloud user
- * name or an instance of that user
- * @return bool
+ * @param string|User $user either the Nextcloud user
+ * name or an instance of that user
* @throws \Exception
* @throws \OC\ServerNotAvailableException
*/
- public function userExistsOnLDAP($user) {
+ public function userExistsOnLDAP($user, bool $ignoreCache = false): bool {
if (is_string($user)) {
$user = $this->access->userManager->get($user);
}
@@ -299,9 +263,11 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
}
$uid = $user instanceof User ? $user->getUsername() : $user->getOCName();
$cacheKey = 'userExistsOnLDAP' . $uid;
- $userExists = $this->access->connection->getFromCache($cacheKey);
- if (!is_null($userExists)) {
- return (bool)$userExists;
+ if (!$ignoreCache) {
+ $userExists = $this->access->connection->getFromCache($cacheKey);
+ if (!is_null($userExists)) {
+ return (bool)$userExists;
+ }
}
$dn = $user->getDN();
@@ -320,8 +286,6 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
return false;
}
$this->access->getUserMapper()->setDNbyUUID($newDn, $uuid);
- $this->access->connection->writeToCache($cacheKey, true);
- return true;
} catch (ServerNotAvailableException $e) {
throw $e;
} catch (\Exception $e) {
@@ -345,21 +309,22 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
* @throws \Exception when connection could not be established
*/
public function userExists($uid) {
- $userExists = $this->access->connection->getFromCache('userExists'.$uid);
+ $userExists = $this->access->connection->getFromCache('userExists' . $uid);
if (!is_null($userExists)) {
return (bool)$userExists;
}
- //getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking.
- $user = $this->access->userManager->get($uid);
+ $userExists = $this->access->userManager->exists($uid);
- if (is_null($user)) {
- Util::writeLog('user_ldap', 'No DN found for '.$uid.' on '.
- $this->access->connection->ldapHost, ILogger::DEBUG);
- $this->access->connection->writeToCache('userExists'.$uid, false);
+ if (!$userExists) {
+ $this->logger->debug(
+ 'No DN found for ' . $uid . ' on ' . $this->access->connection->ldapHost,
+ ['app' => 'user_ldap']
+ );
+ $this->access->connection->writeToCache('userExists' . $uid, false);
return false;
}
- $this->access->connection->writeToCache('userExists'.$uid, true);
+ $this->access->connection->writeToCache('userExists' . $uid, true);
return true;
}
@@ -377,14 +342,29 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
}
}
- $marked = $this->ocConfig->getUserValue($uid, 'user_ldap', 'isDeleted', 0);
- if ((int)$marked === 0) {
- \OC::$server->getLogger()->notice(
- 'User '.$uid . ' is not marked as deleted, not cleaning up.',
- ['app' => 'user_ldap']);
- return false;
+ $marked = $this->deletedUsersIndex->isUserMarked($uid);
+ if (!$marked) {
+ try {
+ $user = $this->access->userManager->get($uid);
+ if (($user instanceof User) && !$this->userExistsOnLDAP($uid, true)) {
+ $user->markUser();
+ $marked = true;
+ }
+ } catch (\Exception $e) {
+ $this->logger->debug(
+ $e->getMessage(),
+ ['app' => 'user_ldap', 'exception' => $e]
+ );
+ }
+ if (!$marked) {
+ $this->logger->notice(
+ 'User ' . $uid . ' is not marked as deleted, not cleaning up.',
+ ['app' => 'user_ldap']
+ );
+ return false;
+ }
}
- \OC::$server->getLogger()->info('Cleaning up after user ' . $uid,
+ $this->logger->info('Cleaning up after user ' . $uid,
['app' => 'user_ldap']);
$this->access->getUserMapper()->unmap($uid); // we don't emit unassign signals here, since it is implicit to delete signals fired from core
@@ -411,7 +391,7 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
return $this->userPluginManager->getHome($uid);
}
- $cacheKey = 'getHome'.$uid;
+ $cacheKey = 'getHome' . $uid;
$path = $this->access->connection->getFromCache($cacheKey);
if (!is_null($path)) {
return $path;
@@ -443,7 +423,7 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
return false;
}
- $cacheKey = 'getDisplayName'.$uid;
+ $cacheKey = 'getDisplayName' . $uid;
if (!is_null($displayName = $this->access->connection->getFromCache($cacheKey))) {
return $displayName;
}
@@ -470,11 +450,10 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
$user = $this->access->userManager->get($uid);
if ($user instanceof User) {
- $displayName = $user->composeAndStoreDisplayName($displayName, $displayName2);
+ $displayName = $user->composeAndStoreDisplayName($displayName, (string)$displayName2);
$this->access->connection->writeToCache($cacheKey, $displayName);
}
if ($user instanceof OfflineUser) {
- /** @var OfflineUser $user*/
$displayName = $user->getDisplayName();
}
return $displayName;
@@ -502,12 +481,12 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
* Get a list of all display names
*
* @param string $search
- * @param string|null $limit
- * @param string|null $offset
+ * @param int|null $limit
+ * @param int|null $offset
* @return array an array of all displayNames (value) and the corresponding uids (key)
*/
public function getDisplayNames($search = '', $limit = null, $offset = null) {
- $cacheKey = 'getDisplayNames-'.$search.'-'.$limit.'-'.$offset;
+ $cacheKey = 'getDisplayNames-' . $search . '-' . $limit . '-' . $offset;
if (!is_null($displayNames = $this->access->connection->getFromCache($cacheKey))) {
return $displayNames;
}
@@ -549,24 +528,26 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
/**
* counts the users in LDAP
- *
- * @return int|bool
*/
- public function countUsers() {
+ public function countUsers(int $limit = 0): int|false {
if ($this->userPluginManager->implementsActions(Backend::COUNT_USERS)) {
return $this->userPluginManager->countUsers();
}
$filter = $this->access->getFilterForUserCount();
- $cacheKey = 'countUsers-'.$filter;
+ $cacheKey = 'countUsers-' . $filter . '-' . $limit;
if (!is_null($entries = $this->access->connection->getFromCache($cacheKey))) {
return $entries;
}
- $entries = $this->access->countUsers($filter);
+ $entries = $this->access->countUsers($filter, limit:$limit);
$this->access->connection->writeToCache($cacheKey, $entries);
return $entries;
}
+ public function countMappedUsers(): int {
+ return $this->access->getUserMapper()->count();
+ }
+
/**
* Backend name to be shown in user management
* @return string the name of the backend to be shown
@@ -574,7 +555,7 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
public function getBackendName() {
return 'LDAP';
}
-
+
/**
* Return access for LDAP interaction.
* @param string $uid
@@ -583,13 +564,13 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
public function getLDAPAccess($uid) {
return $this->access;
}
-
+
/**
* Return LDAP connection resource from a cloned connection.
* The cloned connection needs to be closed manually.
* of the current access.
* @param string $uid
- * @return resource of the LDAP connection
+ * @return \LDAP\Connection The LDAP connection
*/
public function getNewLDAPConnection($uid) {
$connection = clone $this->access->getConnection();
@@ -617,9 +598,8 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
$uuid,
true
);
- $this->access->cacheUserExists($username);
} else {
- \OC::$server->getLogger()->warning(
+ $this->logger->warning(
'Failed to map created LDAP user with userid {userid}, because UUID could not be determined',
[
'app' => 'user_ldap',
@@ -628,11 +608,28 @@ class User_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
);
}
} else {
- throw new \UnexpectedValueException("LDAP Plugin: Method createUser changed to return the user DN instead of boolean.");
+ throw new \UnexpectedValueException('LDAP Plugin: Method createUser changed to return the user DN instead of boolean.');
}
}
- return (bool) $dn;
+ return (bool)$dn;
}
return false;
}
+
+ public function isUserEnabled(string $uid, callable $queryDatabaseValue): bool {
+ if ($this->deletedUsersIndex->isUserMarked($uid) && ((int)$this->access->connection->markRemnantsAsDisabled === 1)) {
+ return false;
+ } else {
+ return $queryDatabaseValue();
+ }
+ }
+
+ public function setUserEnabled(string $uid, bool $enabled, callable $queryDatabaseValue, callable $setDatabaseValue): bool {
+ $setDatabaseValue($enabled);
+ return $enabled;
+ }
+
+ public function getDisabledUserList(?int $limit = null, int $offset = 0, string $search = ''): array {
+ throw new \Exception('This is implemented directly in User_Proxy');
+ }
}