From 3534f3dd7a8210575d87e537308426b2c14471d5 Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Fri, 5 Apr 2024 13:07:23 +0200 Subject: [PATCH] fix(session): Do not update authtoken last_check for passwordless Signed-off-by: Christoph Wurst --- lib/private/User/Session.php | 2 - tests/lib/User/SessionTest.php | 78 ++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index a411326c93f31..88359877d7c7f 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -757,8 +757,6 @@ private function checkTokenCredentials(IToken $dbToken, $token) { return false; } - $dbToken->setLastCheck($now); - $this->tokenProvider->updateToken($dbToken); return true; } diff --git a/tests/lib/User/SessionTest.php b/tests/lib/User/SessionTest.php index 50adda64afddd..619f6b3b8748e 100644 --- a/tests/lib/User/SessionTest.php +++ b/tests/lib/User/SessionTest.php @@ -11,9 +11,11 @@ use OC\AppFramework\Http\Request; use OC\Authentication\Events\LoginFailed; use OC\Authentication\Exceptions\InvalidTokenException; +use OC\Authentication\Exceptions\PasswordlessTokenException; use OC\Authentication\Exceptions\PasswordLoginForbiddenException; use OC\Authentication\Token\IProvider; use OC\Authentication\Token\IToken; +use OC\Authentication\Token\PublicKeyToken; use OC\Security\CSRF\CsrfTokenManager; use OC\Session\Memory; use OC\User\LoginException; @@ -35,6 +37,8 @@ use OCP\User\Events\PostLoginEvent; use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; +use function array_diff; +use function get_class_methods; /** * @group DB @@ -309,6 +313,80 @@ public function testLoginInvalidPassword() { $userSession->login('foo', 'bar'); } + public function testPasswordlessLoginNoLastCheckUpdate(): void { + $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); + $managerMethods = get_class_methods(Manager::class); + // Keep following methods intact in order to ensure hooks are working + $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']); + $manager = $this->getMockBuilder(Manager::class) + ->setMethods($mockedManagerMethods) + ->setConstructorArgs([ + $this->config, + $this->createMock(ICacheFactory::class), + $this->createMock(IEventDispatcher::class), + ]) + ->getMock(); + $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); + + $session->expects($this->never()) + ->method('set'); + $session->expects($this->once()) + ->method('regenerateId'); + $token = new PublicKeyToken(); + $token->setLoginName('foo'); + $token->setLastCheck(0); // Never + $token->setUid('foo'); + $this->tokenProvider + ->method('getPassword') + ->with($token) + ->willThrowException(new PasswordlessTokenException()); + $this->tokenProvider + ->method('getToken') + ->with('app-password') + ->willReturn($token); + $this->tokenProvider->expects(self::never()) + ->method('updateToken'); + + $userSession->login('foo', 'app-password'); + } + + public function testLoginLastCheckUpdate(): void { + $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); + $managerMethods = get_class_methods(Manager::class); + // Keep following methods intact in order to ensure hooks are working + $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']); + $manager = $this->getMockBuilder(Manager::class) + ->setMethods($mockedManagerMethods) + ->setConstructorArgs([ + $this->config, + $this->createMock(ICacheFactory::class), + $this->createMock(IEventDispatcher::class), + ]) + ->getMock(); + $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); + + $session->expects($this->never()) + ->method('set'); + $session->expects($this->once()) + ->method('regenerateId'); + $token = new PublicKeyToken(); + $token->setLoginName('foo'); + $token->setLastCheck(0); // Never + $token->setUid('foo'); + $this->tokenProvider + ->method('getPassword') + ->with($token) + ->willReturn('secret'); + $this->tokenProvider + ->method('getToken') + ->with('app-password') + ->willReturn($token); + $this->tokenProvider->expects(self::once()) + ->method('updateToken'); + + $userSession->login('foo', 'app-password'); + } + public function testLoginNonExisting() { $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); $manager = $this->createMock(Manager::class);