From 8de7d5d2fd3ae263c9c0e23d834444969eb2332d Mon Sep 17 00:00:00 2001 From: Louis Chemineau Date: Fri, 20 Sep 2024 11:26:22 +0200 Subject: [PATCH] fix(users): Don't crash if disabled user is missing in the database Signed-off-by: Louis Chemineau --- lib/private/User/LazyUser.php | 9 ++-- lib/private/User/Manager.php | 18 ++++--- tests/lib/Files/Config/UserMountCacheTest.php | 2 +- .../Files/Storage/Wrapper/EncryptionTest.php | 9 ++-- tests/lib/Files/Stream/EncryptionTest.php | 4 +- tests/lib/User/ManagerTest.php | 52 ++++++++++--------- tests/lib/User/SessionTest.php | 9 ++++ 7 files changed, 65 insertions(+), 38 deletions(-) diff --git a/lib/private/User/LazyUser.php b/lib/private/User/LazyUser.php index cd3e268be48bc..92a0c73521514 100644 --- a/lib/private/User/LazyUser.php +++ b/lib/private/User/LazyUser.php @@ -36,9 +36,12 @@ private function getUser(): IUser { $this->user = $this->userManager->get($this->uid); } } - /** @var IUser */ - $user = $this->user; - return $user; + + if ($this->user === null) { + throw new NoUserException('User not found in backend'); + } + + return $this->user; } public function getUID() { diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index e21759b1e9865..3ee748a277577 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -68,6 +68,7 @@ public function __construct( private IConfig $config, ICacheFactory $cacheFactory, private IEventDispatcher $eventDispatcher, + private LoggerInterface $logger, ) { $this->cache = new WithLocalCache($cacheFactory->createDistributed('user_backend_map')); $this->listen('\OC\User', 'postDelete', function (IUser $user): void { @@ -201,7 +202,7 @@ public function checkPassword($loginName, $password) { $result = $this->checkPasswordNoLogging($loginName, $password); if ($result === false) { - \OCP\Server::get(LoggerInterface::class)->warning('Login failed: \'' . $loginName . '\' (Remote IP: \'' . \OC::$server->getRequest()->getRemoteAddress() . '\')', ['app' => 'core']); + $this->logger->warning('Login failed: \'' . $loginName . '\' (Remote IP: \'' . \OC::$server->getRequest()->getRemoteAddress() . '\')', ['app' => 'core']); } return $result; @@ -319,11 +320,16 @@ public function getDisabledUsers(?int $limit = null, int $offset = 0, string $se if ($search !== '') { $users = array_filter( $users, - fn (IUser $user): bool => - mb_stripos($user->getUID(), $search) !== false || - mb_stripos($user->getDisplayName(), $search) !== false || - mb_stripos($user->getEMailAddress() ?? '', $search) !== false, - ); + function (IUser $user) use ($search): bool { + try { + return mb_stripos($user->getUID(), $search) !== false || + mb_stripos($user->getDisplayName(), $search) !== false || + mb_stripos($user->getEMailAddress() ?? '', $search) !== false; + } catch (NoUserException $ex) { + $this->logger->error('Error while filtering disabled users', ['exception' => $ex, 'userUID' => $user->getUID()]); + return false; + } + }); } $tempLimit = ($limit === null ? null : $limit + $offset); diff --git a/tests/lib/Files/Config/UserMountCacheTest.php b/tests/lib/Files/Config/UserMountCacheTest.php index 29f9334ae1598..30c64bf20fad6 100644 --- a/tests/lib/Files/Config/UserMountCacheTest.php +++ b/tests/lib/Files/Config/UserMountCacheTest.php @@ -62,7 +62,7 @@ protected function setUp(): void { ->expects($this->any()) ->method('getAppValue') ->willReturnArgument(2); - $this->userManager = new Manager($config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class)); + $this->userManager = new Manager($config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), $this->createMock(LoggerInterface::class)); $userBackend = new Dummy(); $userBackend->createUser('u1', ''); $userBackend->createUser('u2', ''); diff --git a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php index 851182ab3ebfc..a2949938410bb 100644 --- a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php +++ b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php @@ -137,7 +137,8 @@ protected function setUp(): void { ->setConstructorArgs([new View(), new Manager( $this->config, $this->createMock(ICacheFactory::class), - $this->createMock(IEventDispatcher::class) + $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ), $this->groupManager, $this->config, $this->arrayCache]) ->getMock(); $this->util->expects($this->any()) @@ -577,7 +578,8 @@ public function testGetHeader($path, $strippedPathExists, $strippedPath): void { new Manager( $this->config, $this->createMock(ICacheFactory::class), - $this->createMock(IEventDispatcher::class) + $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ), $this->groupManager, $this->config, @@ -659,7 +661,8 @@ public function testGetHeaderAddLegacyModule($header, $isEncrypted, $exists, $ex ->setConstructorArgs([new View(), new Manager( $this->config, $this->createMock(ICacheFactory::class), - $this->createMock(IEventDispatcher::class) + $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ), $this->groupManager, $this->config, $this->arrayCache]) ->getMock(); diff --git a/tests/lib/Files/Stream/EncryptionTest.php b/tests/lib/Files/Stream/EncryptionTest.php index c29a38f2b098a..419c1a752d093 100644 --- a/tests/lib/Files/Stream/EncryptionTest.php +++ b/tests/lib/Files/Stream/EncryptionTest.php @@ -13,6 +13,7 @@ use OCP\Files\Cache\ICache; use OCP\ICacheFactory; use OCP\IConfig; +use Psr\Log\LoggerInterface; class EncryptionTest extends \Test\TestCase { public const DEFAULT_WRAPPER = '\OC\Files\Stream\Encryption'; @@ -57,7 +58,8 @@ protected function getStream($fileName, $mode, $unencryptedSize, $wrapper = self ->setConstructorArgs([new View(), new \OC\User\Manager( $config, $this->createMock(ICacheFactory::class), - $this->createMock(IEventDispatcher::class) + $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ), $groupManager, $config, $arrayCache]) ->getMock(); $util->expects($this->any()) diff --git a/tests/lib/User/ManagerTest.php b/tests/lib/User/ManagerTest.php index 302cba4ea2b8d..07bc0eac541aa 100644 --- a/tests/lib/User/ManagerTest.php +++ b/tests/lib/User/ManagerTest.php @@ -16,6 +16,7 @@ use OCP\ICacheFactory; use OCP\IConfig; use OCP\IUser; +use Psr\Log\LoggerInterface; use Test\TestCase; /** @@ -34,6 +35,8 @@ class ManagerTest extends TestCase { private $cacheFactory; /** @var ICache */ private $cache; + /** @var LoggerInterface */ + private $logger; protected function setUp(): void { parent::setUp(); @@ -42,6 +45,7 @@ protected function setUp(): void { $this->eventDispatcher = $this->createMock(IEventDispatcher::class); $this->cacheFactory = $this->createMock(ICacheFactory::class); $this->cache = $this->createMock(ICache::class); + $this->logger = $this->createMock(LoggerInterface::class); $this->cacheFactory->method('createDistributed') ->willReturn($this->cache); @@ -49,7 +53,7 @@ protected function setUp(): void { public function testGetBackends(): void { $userDummyBackend = $this->createMock(\Test\Util\User\Dummy::class); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($userDummyBackend); $this->assertEquals([$userDummyBackend], $manager->getBackends()); $dummyDatabaseBackend = $this->createMock(Database::class); @@ -68,7 +72,7 @@ public function testUserExistsSingleBackendExists(): void { ->with($this->equalTo('foo')) ->willReturn(true); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $this->assertTrue($manager->userExists('foo')); @@ -84,14 +88,14 @@ public function testUserExistsSingleBackendNotExists(): void { ->with($this->equalTo('foo')) ->willReturn(false); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $this->assertFalse($manager->userExists('foo')); } public function testUserExistsNoBackends(): void { - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $this->assertFalse($manager->userExists('foo')); } @@ -115,7 +119,7 @@ public function testUserExistsTwoBackendsSecondExists(): void { ->with($this->equalTo('foo')) ->willReturn(true); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend1); $manager->registerBackend($backend2); @@ -139,7 +143,7 @@ public function testUserExistsTwoBackendsFirstExists(): void { $backend2->expects($this->never()) ->method('userExists'); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend1); $manager->registerBackend($backend2); @@ -166,7 +170,7 @@ public function testCheckPassword(): void { } }); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $user = $manager->checkPassword('foo', 'bar'); @@ -185,7 +189,7 @@ public function testCheckPasswordNotSupported(): void { ->method('implementsActions') ->willReturn(false); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $this->assertFalse($manager->checkPassword('foo', 'bar')); @@ -203,7 +207,7 @@ public function testGetOneBackendExists(): void { $backend->expects($this->never()) ->method('loginName2UserName'); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $this->assertEquals('foo', $manager->get('foo')->getUID()); @@ -219,7 +223,7 @@ public function testGetOneBackendNotExists(): void { ->with($this->equalTo('foo')) ->willReturn(false); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $this->assertEquals(null, $manager->get('foo')); @@ -237,7 +241,7 @@ public function testGetOneBackendDoNotTranslateLoginNames(): void { $backend->expects($this->never()) ->method('loginName2UserName'); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $this->assertEquals('bLeNdEr', $manager->get('bLeNdEr')->getUID()); @@ -255,7 +259,7 @@ public function testSearchOneBackend(): void { $backend->expects($this->never()) ->method('loginName2UserName'); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $result = $manager->search('fo'); @@ -289,7 +293,7 @@ public function testSearchTwoBackendLimitOffset(): void { $backend2->expects($this->never()) ->method('loginName2UserName'); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend1); $manager->registerBackend($backend2); @@ -343,7 +347,7 @@ public function testCreateUserInvalid($uid, $password, $exception): void { ->willReturn(true); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $this->expectException(\InvalidArgumentException::class, $exception); @@ -370,7 +374,7 @@ public function testCreateUserSingleBackendNotExists(): void { $backend->expects($this->never()) ->method('loginName2UserName'); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $user = $manager->createUser('foo', 'bar'); @@ -397,7 +401,7 @@ public function testCreateUserSingleBackendExists(): void { ->with($this->equalTo('foo')) ->willReturn(true); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $manager->createUser('foo', 'bar'); @@ -418,14 +422,14 @@ public function testCreateUserSingleBackendNotSupported(): void { $backend->expects($this->never()) ->method('userExists'); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $this->assertFalse($manager->createUser('foo', 'bar')); } public function testCreateUserNoBackends(): void { - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $this->assertFalse($manager->createUser('foo', 'bar')); } @@ -485,7 +489,7 @@ public function testCreateUserTwoBackendExists(): void { ->with($this->equalTo('foo')) ->willReturn(true); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend1); $manager->registerBackend($backend2); @@ -493,7 +497,7 @@ public function testCreateUserTwoBackendExists(): void { } public function testCountUsersNoBackend(): void { - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $result = $manager->countUsers(); $this->assertTrue(is_array($result)); @@ -518,7 +522,7 @@ public function testCountUsersOneBackend(): void { ->method('getBackendName') ->willReturn('Mock_Test_Util_User_Dummy'); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $result = $manager->countUsers(); @@ -559,7 +563,7 @@ public function testCountUsersTwoBackends(): void { ->method('getBackendName') ->willReturn('Mock_Test_Util_User_Dummy'); - $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend1); $manager->registerBackend($backend2); @@ -672,7 +676,7 @@ public function testDeleteUser(): void { ->method('getAppValue') ->willReturnArgument(2); - $manager = new \OC\User\Manager($config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $backend = new \Test\Util\User\Dummy(); $manager->registerBackend($backend); @@ -706,7 +710,7 @@ public function testGetByEmail(): void { true ); - $manager = new \OC\User\Manager($config, $this->cacheFactory, $this->eventDispatcher); + $manager = new \OC\User\Manager($config, $this->cacheFactory, $this->eventDispatcher, $this->logger); $manager->registerBackend($backend); $users = $manager->getByEmail('test@example.com'); diff --git a/tests/lib/User/SessionTest.php b/tests/lib/User/SessionTest.php index fad5d11565c00..b3f040d71ec6f 100644 --- a/tests/lib/User/SessionTest.php +++ b/tests/lib/User/SessionTest.php @@ -181,6 +181,7 @@ public function testLoginValidPasswordEnabled(): void { $this->config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); @@ -247,6 +248,7 @@ public function testLoginValidPasswordDisabled(): void { $this->config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); @@ -280,6 +282,7 @@ public function testLoginInvalidPassword(): void { $this->config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); $backend = $this->createMock(\Test\Util\User\Dummy::class); @@ -323,6 +326,7 @@ public function testPasswordlessLoginNoLastCheckUpdate(): void { $this->config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); @@ -360,6 +364,7 @@ public function testLoginLastCheckUpdate(): void { $this->config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); @@ -617,6 +622,7 @@ public function testRememberLoginValidToken(): void { $this->config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); $userSession = $this->getMockBuilder(Session::class) @@ -706,6 +712,7 @@ public function testRememberLoginInvalidSessionToken(): void { $this->config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); $userSession = $this->getMockBuilder(Session::class) @@ -770,6 +777,7 @@ public function testRememberLoginInvalidToken(): void { $this->config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); $userSession = $this->getMockBuilder(Session::class) @@ -822,6 +830,7 @@ public function testRememberLoginInvalidUser(): void { $this->config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); $userSession = $this->getMockBuilder(Session::class)