diff options
Diffstat (limited to 'apps/user_ldap/lib/User_LDAP.php')
-rw-r--r-- | apps/user_ldap/lib/User_LDAP.php | 194 |
1 files changed, 80 insertions, 114 deletions
diff --git a/apps/user_ldap/lib/User_LDAP.php b/apps/user_ldap/lib/User_LDAP.php index 5a445100052..c3f56f5ff9b 100644 --- a/apps/user_ldap/lib/User_LDAP.php +++ b/apps/user_ldap/lib/User_LDAP.php @@ -1,40 +1,9 @@ <?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; @@ -42,45 +11,30 @@ 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\IUserSession; -use OCP\Notification\IManager as INotificationManager; -use OCP\User\Backend\ICountUsersBackend; use OCP\IUserBackend; +use OCP\Notification\IManager as INotificationManager; +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, ICountUsersBackend { - /** @var \OCP\IConfig */ - protected $ocConfig; - - /** @var INotificationManager */ - protected $notificationManager; - - /** @var UserPluginManager */ - protected $userPluginManager; - - /** @var LoggerInterface */ - protected $logger; - - /** - * @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) { +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; - $this->logger = \OC::$server->get(LoggerInterface::class); } /** - * 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 @@ -113,11 +67,12 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I * @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; } @@ -132,6 +87,9 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I } $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); @@ -161,8 +119,8 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I $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]; } @@ -175,22 +133,17 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I * @return false|string */ public function checkPassword($uid, $password) { - try { - $ldapRecord = $this->getLDAPUserByLoginName($uid); - } catch (NotOnLDAP $e) { - $this->logger->debug( - $e->getMessage(), - ['app' => 'user_ldap', 'exception' => $e] - ); + $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) { $this->logger->warning( - 'LDAP Login: Could not get user object for DN ' . $dn . - '. Maybe the LDAP entry has no set display name attribute?', + '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; @@ -202,7 +155,6 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I } $this->access->cacheUserExists($user->getUsername()); - $user->processAttributes($ldapRecord); $user->markLogin(); return $user->getUsername(); @@ -225,8 +177,8 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I $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; @@ -256,7 +208,7 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I */ 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); @@ -276,7 +228,7 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I ]); $this->logger->debug( - 'getUsers: Options: search '.$search.' limit '.$limit.' offset '.$offset.' Filter: '.$filter, + 'getUsers: Options: search ' . $search . ' limit ' . $limit . ' offset ' . $offset . ' Filter: ' . $filter, ['app' => 'user_ldap'] ); //do the search and translate results to Nextcloud names @@ -286,7 +238,7 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I $limit, $offset); $ldap_users = $this->access->nextcloudUserNames($ldap_users); $this->logger->debug( - 'getUsers: '.count($ldap_users). ' Users found', + 'getUsers: ' . count($ldap_users) . ' Users found', ['app' => 'user_ldap'] ); @@ -297,8 +249,8 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I /** * 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 + * @param string|User $user either the Nextcloud user + * name or an instance of that user * @throws \Exception * @throws \OC\ServerNotAvailableException */ @@ -334,8 +286,6 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I return false; } $this->access->getUserMapper()->setDNbyUUID($newDn, $uuid); - $this->access->connection->writeToCache($cacheKey, true); - return true; } catch (ServerNotAvailableException $e) { throw $e; } catch (\Exception $e) { @@ -359,23 +309,22 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I * @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)) { + if (!$userExists) { $this->logger->debug( - 'No DN found for '.$uid.' on '.$this->access->connection->ldapHost, + 'No DN found for ' . $uid . ' on ' . $this->access->connection->ldapHost, ['app' => 'user_ldap'] ); - $this->access->connection->writeToCache('userExists'.$uid, false); + $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; } @@ -393,13 +342,13 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I } } - $marked = (int)$this->ocConfig->getUserValue($uid, 'user_ldap', 'isDeleted', 0); - if ($marked === 0) { + $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 = 1; + $marked = true; } } catch (\Exception $e) { $this->logger->debug( @@ -407,9 +356,9 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I ['app' => 'user_ldap', 'exception' => $e] ); } - if ($marked === 0) { + if (!$marked) { $this->logger->notice( - 'User '.$uid . ' is not marked as deleted, not cleaning up.', + 'User ' . $uid . ' is not marked as deleted, not cleaning up.', ['app' => 'user_ldap'] ); return false; @@ -442,7 +391,7 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I return $this->userPluginManager->getHome($uid); } - $cacheKey = 'getHome'.$uid; + $cacheKey = 'getHome' . $uid; $path = $this->access->connection->getFromCache($cacheKey); if (!is_null($path)) { return $path; @@ -474,7 +423,7 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I return false; } - $cacheKey = 'getDisplayName'.$uid; + $cacheKey = 'getDisplayName' . $uid; if (!is_null($displayName = $this->access->connection->getFromCache($cacheKey))) { return $displayName; } @@ -501,11 +450,10 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I $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; @@ -538,7 +486,7 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I * @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; } @@ -580,24 +528,26 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I /** * 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 @@ -620,7 +570,7 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I * The cloned connection needs to be closed manually. * of the current access. * @param string $uid - * @return resource|\LDAP\Connection The LDAP connection + * @return \LDAP\Connection The LDAP connection */ public function getNewLDAPConnection($uid) { $connection = clone $this->access->getConnection(); @@ -648,7 +598,6 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I $uuid, true ); - $this->access->cacheUserExists($username); } else { $this->logger->warning( 'Failed to map created LDAP user with userid {userid}, because UUID could not be determined', @@ -659,11 +608,28 @@ class User_LDAP extends BackendUtility implements IUserBackend, UserInterface, I ); } } 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'); + } } |