diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index 5c899b7892f21..2dc37f97b0bf7 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -9,6 +9,7 @@ use OC\Hooks\PublicEmitter; use OC\Memcache\WithLocalCache; +use OC\ServerNotAvailableException; use OCP\Config\IUserConfig; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\EventDispatcher\IEventDispatcher; @@ -231,7 +232,12 @@ public function checkPasswordNoLogging($loginName, $password) { foreach ($backends as $backend) { if ($backend instanceof ICheckPasswordBackend || $backend->implementsActions(Backend::CHECK_PASSWORD)) { /** @var ICheckPasswordBackend $backend */ - $uid = $backend->checkPassword($loginName, $password); + try { + $uid = $backend->checkPassword($loginName, $password); + } catch (ServerNotAvailableException $e) { + $this->logger->warning('Unable to check password against user backend: ' . ($backend instanceof IUserBackend ? $backend->getBackendName() : get_class($backend)), ['exception' => $e]); + continue; + } if ($uid !== false) { return $this->getUserObject($uid, $backend); } @@ -246,7 +252,12 @@ public function checkPasswordNoLogging($loginName, $password) { foreach ($backends as $backend) { if ($backend instanceof ICheckPasswordBackend || $backend->implementsActions(Backend::CHECK_PASSWORD)) { /** @var ICheckPasswordBackend|UserInterface $backend */ - $uid = $backend->checkPassword($loginName, $password); + try { + $uid = $backend->checkPassword($loginName, $password); + } catch (ServerNotAvailableException $e) { + $this->logger->warning('Unable to check password against user backend: ' . ($backend instanceof IUserBackend ? $backend->getBackendName() : get_class($backend)), ['exception' => $e]); + continue; + } if ($uid !== false) { return $this->getUserObject($uid, $backend); } diff --git a/tests/lib/User/ManagerTest.php b/tests/lib/User/ManagerTest.php index f606ac4d80503..0c86a4ca043c9 100644 --- a/tests/lib/User/ManagerTest.php +++ b/tests/lib/User/ManagerTest.php @@ -9,6 +9,7 @@ namespace Test\User; use OC\AllConfig; +use OC\ServerNotAvailableException; use OC\USER\BACKEND; use OC\User\Database; use OC\User\Manager; @@ -165,6 +166,60 @@ public function testCheckPassword(): void { $this->assertTrue($user instanceof User); } + public function testCheckPasswordNoLoggingContinuesAfterUnavailableBackend(): void { + $exception = new ServerNotAvailableException(); + $unavailableBackend = $this->createMock(\Test\Util\User\Dummy::class); + $unavailableBackend->expects($this->once()) + ->method('checkPassword') + ->with('foo', 'bar') + ->willThrowException($exception); + $unavailableBackend->method('implementsActions') + ->with(BACKEND::CHECK_PASSWORD) + ->willReturn(true); + $unavailableBackend->method('getBackendName') + ->willReturn('Dummy'); + + $databaseBackend = $this->createMock(Database::class); + $databaseBackend->expects($this->once()) + ->method('checkPassword') + ->with('foo', 'bar') + ->willReturn('foo'); + + $this->logger->expects($this->once()) + ->method('warning') + ->with('Unable to check password against user backend: Dummy', ['exception' => $exception]); + + $manager = new Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); + $manager->registerBackend($unavailableBackend); + $manager->registerBackend($databaseBackend); + + $user = $manager->checkPasswordNoLogging('foo', 'bar'); + $this->assertInstanceOf(User::class, $user); + $this->assertSame('foo', $user->getUID()); + } + + public function testCheckPasswordNoLoggingReturnsFalseForUnavailableBackend(): void { + $exception = new ServerNotAvailableException(); + $backend = $this->createMock(\Test\Util\User\Dummy::class); + $backend->method('checkPassword') + ->with('foo', 'bar') + ->willThrowException($exception); + $backend->method('implementsActions') + ->with(BACKEND::CHECK_PASSWORD) + ->willReturn(true); + $backend->method('getBackendName') + ->willReturn('Dummy'); + + $this->logger->expects($this->atLeastOnce()) + ->method('warning') + ->with('Unable to check password against user backend: Dummy', ['exception' => $exception]); + + $manager = new Manager($this->config, $this->cacheFactory, $this->eventDispatcher, $this->logger); + $manager->registerBackend($backend); + + $this->assertFalse($manager->checkPasswordNoLogging('foo', 'bar')); + } + public function testCheckPasswordNotSupported(): void { $backend = $this->createMock(\Test\Util\User\Dummy::class); $backend->expects($this->never())