diff options
Diffstat (limited to 'tests/Core/Controller/LostControllerTest.php')
-rw-r--r-- | tests/Core/Controller/LostControllerTest.php | 593 |
1 files changed, 223 insertions, 370 deletions
diff --git a/tests/Core/Controller/LostControllerTest.php b/tests/Core/Controller/LostControllerTest.php index 4742e7ae425..bbb5f2c2e54 100644 --- a/tests/Core/Controller/LostControllerTest.php +++ b/tests/Core/Controller/LostControllerTest.php @@ -1,87 +1,76 @@ <?php + /** - * @author Lukas Reschke <lukas@owncloud.com> - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @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: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-only */ namespace Tests\Core\Controller; use OC\Authentication\TwoFactorAuth\Manager; use OC\Core\Controller\LostController; +use OC\Core\Events\BeforePasswordResetEvent; +use OC\Core\Events\PasswordResetEvent; use OC\Mail\Message; +use OC\Security\RateLimiting\Limiter; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\TemplateResponse; -use OCP\AppFramework\Utility\ITimeFactory; +use OCP\AppFramework\Services\IInitialState; use OCP\Defaults; use OCP\Encryption\IEncryptionModule; use OCP\Encryption\IManager; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; -use OCP\IInitialStateService; use OCP\IL10N; -use OCP\ILogger; use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserManager; use OCP\Mail\IEMailTemplate; use OCP\Mail\IMailer; -use OCP\Security\ICrypto; -use OCP\Security\ISecureRandom; +use OCP\Security\VerificationToken\InvalidTokenException; +use OCP\Security\VerificationToken\IVerificationToken; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; +use Test\TestCase; /** * Class LostControllerTest * * @package OC\Core\Controller */ -class LostControllerTest extends \Test\TestCase { - - /** @var LostController */ - private $lostController; +class LostControllerTest extends TestCase { + private LostController $lostController; /** @var IUser */ private $existingUser; - /** @var IURLGenerator | \PHPUnit\Framework\MockObject\MockObject */ + /** @var IURLGenerator | MockObject */ private $urlGenerator; /** @var IL10N */ private $l10n; - /** @var IUserManager | \PHPUnit\Framework\MockObject\MockObject */ + /** @var IUserManager | MockObject */ private $userManager; /** @var Defaults */ private $defaults; - /** @var IConfig | \PHPUnit\Framework\MockObject\MockObject */ + /** @var IConfig | MockObject */ private $config; - /** @var IMailer | \PHPUnit\Framework\MockObject\MockObject */ + /** @var IMailer | MockObject */ private $mailer; - /** @var ISecureRandom | \PHPUnit\Framework\MockObject\MockObject */ - private $secureRandom; - /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IManager|MockObject */ private $encryptionManager; - /** @var ITimeFactory | \PHPUnit\Framework\MockObject\MockObject */ - private $timeFactory; - /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IRequest|MockObject */ private $request; - /** @var ICrypto|\PHPUnit\Framework\MockObject\MockObject */ - private $crypto; - /** @var ILogger|\PHPUnit\Framework\MockObject\MockObject */ + /** @var LoggerInterface|MockObject */ private $logger; - /** @var Manager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Manager|MockObject */ private $twofactorManager; - /** @var IInitialStateService|\PHPUnit\Framework\MockObject\MockObject */ - private $initialStateService; + /** @var IInitialState|MockObject */ + private $initialState; + /** @var IVerificationToken|MockObject */ + private $verificationToken; + /** @var IEventDispatcher|MockObject */ + private $eventDispatcher; + /** @var Limiter|MockObject */ + private $limiter; protected function setUp(): void { parent::setUp(); @@ -94,6 +83,9 @@ class LostControllerTest extends \Test\TestCase { ->method('getUID') ->willReturn('ExistingUser'); $this->existingUser->expects($this->any()) + ->method('getDisplayName') + ->willReturn('Existing User'); + $this->existingUser->expects($this->any()) ->method('isEnabled') ->willReturn(true); @@ -112,29 +104,21 @@ class LostControllerTest extends \Test\TestCase { ->willReturnCallback(function ($text, $parameters = []) { return vsprintf($text, $parameters); }); - $this->defaults = $this->getMockBuilder('\OCP\Defaults') - ->disableOriginalConstructor()->getMock(); - $this->userManager = $this->getMockBuilder(IUserManager::class) - ->disableOriginalConstructor()->getMock(); - $this->urlGenerator = $this->getMockBuilder(IURLGenerator::class) - ->disableOriginalConstructor()->getMock(); - $this->mailer = $this->getMockBuilder('\OCP\Mail\IMailer') - ->disableOriginalConstructor()->getMock(); - $this->secureRandom = $this->getMockBuilder('\OCP\Security\ISecureRandom') - ->disableOriginalConstructor()->getMock(); - $this->timeFactory = $this->getMockBuilder('\OCP\AppFramework\Utility\ITimeFactory') - ->disableOriginalConstructor()->getMock(); - $this->request = $this->getMockBuilder(IRequest::class) - ->disableOriginalConstructor()->getMock(); - $this->encryptionManager = $this->getMockBuilder(IManager::class) - ->disableOriginalConstructor()->getMock(); + $this->defaults = $this->createMock(Defaults::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->mailer = $this->createMock(IMailer::class); + $this->request = $this->createMock(IRequest::class); + $this->encryptionManager = $this->createMock(IManager::class); $this->encryptionManager->expects($this->any()) ->method('isEnabled') ->willReturn(true); - $this->crypto = $this->createMock(ICrypto::class); - $this->logger = $this->createMock(ILogger::class); + $this->logger = $this->createMock(LoggerInterface::class); $this->twofactorManager = $this->createMock(Manager::class); - $this->initialStateService = $this->createMock(IInitialStateService::class); + $this->initialState = $this->createMock(IInitialState::class); + $this->verificationToken = $this->createMock(IVerificationToken::class); + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->limiter = $this->createMock(Limiter::class); $this->lostController = new LostController( 'Core', $this->request, @@ -143,129 +127,66 @@ class LostControllerTest extends \Test\TestCase { $this->defaults, $this->l10n, $this->config, - $this->secureRandom, 'lostpassword-noreply@localhost', $this->encryptionManager, $this->mailer, - $this->timeFactory, - $this->crypto, $this->logger, $this->twofactorManager, - $this->initialStateService - ); - } - - public function testResetFormWithNotExistingUser() { - $this->userManager->method('get') - ->with('NotExistingUser') - ->willReturn(null); - - $expectedResponse = new TemplateResponse( - 'core', - 'error', - [ - 'errors' => [ - ['error' => 'Couldn\'t reset password because the token is invalid'], - ] - ], - 'guest' + $this->initialState, + $this->verificationToken, + $this->eventDispatcher, + $this->limiter ); - $this->assertEquals($expectedResponse, $this->lostController->resetform('MySecretToken', 'NotExistingUser')); } - public function testResetFormInvalidTokenMatch() { - $this->config->method('getUserValue') - ->with('ValidTokenUser', 'core', 'lostpassword', null) - ->willReturn('encryptedToken'); - $this->existingUser->method('getLastLogin') - ->willReturn(12344); + public function testResetFormTokenError(): void { $this->userManager->method('get') ->with('ValidTokenUser') ->willReturn($this->existingUser); - $this->crypto->method('decrypt') - ->with( - $this->equalTo('encryptedToken'), - $this->equalTo('test@example.comSECRET') - )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword'); + $this->verificationToken->expects($this->once()) + ->method('check') + ->with('12345:MySecretToken', $this->existingUser, 'lostpassword', 'test@example.com') + ->willThrowException(new InvalidTokenException(InvalidTokenException::TOKEN_DECRYPTION_ERROR)); $response = $this->lostController->resetform('12345:MySecretToken', 'ValidTokenUser'); $expectedResponse = new TemplateResponse('core', 'error', [ 'errors' => [ - ['error' => 'Couldn\'t reset password because the token is invalid'], - ] - ], - 'guest'); - $this->assertEquals($expectedResponse, $response); - } - - - public function testResetFormExpiredToken() { - $this->userManager->method('get') - ->with('ValidTokenUser') - ->willReturn($this->existingUser); - $this->config - ->expects($this->once()) - ->method('getUserValue') - ->with('ValidTokenUser', 'core', 'lostpassword', null) - ->willReturn('encryptedToken'); - $this->crypto->method('decrypt') - ->with( - $this->equalTo('encryptedToken'), - $this->equalTo('test@example.comSECRET') - )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword'); - $this->timeFactory - ->expects($this->once()) - ->method('getTime') - ->willReturn(999999); - - $response = $this->lostController->resetform('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser'); - $expectedResponse = new TemplateResponse('core', - 'error', - [ - 'errors' => [ - ['error' => 'Couldn\'t reset password because the token is expired'], + ['error' => 'Could not reset password because the token is invalid'], ] ], 'guest'); + $expectedResponse->throttle(); $this->assertEquals($expectedResponse, $response); } - public function testResetFormValidToken() { - $this->existingUser->method('getLastLogin') - ->willReturn(12344); + public function testResetFormValidToken(): void { $this->userManager->method('get') ->with('ValidTokenUser') ->willReturn($this->existingUser); - $this->timeFactory - ->expects($this->once()) - ->method('getTime') - ->willReturn(12348); - - $this->config->method('getUserValue') - ->with('ValidTokenUser', 'core', 'lostpassword', null) - ->willReturn('encryptedToken'); - - $this->crypto->method('decrypt') - ->with( - $this->equalTo('encryptedToken'), - $this->equalTo('test@example.comSECRET') - )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword'); + $this->verificationToken->expects($this->once()) + ->method('check') + ->with('MySecretToken', $this->existingUser, 'lostpassword', 'test@example.com'); $this->urlGenerator ->expects($this->once()) ->method('linkToRouteAbsolute') - ->with('core.lost.setPassword', ['userId' => 'ValidTokenUser', 'token' => 'TheOnlyAndOnlyOneTokenToResetThePassword']) - ->willReturn('https://example.tld/index.php/lostpassword/'); + ->with('core.lost.setPassword', ['userId' => 'ValidTokenUser', 'token' => 'MySecretToken']) + ->willReturn('https://example.tld/index.php/lostpassword/set/sometoken/someuser'); - $this->initialStateService->expects($this->at(0)) - ->method('provideInitialState') - ->with('core', 'resetPasswordUser', 'ValidTokenUser'); - $this->initialStateService->expects($this->at(1)) + $calls = [ + ['resetPasswordUser', 'ValidTokenUser'], + ['resetPasswordTarget', 'https://example.tld/index.php/lostpassword/set/sometoken/someuser'], + ]; + $this->initialState + ->expects($this->exactly(2)) ->method('provideInitialState') - ->with('core', 'resetPasswordTarget', 'https://example.tld/index.php/lostpassword/'); + ->willReturnCallback(function () use (&$calls): void { + $expected = array_shift($calls); + $this->assertEquals($expected, func_get_args()); + }); - $response = $this->lostController->resetform('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser'); + $response = $this->lostController->resetform('MySecretToken', 'ValidTokenUser'); $expectedResponse = new TemplateResponse('core', 'login', [], @@ -273,7 +194,7 @@ class LostControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $response); } - public function testEmailUnsuccessful() { + public function testEmailUnsuccessful(): void { $existingUser = 'ExistingUser'; $nonExistingUser = 'NonExistingUser'; $this->userManager @@ -285,7 +206,7 @@ class LostControllerTest extends \Test\TestCase { ]); $this->logger->expects($this->exactly(0)) - ->method('logException'); + ->method('error'); $this->logger->expects($this->exactly(2)) ->method('warning'); @@ -315,25 +236,15 @@ class LostControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $response); } - public function testEmailSuccessful() { - $this->secureRandom - ->expects($this->once()) - ->method('generate') - ->with('21') - ->willReturn('ThisIsMaybeANotSoSecretToken!'); + public function testEmailSuccessful(): void { $this->userManager - ->expects($this->any()) - ->method('get') - ->with('ExistingUser') - ->willReturn($this->existingUser); - $this->timeFactory - ->expects($this->once()) - ->method('getTime') - ->willReturn(12348); - $this->config - ->expects($this->once()) - ->method('setUserValue') - ->with('ExistingUser', 'core', 'lostpassword', 'encryptedToken'); + ->expects($this->any()) + ->method('get') + ->with('ExistingUser') + ->willReturn($this->existingUser); + $this->verificationToken->expects($this->once()) + ->method('create') + ->willReturn('ThisIsMaybeANotSoSecretToken!'); $this->urlGenerator ->expects($this->once()) ->method('linkToRouteAbsolute') @@ -342,11 +253,11 @@ class LostControllerTest extends \Test\TestCase { $message = $this->getMockBuilder('\OC\Mail\Message') ->disableOriginalConstructor()->getMock(); $message - ->expects($this->at(0)) + ->expects($this->once()) ->method('setTo') - ->with(['test@example.com' => 'ExistingUser']); + ->with(['test@example.com' => 'Existing User']); $message - ->expects($this->at(1)) + ->expects($this->once()) ->method('setFrom') ->with(['lostpassword-noreply@localhost' => null]); @@ -359,59 +270,43 @@ class LostControllerTest extends \Test\TestCase { ->willReturn('text body'); $message - ->expects($this->at(2)) + ->expects($this->once()) ->method('useTemplate') ->with($emailTemplate); $this->mailer - ->expects($this->at(0)) + ->expects($this->once()) ->method('createEMailTemplate') ->willReturn($emailTemplate); $this->mailer - ->expects($this->at(1)) + ->expects($this->once()) ->method('createMessage') ->willReturn($message); $this->mailer - ->expects($this->at(2)) + ->expects($this->once()) ->method('send') ->with($message); - $this->crypto->method('encrypt') - ->with( - $this->equalTo('12348:ThisIsMaybeANotSoSecretToken!'), - $this->equalTo('test@example.comSECRET') - )->willReturn('encryptedToken'); - $response = $this->lostController->email('ExistingUser'); $expectedResponse = new JSONResponse(['status' => 'success']); $expectedResponse->throttle(); $this->assertEquals($expectedResponse, $response); } - public function testEmailWithMailSuccessful() { - $this->secureRandom - ->expects($this->once()) - ->method('generate') - ->with('21') - ->willReturn('ThisIsMaybeANotSoSecretToken!'); + public function testEmailWithMailSuccessful(): void { $this->userManager - ->expects($this->any()) - ->method('get') - ->with('test@example.com') - ->willReturn(null); + ->expects($this->any()) + ->method('get') + ->with('test@example.com') + ->willReturn(null); $this->userManager - ->expects($this->any()) - ->method('getByEmail') - ->with('test@example.com') - ->willReturn([$this->existingUser]); - $this->timeFactory - ->expects($this->once()) - ->method('getTime') - ->willReturn(12348); - $this->config - ->expects($this->once()) - ->method('setUserValue') - ->with('ExistingUser', 'core', 'lostpassword', 'encryptedToken'); + ->expects($this->any()) + ->method('getByEmail') + ->with('test@example.com') + ->willReturn([$this->existingUser]); + $this->verificationToken->expects($this->once()) + ->method('create') + ->willReturn('ThisIsMaybeANotSoSecretToken!'); $this->urlGenerator ->expects($this->once()) ->method('linkToRouteAbsolute') @@ -420,11 +315,11 @@ class LostControllerTest extends \Test\TestCase { $message = $this->getMockBuilder('\OC\Mail\Message') ->disableOriginalConstructor()->getMock(); $message - ->expects($this->at(0)) + ->expects($this->once()) ->method('setTo') - ->with(['test@example.com' => 'ExistingUser']); + ->with(['test@example.com' => 'Existing User']); $message - ->expects($this->at(1)) + ->expects($this->once()) ->method('setFrom') ->with(['lostpassword-noreply@localhost' => null]); @@ -437,54 +332,38 @@ class LostControllerTest extends \Test\TestCase { ->willReturn('text body'); $message - ->expects($this->at(2)) + ->expects($this->once()) ->method('useTemplate') ->with($emailTemplate); $this->mailer - ->expects($this->at(0)) + ->expects($this->once()) ->method('createEMailTemplate') ->willReturn($emailTemplate); $this->mailer - ->expects($this->at(1)) + ->expects($this->once()) ->method('createMessage') ->willReturn($message); $this->mailer - ->expects($this->at(2)) + ->expects($this->once()) ->method('send') ->with($message); - $this->crypto->method('encrypt') - ->with( - $this->equalTo('12348:ThisIsMaybeANotSoSecretToken!'), - $this->equalTo('test@example.comSECRET') - )->willReturn('encryptedToken'); - $response = $this->lostController->email('test@example.com'); $expectedResponse = new JSONResponse(['status' => 'success']); $expectedResponse->throttle(); $this->assertEquals($expectedResponse, $response); } - public function testEmailCantSendException() { - $this->secureRandom - ->expects($this->once()) - ->method('generate') - ->with('21') - ->willReturn('ThisIsMaybeANotSoSecretToken!'); + public function testEmailCantSendException(): void { $this->userManager - ->expects($this->any()) - ->method('get') - ->with('ExistingUser') - ->willReturn($this->existingUser); - $this->config - ->expects($this->once()) - ->method('setUserValue') - ->with('ExistingUser', 'core', 'lostpassword', 'encryptedToken'); - $this->timeFactory - ->expects($this->once()) - ->method('getTime') - ->willReturn(12348); + ->expects($this->any()) + ->method('get') + ->with('ExistingUser') + ->willReturn($this->existingUser); + $this->verificationToken->expects($this->once()) + ->method('create') + ->willReturn('ThisIsMaybeANotSoSecretToken!'); $this->urlGenerator ->expects($this->once()) ->method('linkToRouteAbsolute') @@ -492,11 +371,11 @@ class LostControllerTest extends \Test\TestCase { ->willReturn('https://example.tld/index.php/lostpassword/'); $message = $this->createMock(Message::class); $message - ->expects($this->at(0)) + ->expects($this->once()) ->method('setTo') - ->with(['test@example.com' => 'ExistingUser']); + ->with(['test@example.com' => 'Existing User']); $message - ->expects($this->at(1)) + ->expects($this->once()) ->method('setFrom') ->with(['lostpassword-noreply@localhost' => null]); @@ -509,32 +388,26 @@ class LostControllerTest extends \Test\TestCase { ->willReturn('text body'); $message - ->expects($this->at(2)) + ->expects($this->once()) ->method('useTemplate') ->with($emailTemplate); $this->mailer - ->expects($this->at(0)) + ->expects($this->once()) ->method('createEMailTemplate') ->willReturn($emailTemplate); $this->mailer - ->expects($this->at(1)) + ->expects($this->once()) ->method('createMessage') ->willReturn($message); $this->mailer - ->expects($this->at(2)) + ->expects($this->once()) ->method('send') ->with($message) - ->will($this->throwException(new \Exception())); - - $this->crypto->method('encrypt') - ->with( - $this->equalTo('12348:ThisIsMaybeANotSoSecretToken!'), - $this->equalTo('test@example.comSECRET') - )->willReturn('encryptedToken'); + ->willThrowException(new \Exception()); $this->logger->expects($this->exactly(1)) - ->method('logException'); + ->method('error'); $response = $this->lostController->email('ExistingUser'); $expectedResponse = new JSONResponse(['status' => 'success']); @@ -542,7 +415,7 @@ class LostControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $response); } - public function testSetPasswordUnsuccessful() { + public function testSetPasswordUnsuccessful(): void { $this->config->method('getUserValue') ->with('ValidTokenUser', 'core', 'lostpassword', null) ->willReturn('encryptedData'); @@ -555,23 +428,20 @@ class LostControllerTest extends \Test\TestCase { $this->userManager->method('get') ->with('ValidTokenUser') ->willReturn($this->existingUser); + $beforePasswordResetEvent = new BeforePasswordResetEvent($this->existingUser, 'NewPassword'); + $this->eventDispatcher + ->expects($this->once()) + ->method('dispatchTyped') + ->with($beforePasswordResetEvent); $this->config->expects($this->never()) ->method('deleteUserValue'); - $this->timeFactory->method('getTime') - ->willReturn(12348); - - $this->crypto->method('decrypt') - ->with( - $this->equalTo('encryptedData'), - $this->equalTo('test@example.comSECRET') - )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword'); $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', true); $expectedResponse = ['status' => 'error', 'msg' => '']; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testSetPasswordSuccessful() { + public function testSetPasswordSuccessful(): void { $this->config->method('getUserValue') ->with('ValidTokenUser', 'core', 'lostpassword', null) ->willReturn('encryptedData'); @@ -584,48 +454,48 @@ class LostControllerTest extends \Test\TestCase { $this->userManager->method('get') ->with('ValidTokenUser') ->willReturn($this->existingUser); + + $calls = [ + [new BeforePasswordResetEvent($this->existingUser, 'NewPassword')], + [new PasswordResetEvent($this->existingUser, 'NewPassword')], + ]; + $this->eventDispatcher + ->expects($this->exactly(2)) + ->method('dispatchTyped') + ->willReturnCallback(function () use (&$calls): void { + $expected = array_shift($calls); + $this->assertEquals($expected, func_get_args()); + }); + $this->config->expects($this->once()) ->method('deleteUserValue') ->with('ValidTokenUser', 'core', 'lostpassword'); - $this->timeFactory->method('getTime') - ->willReturn(12348); - - $this->crypto->method('decrypt') - ->with( - $this->equalTo('encryptedData'), - $this->equalTo('test@example.comSECRET') - )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword'); $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', true); $expectedResponse = ['user' => 'ValidTokenUser', 'status' => 'success']; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testSetPasswordExpiredToken() { + public function testSetPasswordExpiredToken(): void { $this->config->method('getUserValue') ->with('ValidTokenUser', 'core', 'lostpassword', null) ->willReturn('encryptedData'); $this->userManager->method('get') ->with('ValidTokenUser') ->willReturn($this->existingUser); - $this->timeFactory->method('getTime') - ->willReturn(617146); - - $this->crypto->method('decrypt') - ->with( - $this->equalTo('encryptedData'), - $this->equalTo('test@example.comSECRET') - )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword'); + $this->verificationToken->expects($this->atLeastOnce()) + ->method('check') + ->willThrowException(new InvalidTokenException(InvalidTokenException::TOKEN_EXPIRED)); $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', true); $expectedResponse = [ 'status' => 'error', - 'msg' => 'Couldn\'t reset password because the token is expired', + 'msg' => 'Could not reset password because the token is expired', ]; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testSetPasswordInvalidDataInDb() { + public function testSetPasswordInvalidDataInDb(): void { $this->config->method('getUserValue') ->with('ValidTokenUser', 'core', 'lostpassword', null) ->willReturn('invalidEncryptedData'); @@ -633,94 +503,47 @@ class LostControllerTest extends \Test\TestCase { ->method('get') ->with('ValidTokenUser') ->willReturn($this->existingUser); - - $this->crypto->method('decrypt') - ->with( - $this->equalTo('invalidEncryptedData'), - $this->equalTo('test@example.comSECRET') - )->willReturn('TheOnlyAndOnlyOneTokenToResetThePassword'); - - $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', true); - $expectedResponse = [ - 'status' => 'error', - 'msg' => 'Couldn\'t reset password because the token is invalid', - ]; - $this->assertSame($expectedResponse, $response); - } - - public function testSetPasswordExpiredTokenDueToLogin() { - $this->config->method('getUserValue') - ->with('ValidTokenUser', 'core', 'lostpassword', null) - ->willReturn('encryptedData'); - $this->existingUser->method('getLastLogin') - ->willReturn(12346); - $this->userManager - ->method('get') - ->with('ValidTokenUser') - ->willReturn($this->existingUser); - $this->timeFactory - ->method('getTime') - ->willReturn(12345); - - $this->crypto->method('decrypt') - ->with( - $this->equalTo('encryptedData'), - $this->equalTo('test@example.comSECRET') - )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword'); + $this->verificationToken->expects($this->atLeastOnce()) + ->method('check') + ->willThrowException(new InvalidTokenException(InvalidTokenException::TOKEN_INVALID_FORMAT)); $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', true); $expectedResponse = [ 'status' => 'error', - 'msg' => 'Couldn\'t reset password because the token is expired', + 'msg' => 'Could not reset password because the token is invalid', ]; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testIsSetPasswordWithoutTokenFailing() { + public function testIsSetPasswordWithoutTokenFailing(): void { $this->config->method('getUserValue') ->with('ValidTokenUser', 'core', 'lostpassword', null) ->willReturn('aValidtoken'); $this->userManager->method('get') ->with('ValidTokenUser') ->willReturn($this->existingUser); - - $this->crypto->method('decrypt') - ->with( - $this->equalTo('aValidtoken'), - $this->equalTo('test@example.comSECRET') - )->willThrowException(new \Exception()); + $this->verificationToken->expects($this->atLeastOnce()) + ->method('check') + ->willThrowException(new InvalidTokenException(InvalidTokenException::TOKEN_MISMATCH)); $response = $this->lostController->setPassword('', 'ValidTokenUser', 'NewPassword', true); $expectedResponse = [ 'status' => 'error', - 'msg' => 'Couldn\'t reset password because the token is invalid' + 'msg' => 'Could not reset password because the token is invalid' ]; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testIsSetPasswordTokenNullFailing() { - $this->config->method('getUserValue') - ->with('ValidTokenUser', 'core', 'lostpassword', null) - ->willReturn(null); - $this->userManager->method('get') - ->with('ValidTokenUser') - ->willReturn($this->existingUser); - - $response = $this->lostController->setPassword('', 'ValidTokenUser', 'NewPassword', true); - $expectedResponse = [ - 'status' => 'error', - 'msg' => 'Couldn\'t reset password because the token is invalid' - ]; - $this->assertSame($expectedResponse, $response); - } - - public function testSetPasswordForDisabledUser() { + public function testSetPasswordForDisabledUser(): void { $user = $this->createMock(IUser::class); $user->expects($this->any()) ->method('isEnabled') ->willReturn(false); $user->expects($this->never()) ->method('setPassword'); + $user->expects($this->any()) + ->method('getEMailAddress') + ->willReturn('random@example.org'); $this->config->method('getUserValue') ->with('ValidTokenUser', 'core', 'lostpassword', null) @@ -729,15 +552,19 @@ class LostControllerTest extends \Test\TestCase { ->with('DisabledUser') ->willReturn($user); + $this->verificationToken->expects($this->atLeastOnce()) + ->method('check') + ->willThrowException(new InvalidTokenException(InvalidTokenException::USER_UNKNOWN)); + $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'DisabledUser', 'NewPassword', true); $expectedResponse = [ 'status' => 'error', - 'msg' => 'Couldn\'t reset password because the token is invalid' + 'msg' => 'Could not reset password because the token is invalid' ]; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testSendEmailNoEmail() { + public function testSendEmailNoEmail(): void { $user = $this->createMock(IUser::class); $user->expects($this->any()) ->method('isEnabled') @@ -750,7 +577,7 @@ class LostControllerTest extends \Test\TestCase { ->willReturn($user); $this->logger->expects($this->exactly(0)) - ->method('logException'); + ->method('error'); $this->logger->expects($this->once()) ->method('warning'); @@ -760,8 +587,8 @@ class LostControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $response); } - public function testSetPasswordEncryptionDontProceedPerUserKey() { - /** @var IEncryptionModule|\PHPUnit\Framework\MockObject\MockObject $encryptionModule */ + public function testSetPasswordEncryptionDontProceedPerUserKey(): void { + /** @var IEncryptionModule|MockObject $encryptionModule */ $encryptionModule = $this->createMock(IEncryptionModule::class); $encryptionModule->expects($this->once())->method('needDetailedAccessList')->willReturn(true); $this->encryptionManager->expects($this->once())->method('getEncryptionModules') @@ -770,10 +597,10 @@ class LostControllerTest extends \Test\TestCase { }]]); $response = $this->lostController->setPassword('myToken', 'user', 'newpass', false); $expectedResponse = ['status' => 'error', 'msg' => '', 'encryption' => true]; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testSetPasswordDontProceedMasterKey() { + public function testSetPasswordDontProceedMasterKey(): void { $encryptionModule = $this->createMock(IEncryptionModule::class); $encryptionModule->expects($this->once())->method('needDetailedAccessList')->willReturn(false); $this->encryptionManager->expects($this->once())->method('getEncryptionModules') @@ -795,21 +622,13 @@ class LostControllerTest extends \Test\TestCase { $this->config->expects($this->once()) ->method('deleteUserValue') ->with('ValidTokenUser', 'core', 'lostpassword'); - $this->timeFactory->method('getTime') - ->willReturn(12348); - - $this->crypto->method('decrypt') - ->with( - $this->equalTo('encryptedData'), - $this->equalTo('test@example.comSECRET') - )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword'); $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', false); $expectedResponse = ['user' => 'ValidTokenUser', 'status' => 'success']; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testTwoUsersWithSameEmail() { + public function testTwoUsersWithSameEmail(): void { $user1 = $this->createMock(IUser::class); $user1->expects($this->any()) ->method('getEMailAddress') @@ -841,7 +660,7 @@ class LostControllerTest extends \Test\TestCase { ->willReturn([$user1, $user2]); $this->logger->expects($this->exactly(0)) - ->method('logException'); + ->method('error'); $this->logger->expects($this->once()) ->method('warning'); @@ -860,18 +679,18 @@ class LostControllerTest extends \Test\TestCase { /** * @return array */ - public function dataTwoUserswithSameEmailOneDisabled(): array { + public static function dataTwoUsersWithSameEmailOneDisabled(): array { return [ - ['user1' => true, 'user2' => false], - ['user1' => false, 'user2' => true] + ['userEnabled1' => true, 'userEnabled2' => false], + ['userEnabled1' => false, 'userEnabled2' => true] ]; } /** - * @dataProvider dataTwoUserswithSameEmailOneDisabled * @param bool $userEnabled1 * @param bool $userEnabled2 */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataTwoUsersWithSameEmailOneDisabled')] public function testTwoUsersWithSameEmailOneDisabled(bool $userEnabled1, bool $userEnabled2): void { $user1 = $this->createMock(IUser::class); $user1->method('getEMailAddress') @@ -900,4 +719,38 @@ class LostControllerTest extends \Test\TestCase { $result = self::invokePrivate($this->lostController, 'findUserByIdOrMail', ['test@example.com']); $this->assertInstanceOf(IUser::class, $result); } + + public function testTrimEmailInput(): void { + $this->userManager + ->expects($this->once()) + ->method('getByEmail') + ->with('test@example.com') + ->willReturn([$this->existingUser]); + + $this->mailer + ->expects($this->once()) + ->method('send'); + + $response = $this->lostController->email(' test@example.com '); + $expectedResponse = new JSONResponse(['status' => 'success']); + $expectedResponse->throttle(); + $this->assertEquals($expectedResponse, $response); + } + + public function testUsernameInput(): void { + $this->userManager + ->expects($this->once()) + ->method('get') + ->with('ExistingUser') + ->willReturn($this->existingUser); + + $this->mailer + ->expects($this->once()) + ->method('send'); + + $response = $this->lostController->email(' ExistingUser '); + $expectedResponse = new JSONResponse(['status' => 'success']); + $expectedResponse->throttle(); + $this->assertEquals($expectedResponse, $response); + } } |