diff options
Diffstat (limited to 'tests/lib/User/SessionTest.php')
-rw-r--r-- | tests/lib/User/SessionTest.php | 945 |
1 files changed, 397 insertions, 548 deletions
diff --git a/tests/lib/User/SessionTest.php b/tests/lib/User/SessionTest.php index 8f72ba06b92..50c449559a0 100644 --- a/tests/lib/User/SessionTest.php +++ b/tests/lib/User/SessionTest.php @@ -1,20 +1,24 @@ <?php + /** - * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\User; use OC\AppFramework\Http\Request; -use OC\Authentication\Token\DefaultTokenMapper; -use OC\Authentication\Token\DefaultTokenProvider; +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\Security\Bruteforce\Throttler; +use OC\Authentication\Token\PublicKeyToken; +use OC\Security\CSRF\CsrfTokenManager; use OC\Session\Memory; +use OC\User\LoginException; use OC\User\Manager; use OC\User\Session; use OC\User\User; @@ -23,17 +27,19 @@ use OCP\AppFramework\Utility\ITimeFactory; use OCP\EventDispatcher\IEventDispatcher; use OCP\ICacheFactory; use OCP\IConfig; -use OCP\ILogger; use OCP\IRequest; +use OCP\IRequestId; use OCP\ISession; use OCP\IUser; use OCP\Lockdown\ILockdownManager; -use OCP\Security\ICrypto; +use OCP\Security\Bruteforce\IThrottler; use OCP\Security\ISecureRandom; use OCP\User\Events\PostLoginEvent; +use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use function array_diff; +use function get_class_methods; /** * @group DB @@ -42,11 +48,11 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; class SessionTest extends \Test\TestCase { /** @var ITimeFactory|MockObject */ private $timeFactory; - /** @var DefaultTokenProvider|MockObject */ - protected $tokenProvider; + /** @var IProvider|MockObject */ + private $tokenProvider; /** @var IConfig|MockObject */ private $config; - /** @var Throttler|MockObject */ + /** @var IThrottler|MockObject */ private $throttler; /** @var ISecureRandom|MockObject */ private $random; @@ -58,7 +64,7 @@ class SessionTest extends \Test\TestCase { private $userSession; /** @var ILockdownManager|MockObject */ private $lockdownManager; - /** @var ILogger|MockObject */ + /** @var LoggerInterface|MockObject */ private $logger; /** @var IEventDispatcher|MockObject */ private $dispatcher; @@ -72,12 +78,12 @@ class SessionTest extends \Test\TestCase { ->willReturn(10000); $this->tokenProvider = $this->createMock(IProvider::class); $this->config = $this->createMock(IConfig::class); - $this->throttler = $this->createMock(Throttler::class); + $this->throttler = $this->createMock(IThrottler::class); $this->random = $this->createMock(ISecureRandom::class); $this->manager = $this->createMock(Manager::class); $this->session = $this->createMock(ISession::class); $this->lockdownManager = $this->createMock(ILockdownManager::class); - $this->logger = $this->createMock(ILogger::class); + $this->logger = $this->createMock(LoggerInterface::class); $this->dispatcher = $this->createMock(IEventDispatcher::class); $this->userSession = $this->getMockBuilder(Session::class) ->setConstructorArgs([ @@ -91,7 +97,7 @@ class SessionTest extends \Test\TestCase { $this->logger, $this->dispatcher ]) - ->setMethods([ + ->onlyMethods([ 'setMagicInCookie', ]) ->getMock(); @@ -99,93 +105,34 @@ class SessionTest extends \Test\TestCase { \OC_User::setIncognitoMode(false); } - public function testGetUser() { - $token = new \OC\Authentication\Token\DefaultToken(); - $token->setLoginName('User123'); - $token->setLastCheck(200); - - $expectedUser = $this->createMock(IUser::class); - $expectedUser->expects($this->any()) - ->method('getUID') - ->willReturn('user123'); - $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); - $session->expects($this->at(0)) - ->method('get') - ->with('user_id') - ->willReturn($expectedUser->getUID()); - $sessionId = 'abcdef12345'; - - $manager = $this->getMockBuilder('\OC\User\Manager') - ->disableOriginalConstructor() - ->getMock(); - $session->expects($this->at(1)) - ->method('get') - ->with('app_password') - ->willReturn(null); // No password set -> browser session - $session->expects($this->once()) - ->method('getId') - ->willReturn($sessionId); - $this->tokenProvider->expects($this->once()) - ->method('getToken') - ->with($sessionId) - ->willReturn($token); - $this->tokenProvider->expects($this->once()) - ->method('getPassword') - ->with($token, $sessionId) - ->willReturn('passme'); - $manager->expects($this->once()) - ->method('checkPassword') - ->with('User123', 'passme') - ->willReturn(true); - $expectedUser->expects($this->once()) - ->method('isEnabled') - ->willReturn(true); - - $this->tokenProvider->expects($this->once()) - ->method('updateTokenActivity') - ->with($token); - - $manager->expects($this->once()) - ->method('get') - ->with($expectedUser->getUID()) - ->willReturn($expectedUser); - - $userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); - $user = $userSession->getUser(); - $this->assertSame($expectedUser, $user); - $this->assertSame(10000, $token->getLastCheck()); - } - - public function isLoggedInData() { + public static function isLoggedInData(): array { return [ [true], [false], ]; } - /** - * @dataProvider isLoggedInData - */ - public function testIsLoggedIn($isLoggedIn) { - $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); + #[\PHPUnit\Framework\Attributes\DataProvider('isLoggedInData')] + public function testIsLoggedIn($isLoggedIn): void { + $session = $this->createMock(Memory::class); $manager = $this->createMock(Manager::class); $userSession = $this->getMockBuilder(Session::class) ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) - ->setMethods([ + ->onlyMethods([ 'getUser' ]) ->getMock(); - $user = new User('sepp', null, $this->createMock(EventDispatcherInterface::class)); + $user = new User('sepp', null, $this->createMock(IEventDispatcher::class)); $userSession->expects($this->once()) ->method('getUser') ->willReturn($isLoggedIn ? $user : null); $this->assertEquals($isLoggedIn, $userSession->isLoggedIn()); } - public function testSetUser() { - $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); + public function testSetUser(): void { + $session = $this->createMock(Memory::class); $session->expects($this->once()) ->method('set') ->with('user_id', 'foo'); @@ -199,18 +146,18 @@ class SessionTest extends \Test\TestCase { ->method('getUID') ->willReturn('foo'); - $userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); + $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); $userSession->setUser($user); } - public function testLoginValidPasswordEnabled() { - $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); + public function testLoginValidPasswordEnabled(): void { + $session = $this->createMock(Memory::class); $session->expects($this->once()) ->method('regenerateId'); $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('bar') - ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException())); + ->willThrowException(new InvalidTokenException()); $session->expects($this->exactly(2)) ->method('set') ->with($this->callback(function ($key) { @@ -229,12 +176,12 @@ class SessionTest extends \Test\TestCase { //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) + ->onlyMethods($mockedManagerMethods) ->setConstructorArgs([ $this->config, - $this->createMock(EventDispatcherInterface::class), $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); @@ -257,7 +204,7 @@ class SessionTest extends \Test\TestCase { $userSession = $this->getMockBuilder(Session::class) ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) - ->setMethods([ + ->onlyMethods([ 'prepareUserLogin' ]) ->getMock(); @@ -268,9 +215,9 @@ class SessionTest extends \Test\TestCase { ->method('dispatchTyped') ->with( $this->callback(function (PostLoginEvent $e) { - return $e->getUser()->getUID() === 'foo' && - $e->getPassword() === 'bar' && - $e->isTokenLogin() === false; + return $e->getUser()->getUID() === 'foo' + && $e->getPassword() === 'bar' + && $e->isTokenLogin() === false; }) ); @@ -279,10 +226,10 @@ class SessionTest extends \Test\TestCase { } - public function testLoginValidPasswordDisabled() { - $this->expectException(\OC\User\LoginException::class); + public function testLoginValidPasswordDisabled(): void { + $this->expectException(LoginException::class); - $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); + $session = $this->createMock(Memory::class); $session->expects($this->never()) ->method('set'); $session->expects($this->once()) @@ -290,18 +237,18 @@ class SessionTest extends \Test\TestCase { $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('bar') - ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException())); + ->willThrowException(new InvalidTokenException()); - $managerMethods = get_class_methods(\OC\User\Manager::class); + $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) + ->onlyMethods($mockedManagerMethods) ->setConstructorArgs([ $this->config, - $this->createMock(EventDispatcherInterface::class), $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); @@ -320,26 +267,26 @@ class SessionTest extends \Test\TestCase { $this->dispatcher->expects($this->never()) ->method('dispatch'); - $userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); + $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); $userSession->login('foo', 'bar'); } - public function testLoginInvalidPassword() { - $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); - $managerMethods = get_class_methods(\OC\User\Manager::class); + public function testLoginInvalidPassword(): void { + $session = $this->createMock(Memory::class); + $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) + ->onlyMethods($mockedManagerMethods) ->setConstructorArgs([ $this->config, - $this->createMock(EventDispatcherInterface::class), $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); $backend = $this->createMock(\Test\Util\User\Dummy::class); - $userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); + $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); $user = $this->createMock(IUser::class); @@ -350,7 +297,7 @@ class SessionTest extends \Test\TestCase { $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('bar') - ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException())); + ->willThrowException(new InvalidTokenException()); $user->expects($this->never()) ->method('isEnabled'); @@ -368,39 +315,86 @@ class SessionTest extends \Test\TestCase { $userSession->login('foo', 'bar'); } - public function testLoginNonExisting() { - $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); - $manager = $this->createMock(Manager::class); - $userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); + public function testPasswordlessLoginNoLastCheckUpdate(): void { + $session = $this->createMock(Memory::class); + $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) + ->onlyMethods($mockedManagerMethods) + ->setConstructorArgs([ + $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); $session->expects($this->never()) ->method('set'); $session->expects($this->once()) ->method('regenerateId'); - $this->tokenProvider->expects($this->once()) + $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('bar') - ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException())); + ->with('app-password') + ->willReturn($token); + $this->tokenProvider->expects(self::never()) + ->method('updateToken'); - $manager->expects($this->once()) - ->method('checkPasswordNoLogging') - ->with('foo', 'bar') - ->willReturn(false); + $userSession->login('foo', 'app-password'); + } - $userSession->login('foo', 'bar'); + public function testLoginLastCheckUpdate(): void { + $session = $this->createMock(Memory::class); + $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) + ->onlyMethods($mockedManagerMethods) + ->setConstructorArgs([ + $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); + + $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'); } - /** - * When using a device token, the loginname must match the one that was used - * when generating the token on the browser. - */ - public function testLoginWithDifferentTokenLoginName() { - $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); + public function testLoginNonExisting(): void { + $session = $this->createMock(Memory::class); $manager = $this->createMock(Manager::class); - $userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); - $username = 'user123'; - $token = new \OC\Authentication\Token\DefaultToken(); - $token->setLoginName($username); + $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'); @@ -409,7 +403,7 @@ class SessionTest extends \Test\TestCase { $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('bar') - ->willReturn($token); + ->willThrowException(new InvalidTokenException()); $manager->expects($this->once()) ->method('checkPasswordNoLogging') @@ -419,26 +413,25 @@ class SessionTest extends \Test\TestCase { $userSession->login('foo', 'bar'); } - - public function testLogClientInNoTokenPasswordWith2fa() { - $this->expectException(\OC\Authentication\Exceptions\PasswordLoginForbiddenException::class); + public function testLogClientInNoTokenPasswordWith2fa(): void { + $this->expectException(PasswordLoginForbiddenException::class); $manager = $this->createMock(Manager::class); $session = $this->createMock(ISession::class); $request = $this->createMock(IRequest::class); - /** @var \OC\User\Session $userSession */ + /** @var Session $userSession */ $userSession = $this->getMockBuilder(Session::class) ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) - ->setMethods(['login', 'supportsCookies', 'createSessionToken', 'getUser']) + ->onlyMethods(['login', 'supportsCookies', 'createSessionToken', 'getUser']) ->getMock(); $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('doe') - ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException())); + ->willThrowException(new InvalidTokenException()); $this->config->expects($this->once()) - ->method('getSystemValue') + ->method('getSystemValueBool') ->with('token_auth_enforced', false) ->willReturn(true); $request @@ -447,7 +440,7 @@ class SessionTest extends \Test\TestCase { ->willReturn('192.168.0.1'); $this->throttler ->expects($this->once()) - ->method('sleepDelay') + ->method('sleepDelayOrThrowOnMax') ->with('192.168.0.1'); $this->throttler ->expects($this->any()) @@ -458,7 +451,7 @@ class SessionTest extends \Test\TestCase { $userSession->logClientIn('john', 'doe', $request, $this->throttler); } - public function testLogClientInUnexist() { + public function testLogClientInUnexist(): void { $manager = $this->createMock(Manager::class); $session = $this->createMock(ISession::class); $request = $this->createMock(IRequest::class); @@ -466,15 +459,15 @@ class SessionTest extends \Test\TestCase { /** @var Session $userSession */ $userSession = $this->getMockBuilder(Session::class) ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) - ->setMethods(['login', 'supportsCookies', 'createSessionToken', 'getUser']) + ->onlyMethods(['login', 'supportsCookies', 'createSessionToken', 'getUser']) ->getMock(); $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('doe') - ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException())); + ->willThrowException(new InvalidTokenException()); $this->config->expects($this->once()) - ->method('getSystemValue') + ->method('getSystemValueBool') ->with('token_auth_enforced', false) ->willReturn(false); $manager->method('getByEmail') @@ -484,15 +477,15 @@ class SessionTest extends \Test\TestCase { $this->assertFalse($userSession->logClientIn('unexist', 'doe', $request, $this->throttler)); } - public function testLogClientInWithTokenPassword() { + public function testLogClientInWithTokenPassword(): void { $manager = $this->createMock(Manager::class); $session = $this->createMock(ISession::class); $request = $this->createMock(IRequest::class); - /** @var \OC\User\Session $userSession */ + /** @var Session $userSession */ $userSession = $this->getMockBuilder(Session::class) ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) - ->setMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser']) + ->onlyMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser']) ->getMock(); $userSession->expects($this->once()) @@ -512,7 +505,7 @@ class SessionTest extends \Test\TestCase { ->willReturn('192.168.0.1'); $this->throttler ->expects($this->once()) - ->method('sleepDelay') + ->method('sleepDelayOrThrowOnMax') ->with('192.168.0.1'); $this->throttler ->expects($this->any()) @@ -524,25 +517,25 @@ class SessionTest extends \Test\TestCase { } - public function testLogClientInNoTokenPasswordNo2fa() { - $this->expectException(\OC\Authentication\Exceptions\PasswordLoginForbiddenException::class); + public function testLogClientInNoTokenPasswordNo2fa(): void { + $this->expectException(PasswordLoginForbiddenException::class); $manager = $this->createMock(Manager::class); $session = $this->createMock(ISession::class); $request = $this->createMock(IRequest::class); - /** @var \OC\User\Session $userSession */ + /** @var Session $userSession */ $userSession = $this->getMockBuilder(Session::class) ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) - ->setMethods(['login', 'isTwoFactorEnforced']) + ->onlyMethods(['login', 'isTwoFactorEnforced']) ->getMock(); $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('doe') - ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException())); + ->willThrowException(new InvalidTokenException()); $this->config->expects($this->once()) - ->method('getSystemValue') + ->method('getSystemValueBool') ->with('token_auth_enforced', false) ->willReturn(false); @@ -557,7 +550,7 @@ class SessionTest extends \Test\TestCase { ->willReturn('192.168.0.1'); $this->throttler ->expects($this->once()) - ->method('sleepDelay') + ->method('sleepDelayOrThrowOnMax') ->with('192.168.0.1'); $this->throttler ->expects($this->any()) @@ -568,23 +561,112 @@ class SessionTest extends \Test\TestCase { $userSession->logClientIn('john', 'doe', $request, $this->throttler); } - public function testRememberLoginValidToken() { - $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); - $managerMethods = get_class_methods(\OC\User\Manager::class); + public function testTryTokenLoginNoHeaderNoSessionCookie(): void { + $request = $this->createMock(IRequest::class); + $this->config->expects(self::once()) + ->method('getSystemValueString') + ->with('instanceid') + ->willReturn('abc123'); + $request->method('getHeader')->with('Authorization')->willReturn(''); + $request->method('getCookie')->with('abc123')->willReturn(null); + $this->tokenProvider->expects(self::never()) + ->method('getToken'); + + $loginResult = $this->userSession->tryTokenLogin($request); + + self::assertFalse($loginResult); + } + + public function testTryTokenLoginAuthorizationHeaderTokenNotFound(): void { + $request = $this->createMock(IRequest::class); + $request->method('getHeader')->with('Authorization')->willReturn('Bearer abcde-12345'); + $this->tokenProvider->expects(self::once()) + ->method('getToken') + ->with('abcde-12345') + ->willThrowException(new InvalidTokenException()); + + $loginResult = $this->userSession->tryTokenLogin($request); + + self::assertFalse($loginResult); + } + + public function testTryTokenLoginSessionIdTokenNotFound(): void { + $request = $this->createMock(IRequest::class); + $this->config->expects(self::once()) + ->method('getSystemValueString') + ->with('instanceid') + ->willReturn('abc123'); + $request->method('getHeader')->with('Authorization')->willReturn(''); + $request->method('getCookie')->with('abc123')->willReturn('abcde12345'); + $this->session->expects(self::once()) + ->method('getId') + ->willReturn('abcde12345'); + $this->tokenProvider->expects(self::once()) + ->method('getToken') + ->with('abcde12345') + ->willThrowException(new InvalidTokenException()); + + $loginResult = $this->userSession->tryTokenLogin($request); + + self::assertFalse($loginResult); + } + + public function testTryTokenLoginNotAnAppPassword(): void { + $request = $this->createMock(IRequest::class); + $this->config->expects(self::once()) + ->method('getSystemValueString') + ->with('instanceid') + ->willReturn('abc123'); + $request->method('getHeader')->with('Authorization')->willReturn(''); + $request->method('getCookie')->with('abc123')->willReturn('abcde12345'); + $this->session->expects(self::once()) + ->method('getId') + ->willReturn('abcde12345'); + $dbToken = new PublicKeyToken(); + $dbToken->setId(42); + $dbToken->setUid('johnny'); + $dbToken->setLoginName('johnny'); + $dbToken->setLastCheck(0); + $dbToken->setType(IToken::TEMPORARY_TOKEN); + $dbToken->setRemember(IToken::REMEMBER); + $this->tokenProvider->expects(self::any()) + ->method('getToken') + ->with('abcde12345') + ->willReturn($dbToken); + $this->session->method('set') + ->willReturnCallback(function ($key, $value): void { + if ($key === 'app_password') { + throw new ExpectationFailedException('app_password should not be set in session'); + } + }); + $user = $this->createMock(IUser::class); + $user->method('isEnabled')->willReturn(true); + $this->manager->method('get') + ->with('johnny') + ->willReturn($user); + + $loginResult = $this->userSession->tryTokenLogin($request); + + self::assertTrue($loginResult); + } + + public function testRememberLoginValidToken(): void { + $session = $this->createMock(Memory::class); + $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) + ->onlyMethods($mockedManagerMethods) ->setConstructorArgs([ $this->config, - $this->createMock(EventDispatcherInterface::class), $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); $userSession = $this->getMockBuilder(Session::class) //override, otherwise tests will fail because of setcookie() - ->setMethods(['setMagicInCookie', 'setLoginName']) + ->onlyMethods(['setMagicInCookie', 'setLoginName']) ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) ->getMock(); @@ -642,7 +724,7 @@ class SessionTest extends \Test\TestCase { $setUID = false; $session ->method('set') - ->willReturnCallback(function ($k, $v) use (&$setUID) { + ->willReturnCallback(function ($k, $v) use (&$setUID): void { if ($k === 'user_id' && $v === 'foo') { $setUID = true; } @@ -658,23 +740,23 @@ class SessionTest extends \Test\TestCase { $this->assertTrue($granted); } - public function testRememberLoginInvalidSessionToken() { - $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); - $managerMethods = get_class_methods(\OC\User\Manager::class); + public function testRememberLoginInvalidSessionToken(): void { + $session = $this->createMock(Memory::class); + $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) + ->onlyMethods($mockedManagerMethods) ->setConstructorArgs([ $this->config, - $this->createMock(EventDispatcherInterface::class), $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); $userSession = $this->getMockBuilder(Session::class) //override, otherwise tests will fail because of setcookie() - ->setMethods(['setMagicInCookie']) + ->onlyMethods(['setMagicInCookie']) ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) ->getMock(); @@ -705,7 +787,7 @@ class SessionTest extends \Test\TestCase { $this->tokenProvider->expects($this->once()) ->method('renewSessionToken') ->with($oldSessionId, $sessionId) - ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException())); + ->willThrowException(new InvalidTokenException()); $user->expects($this->never()) ->method('getUID') @@ -723,23 +805,23 @@ class SessionTest extends \Test\TestCase { $this->assertFalse($granted); } - public function testRememberLoginInvalidToken() { - $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); - $managerMethods = get_class_methods(\OC\User\Manager::class); + public function testRememberLoginInvalidToken(): void { + $session = $this->createMock(Memory::class); + $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) + ->onlyMethods($mockedManagerMethods) ->setConstructorArgs([ $this->config, - $this->createMock(EventDispatcherInterface::class), $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); $userSession = $this->getMockBuilder(Session::class) //override, otherwise tests will fail because of setcookie() - ->setMethods(['setMagicInCookie']) + ->onlyMethods(['setMagicInCookie']) ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) ->getMock(); @@ -776,23 +858,23 @@ class SessionTest extends \Test\TestCase { $this->assertFalse($granted); } - public function testRememberLoginInvalidUser() { - $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock(); - $managerMethods = get_class_methods(\OC\User\Manager::class); + public function testRememberLoginInvalidUser(): void { + $session = $this->createMock(Memory::class); + $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) + ->onlyMethods($mockedManagerMethods) ->setConstructorArgs([ $this->config, - $this->createMock(EventDispatcherInterface::class), $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), ]) ->getMock(); $userSession = $this->getMockBuilder(Session::class) //override, otherwise tests will fail because of setcookie() - ->setMethods(['setMagicInCookie']) + ->onlyMethods(['setMagicInCookie']) ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) ->getMock(); $token = 'goodToken'; @@ -822,13 +904,13 @@ class SessionTest extends \Test\TestCase { $this->assertFalse($granted); } - public function testActiveUserAfterSetSession() { + public function testActiveUserAfterSetSession(): void { $users = [ - 'foo' => new User('foo', null, $this->createMock(EventDispatcherInterface::class)), - 'bar' => new User('bar', null, $this->createMock(EventDispatcherInterface::class)) + 'foo' => new User('foo', null, $this->createMock(IEventDispatcher::class)), + 'bar' => new User('bar', null, $this->createMock(IEventDispatcher::class)) ]; - $manager = $this->getMockBuilder('\OC\User\Manager') + $manager = $this->getMockBuilder(Manager::class) ->disableOriginalConstructor() ->getMock(); @@ -838,11 +920,11 @@ class SessionTest extends \Test\TestCase { return $users[$uid]; }); - $session = new Memory(''); + $session = new Memory(); $session->set('user_id', 'foo'); $userSession = $this->getMockBuilder(Session::class) ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) - ->setMethods([ + ->onlyMethods([ 'validateSession' ]) ->getMock(); @@ -851,28 +933,28 @@ class SessionTest extends \Test\TestCase { $this->assertEquals($users['foo'], $userSession->getUser()); - $session2 = new Memory(''); + $session2 = new Memory(); $session2->set('user_id', 'bar'); $userSession->setSession($session2); $this->assertEquals($users['bar'], $userSession->getUser()); } - public function testCreateSessionToken() { + public function testCreateSessionToken(): void { $manager = $this->createMock(Manager::class); $session = $this->createMock(ISession::class); $user = $this->createMock(IUser::class); - $userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); + $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); - $random = $this->createMock(ISecureRandom::class); + $requestId = $this->createMock(IRequestId::class); $config = $this->createMock(IConfig::class); - $csrf = $this->getMockBuilder('\OC\Security\CSRF\CsrfTokenManager') + $csrf = $this->getMockBuilder(CsrfTokenManager::class) ->disableOriginalConstructor() ->getMock(); - $request = new \OC\AppFramework\Http\Request([ + $request = new Request([ 'server' => [ 'HTTP_USER_AGENT' => 'Firefox', ] - ], $random, $config, $csrf); + ], $requestId, $config, $csrf); $uid = 'user123'; $loginName = 'User123'; @@ -889,7 +971,7 @@ class SessionTest extends \Test\TestCase { $this->tokenProvider->expects($this->once()) ->method('getToken') ->with($password) - ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException())); + ->willThrowException(new InvalidTokenException()); $this->tokenProvider->expects($this->once()) ->method('generateToken') @@ -898,22 +980,22 @@ class SessionTest extends \Test\TestCase { $this->assertTrue($userSession->createSessionToken($request, $uid, $loginName, $password)); } - public function testCreateRememberedSessionToken() { + public function testCreateRememberedSessionToken(): void { $manager = $this->createMock(Manager::class); $session = $this->createMock(ISession::class); $user = $this->createMock(IUser::class); - $userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); + $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); - $random = $this->createMock(ISecureRandom::class); + $requestId = $this->createMock(IRequestId::class); $config = $this->createMock(IConfig::class); - $csrf = $this->getMockBuilder('\OC\Security\CSRF\CsrfTokenManager') + $csrf = $this->getMockBuilder(CsrfTokenManager::class) ->disableOriginalConstructor() ->getMock(); - $request = new \OC\AppFramework\Http\Request([ + $request = new Request([ 'server' => [ 'HTTP_USER_AGENT' => 'Firefox', ] - ], $random, $config, $csrf); + ], $requestId, $config, $csrf); $uid = 'user123'; $loginName = 'User123'; @@ -930,7 +1012,7 @@ class SessionTest extends \Test\TestCase { $this->tokenProvider->expects($this->once()) ->method('getToken') ->with($password) - ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException())); + ->willThrowException(new InvalidTokenException()); $this->tokenProvider->expects($this->once()) ->method('generateToken') @@ -939,25 +1021,25 @@ class SessionTest extends \Test\TestCase { $this->assertTrue($userSession->createSessionToken($request, $uid, $loginName, $password, true)); } - public function testCreateSessionTokenWithTokenPassword() { - $manager = $this->getMockBuilder('\OC\User\Manager') + public function testCreateSessionTokenWithTokenPassword(): void { + $manager = $this->getMockBuilder(Manager::class) ->disableOriginalConstructor() ->getMock(); $session = $this->createMock(ISession::class); $token = $this->createMock(IToken::class); $user = $this->createMock(IUser::class); - $userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); + $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); - $random = $this->createMock(ISecureRandom::class); + $requestId = $this->createMock(IRequestId::class); $config = $this->createMock(IConfig::class); - $csrf = $this->getMockBuilder('\OC\Security\CSRF\CsrfTokenManager') + $csrf = $this->getMockBuilder(CsrfTokenManager::class) ->disableOriginalConstructor() ->getMock(); - $request = new \OC\AppFramework\Http\Request([ + $request = new Request([ 'server' => [ 'HTTP_USER_AGENT' => 'Firefox', ] - ], $random, $config, $csrf); + ], $requestId, $config, $csrf); $uid = 'user123'; $loginName = 'User123'; @@ -988,12 +1070,12 @@ class SessionTest extends \Test\TestCase { $this->assertTrue($userSession->createSessionToken($request, $uid, $loginName, $password)); } - public function testCreateSessionTokenWithNonExistentUser() { - $manager = $this->getMockBuilder('\OC\User\Manager') + public function testCreateSessionTokenWithNonExistentUser(): void { + $manager = $this->getMockBuilder(Manager::class) ->disableOriginalConstructor() ->getMock(); $session = $this->createMock(ISession::class); - $userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); + $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); $request = $this->createMock(IRequest::class); $uid = 'user123'; @@ -1008,336 +1090,7 @@ class SessionTest extends \Test\TestCase { $this->assertFalse($userSession->createSessionToken($request, $uid, $loginName, $password)); } - - public function testTryTokenLoginWithDisabledUser() { - $this->expectException(\OC\User\LoginException::class); - - $manager = $this->getMockBuilder('\OC\User\Manager') - ->disableOriginalConstructor() - ->getMock(); - $session = new Memory(''); - $token = new \OC\Authentication\Token\DefaultToken(); - $token->setLoginName('fritz'); - $token->setUid('fritz0'); - $token->setLastCheck(100); // Needs check - $user = $this->createMock(IUser::class); - $userSession = $this->getMockBuilder(Session::class) - ->setMethods(['logout']) - ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) - ->getMock(); - $request = $this->createMock(IRequest::class); - - $request->expects($this->once()) - ->method('getHeader') - ->with('Authorization') - ->willReturn('Bearer xxxxx'); - $this->tokenProvider->expects($this->once()) - ->method('getToken') - ->with('xxxxx') - ->willReturn($token); - $manager->expects($this->once()) - ->method('get') - ->with('fritz0') - ->willReturn($user); - $user->expects($this->once()) - ->method('isEnabled') - ->willReturn(false); - - $userSession->tryTokenLogin($request); - } - - public function testValidateSessionDisabledUser() { - $userManager = $this->createMock(Manager::class); - $session = $this->createMock(ISession::class); - $timeFactory = $this->createMock(ITimeFactory::class); - $tokenProvider = $this->createMock(IProvider::class); - $userSession = $this->getMockBuilder(Session::class) - ->setConstructorArgs([$userManager, $session, $timeFactory, $tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) - ->setMethods(['logout']) - ->getMock(); - - $user = $this->createMock(IUser::class); - $token = new \OC\Authentication\Token\DefaultToken(); - $token->setLoginName('susan'); - $token->setLastCheck(20); - - $session->expects($this->once()) - ->method('get') - ->with('app_password') - ->willReturn('APP-PASSWORD'); - $tokenProvider->expects($this->once()) - ->method('getToken') - ->with('APP-PASSWORD') - ->willReturn($token); - $timeFactory->expects($this->once()) - ->method('getTime') - ->willReturn(1000); // more than 5min since last check - $tokenProvider->expects($this->once()) - ->method('getPassword') - ->with($token, 'APP-PASSWORD') - ->willReturn('123456'); - $userManager->expects($this->never()) - ->method('checkPassword'); - $user->expects($this->once()) - ->method('isEnabled') - ->willReturn(false); - $tokenProvider->expects($this->once()) - ->method('invalidateToken') - ->with('APP-PASSWORD'); - $userSession->expects($this->once()) - ->method('logout'); - - $userSession->setUser($user); - $this->invokePrivate($userSession, 'validateSession'); - } - - public function testValidateSessionNoPassword() { - $userManager = $this->createMock(Manager::class); - $session = $this->createMock(ISession::class); - $timeFactory = $this->createMock(ITimeFactory::class); - $tokenProvider = $this->createMock(IProvider::class); - $userSession = $this->getMockBuilder(Session::class) - ->setConstructorArgs([$userManager, $session, $timeFactory, $tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) - ->setMethods(['logout']) - ->getMock(); - - $user = $this->createMock(IUser::class); - $token = new \OC\Authentication\Token\DefaultToken(); - $token->setLastCheck(20); - - $session->expects($this->once()) - ->method('get') - ->with('app_password') - ->willReturn('APP-PASSWORD'); - $tokenProvider->expects($this->once()) - ->method('getToken') - ->with('APP-PASSWORD') - ->willReturn($token); - $timeFactory->expects($this->once()) - ->method('getTime') - ->willReturn(1000); // more than 5min since last check - $tokenProvider->expects($this->once()) - ->method('getPassword') - ->with($token, 'APP-PASSWORD') - ->will($this->throwException(new \OC\Authentication\Exceptions\PasswordlessTokenException())); - - $this->invokePrivate($userSession, 'validateSession', [$user]); - - $this->assertEquals(1000, $token->getLastCheck()); - } - - public function testValidateSessionInvalidPassword() { - $userManager = $this->createMock(Manager::class); - $session = $this->createMock(ISession::class); - $timeFactory = $this->createMock(ITimeFactory::class); - $tokenProvider = $this->createMock(IProvider::class); - $userSession = $this->getMockBuilder(Session::class) - ->setConstructorArgs([$userManager, $session, $timeFactory, $tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) - ->setMethods(['logout']) - ->getMock(); - - $user = $this->createMock(IUser::class); - $token = new \OC\Authentication\Token\DefaultToken(); - $token->setLoginName('susan'); - $token->setLastCheck(20); - - $session->expects($this->once()) - ->method('get') - ->with('app_password') - ->willReturn('APP-PASSWORD'); - $tokenProvider->expects($this->once()) - ->method('getToken') - ->with('APP-PASSWORD') - ->willReturn($token); - $timeFactory->expects($this->once()) - ->method('getTime') - ->willReturn(1000); // more than 5min since last check - $tokenProvider->expects($this->once()) - ->method('getPassword') - ->with($token, 'APP-PASSWORD') - ->willReturn('123456'); - $userManager->expects($this->once()) - ->method('checkPassword') - ->with('susan', '123456') - ->willReturn(false); - $user->expects($this->once()) - ->method('isEnabled') - ->willReturn(true); - $tokenProvider->expects($this->never()) - ->method('invalidateToken'); - $tokenProvider->expects($this->once()) - ->method('markPasswordInvalid') - ->with($token, 'APP-PASSWORD'); - $userSession->expects($this->once()) - ->method('logout'); - - $userSession->setUser($user); - $this->invokePrivate($userSession, 'validateSession'); - } - - public function testUpdateSessionTokenPassword() { - $userManager = $this->createMock(Manager::class); - $session = $this->createMock(ISession::class); - $timeFactory = $this->createMock(ITimeFactory::class); - $tokenProvider = $this->createMock(IProvider::class); - $userSession = new \OC\User\Session($userManager, $session, $timeFactory, $tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); - - $password = '123456'; - $sessionId = 'session1234'; - $token = new \OC\Authentication\Token\DefaultToken(); - - $session->expects($this->once()) - ->method('getId') - ->willReturn($sessionId); - $tokenProvider->expects($this->once()) - ->method('getToken') - ->with($sessionId) - ->willReturn($token); - $tokenProvider->expects($this->once()) - ->method('setPassword') - ->with($token, $sessionId, $password); - - $userSession->updateSessionTokenPassword($password); - } - - public function testUpdateSessionTokenPasswordNoSessionAvailable() { - $userManager = $this->createMock(Manager::class); - $session = $this->createMock(ISession::class); - $timeFactory = $this->createMock(ITimeFactory::class); - $tokenProvider = $this->createMock(IProvider::class); - $userSession = new \OC\User\Session($userManager, $session, $timeFactory, $tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); - - $session->expects($this->once()) - ->method('getId') - ->will($this->throwException(new \OCP\Session\Exceptions\SessionNotAvailableException())); - - $userSession->updateSessionTokenPassword('1234'); - } - - public function testUpdateSessionTokenPasswordInvalidTokenException() { - $userManager = $this->createMock(Manager::class); - $session = $this->createMock(ISession::class); - $timeFactory = $this->createMock(ITimeFactory::class); - $tokenProvider = $this->createMock(IProvider::class); - $userSession = new \OC\User\Session($userManager, $session, $timeFactory, $tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); - - $password = '123456'; - $sessionId = 'session1234'; - $token = new \OC\Authentication\Token\DefaultToken(); - - $session->expects($this->once()) - ->method('getId') - ->willReturn($sessionId); - $tokenProvider->expects($this->once()) - ->method('getToken') - ->with($sessionId) - ->willReturn($token); - $tokenProvider->expects($this->once()) - ->method('setPassword') - ->with($token, $sessionId, $password) - ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException())); - - $userSession->updateSessionTokenPassword($password); - } - - public function testUpdateAuthTokenLastCheck() { - $manager = $this->createMock(Manager::class); - $session = $this->createMock(ISession::class); - $request = $this->createMock(IRequest::class); - - $token = new \OC\Authentication\Token\DefaultToken(); - $token->setUid('john'); - $token->setLoginName('john'); - $token->setLastActivity(100); - $token->setLastCheck(100); - - $mapper = $this->getMockBuilder(DefaultTokenMapper::class) - ->disableOriginalConstructor() - ->getMock(); - $crypto = $this->createMock(ICrypto::class); - $logger = $this->createMock(LoggerInterface::class); - $tokenProvider = new DefaultTokenProvider($mapper, $crypto, $this->config, $logger, $this->timeFactory); - - /** @var \OC\User\Session $userSession */ - $userSession = new Session($manager, $session, $this->timeFactory, $tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); - - $mapper->expects($this->any()) - ->method('getToken') - ->willReturn($token); - $mapper->expects($this->once()) - ->method('update'); - $request - ->expects($this->any()) - ->method('getRemoteAddress') - ->willReturn('192.168.0.1'); - $this->throttler - ->expects($this->once()) - ->method('sleepDelay') - ->with('192.168.0.1') - ->willReturn(5); - $this->timeFactory - ->expects($this->any()) - ->method('getTime') - ->willReturn(100); - - $manager->method('getByEmail') - ->with('john') - ->willReturn([]); - - $userSession->logClientIn('john', 'doe', $request, $this->throttler); - - $this->assertEquals(10000, $token->getLastActivity()); - $this->assertEquals(10000, $token->getLastCheck()); - } - - public function testNoUpdateAuthTokenLastCheckRecent() { - $manager = $this->createMock(Manager::class); - $session = $this->createMock(ISession::class); - $request = $this->createMock(IRequest::class); - - $token = new \OC\Authentication\Token\DefaultToken(); - $token->setUid('john'); - $token->setLoginName('john'); - $token->setLastActivity(10000); - $token->setLastCheck(100); - - $mapper = $this->getMockBuilder(DefaultTokenMapper::class) - ->disableOriginalConstructor() - ->getMock(); - $crypto = $this->createMock(ICrypto::class); - $logger = $this->createMock(LoggerInterface::class); - $tokenProvider = new DefaultTokenProvider($mapper, $crypto, $this->config, $logger, $this->timeFactory); - - /** @var \OC\User\Session $userSession */ - $userSession = new Session($manager, $session, $this->timeFactory, $tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher); - - $mapper->expects($this->any()) - ->method('getToken') - ->willReturn($token); - $mapper->expects($this->never()) - ->method('update'); - $request - ->expects($this->any()) - ->method('getRemoteAddress') - ->willReturn('192.168.0.1'); - $this->throttler - ->expects($this->once()) - ->method('sleepDelay') - ->with('192.168.0.1') - ->willReturn(5); - $this->timeFactory - ->expects($this->any()) - ->method('getTime') - ->willReturn(100); - - $manager->method('getByEmail') - ->with('john') - ->willReturn([]); - - $userSession->logClientIn('john', 'doe', $request, $this->throttler); - } - - public function testCreateRememberMeToken() { + public function testCreateRememberMeToken(): void { $user = $this->createMock(IUser::class); $user ->expects($this->exactly(2)) @@ -1360,7 +1113,7 @@ class SessionTest extends \Test\TestCase { $this->userSession->createRememberMeToken($user); } - public function testTryBasicAuthLoginValid() { + public function testTryBasicAuthLoginValid(): void { $request = $this->createMock(Request::class); $request->method('__get') ->willReturn([ @@ -1376,7 +1129,7 @@ class SessionTest extends \Test\TestCase { $this->session ->method('set') - ->willReturnCallback(function ($k, $v) use (&$davAuthenticatedSet, &$lastPasswordConfirmSet) { + ->willReturnCallback(function ($k, $v) use (&$davAuthenticatedSet, &$lastPasswordConfirmSet): void { switch ($k) { case Auth::DAV_AUTHENTICATED: $davAuthenticatedSet = $v; @@ -1401,7 +1154,7 @@ class SessionTest extends \Test\TestCase { $this->logger, $this->dispatcher ]) - ->setMethods([ + ->onlyMethods([ 'logClientIn', 'getUser', ]) @@ -1430,7 +1183,7 @@ class SessionTest extends \Test\TestCase { $this->assertSame(1000, $lastPasswordConfirmSet); } - public function testTryBasicAuthLoginNoLogin() { + public function testTryBasicAuthLoginNoLogin(): void { $request = $this->createMock(Request::class); $request->method('__get') ->willReturn([]); @@ -1453,7 +1206,7 @@ class SessionTest extends \Test\TestCase { $this->logger, $this->dispatcher ]) - ->setMethods([ + ->onlyMethods([ 'logClientIn', ]) ->getMock(); @@ -1465,11 +1218,107 @@ class SessionTest extends \Test\TestCase { $this->assertFalse($userSession->tryBasicAuthLogin($request, $this->throttler)); } - public function testUpdateTokens() { + public function testUpdateTokens(): void { $this->tokenProvider->expects($this->once()) ->method('updatePasswords') ->with('uid', 'pass'); $this->userSession->updateTokens('uid', 'pass'); } + + public function testLogClientInThrottlerUsername(): void { + $manager = $this->createMock(Manager::class); + $session = $this->createMock(ISession::class); + $request = $this->createMock(IRequest::class); + + /** @var Session $userSession */ + $userSession = $this->getMockBuilder(Session::class) + ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) + ->onlyMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser']) + ->getMock(); + + $userSession->expects($this->once()) + ->method('isTokenPassword') + ->willReturn(true); + $userSession->expects($this->once()) + ->method('login') + ->with('john', 'I-AM-AN-PASSWORD') + ->willReturn(false); + + $session->expects($this->never()) + ->method('set'); + $request + ->method('getRemoteAddress') + ->willReturn('192.168.0.1'); + $this->throttler + ->expects($this->exactly(2)) + ->method('sleepDelayOrThrowOnMax') + ->with('192.168.0.1'); + $this->throttler + ->expects($this->any()) + ->method('getDelay') + ->with('192.168.0.1') + ->willReturn(0); + + $this->throttler + ->expects($this->once()) + ->method('registerAttempt') + ->with('login', '192.168.0.1', ['user' => 'john']); + $this->dispatcher + ->expects($this->once()) + ->method('dispatchTyped') + ->with(new LoginFailed('john', 'I-AM-AN-PASSWORD')); + + $this->assertFalse($userSession->logClientIn('john', 'I-AM-AN-PASSWORD', $request, $this->throttler)); + } + + public function testLogClientInThrottlerEmail(): void { + $manager = $this->createMock(Manager::class); + $session = $this->createMock(ISession::class); + $request = $this->createMock(IRequest::class); + + /** @var Session $userSession */ + $userSession = $this->getMockBuilder(Session::class) + ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) + ->onlyMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser']) + ->getMock(); + + $userSession->expects($this->once()) + ->method('isTokenPassword') + ->willReturn(false); + $userSession->expects($this->once()) + ->method('login') + ->with('john@foo.bar', 'I-AM-AN-PASSWORD') + ->willReturn(false); + $manager + ->method('getByEmail') + ->with('john@foo.bar') + ->willReturn([]); + + $session->expects($this->never()) + ->method('set'); + $request + ->method('getRemoteAddress') + ->willReturn('192.168.0.1'); + $this->throttler + ->expects($this->exactly(2)) + ->method('sleepDelayOrThrowOnMax') + ->with('192.168.0.1'); + $this->throttler + ->expects($this->any()) + ->method('getDelay') + ->with('192.168.0.1') + ->willReturn(0); + + $this->throttler + ->expects($this->once()) + ->method('registerAttempt') + ->with('login', '192.168.0.1', ['user' => 'john@foo.bar']); + $this->dispatcher + ->expects($this->once()) + ->method('dispatchTyped') + ->with(new LoginFailed('john@foo.bar', 'I-AM-AN-PASSWORD')); + + $this->assertFalse($userSession->logClientIn('john@foo.bar', 'I-AM-AN-PASSWORD', $request, $this->throttler)); + } } |