You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LostControllerTest.php 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900
  1. <?php
  2. /**
  3. * @author Lukas Reschke <lukas@owncloud.com>
  4. *
  5. * @copyright Copyright (c) 2015, ownCloud, Inc.
  6. * @license AGPL-3.0
  7. *
  8. * This code is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License, version 3,
  10. * as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License, version 3,
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>
  19. *
  20. */
  21. namespace Tests\Core\Controller;
  22. use OC\Authentication\TwoFactorAuth\Manager;
  23. use OC\Core\Controller\LostController;
  24. use OC\Mail\Message;
  25. use OCP\AppFramework\Http\JSONResponse;
  26. use OCP\AppFramework\Http\TemplateResponse;
  27. use OCP\AppFramework\Utility\ITimeFactory;
  28. use OCP\Defaults;
  29. use OCP\Encryption\IEncryptionModule;
  30. use OCP\Encryption\IManager;
  31. use OCP\IConfig;
  32. use OCP\IInitialStateService;
  33. use OCP\IL10N;
  34. use OCP\ILogger;
  35. use OCP\IRequest;
  36. use OCP\IURLGenerator;
  37. use OCP\IUser;
  38. use OCP\IUserManager;
  39. use OCP\Mail\IEMailTemplate;
  40. use OCP\Mail\IMailer;
  41. use OCP\Security\ICrypto;
  42. use OCP\Security\ISecureRandom;
  43. use PHPUnit_Framework_MockObject_MockObject;
  44. /**
  45. * Class LostControllerTest
  46. *
  47. * @package OC\Core\Controller
  48. */
  49. class LostControllerTest extends \Test\TestCase {
  50. /** @var LostController */
  51. private $lostController;
  52. /** @var IUser */
  53. private $existingUser;
  54. /** @var IURLGenerator | PHPUnit_Framework_MockObject_MockObject */
  55. private $urlGenerator;
  56. /** @var IL10N */
  57. private $l10n;
  58. /** @var IUserManager | PHPUnit_Framework_MockObject_MockObject */
  59. private $userManager;
  60. /** @var Defaults */
  61. private $defaults;
  62. /** @var IConfig | PHPUnit_Framework_MockObject_MockObject */
  63. private $config;
  64. /** @var IMailer | PHPUnit_Framework_MockObject_MockObject */
  65. private $mailer;
  66. /** @var ISecureRandom | PHPUnit_Framework_MockObject_MockObject */
  67. private $secureRandom;
  68. /** @var IManager|PHPUnit_Framework_MockObject_MockObject */
  69. private $encryptionManager;
  70. /** @var ITimeFactory | PHPUnit_Framework_MockObject_MockObject */
  71. private $timeFactory;
  72. /** @var IRequest */
  73. private $request;
  74. /** @var ICrypto|\PHPUnit_Framework_MockObject_MockObject */
  75. private $crypto;
  76. /** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */
  77. private $logger;
  78. /** @var Manager|\PHPUnit_Framework_MockObject_MockObject */
  79. private $twofactorManager;
  80. /** @var IInitialStateService|\PHPUnit_Framework_MockObject_MockObject */
  81. private $initialStateService;
  82. protected function setUp() {
  83. parent::setUp();
  84. $this->existingUser = $this->createMock(IUser::class);
  85. $this->existingUser->expects($this->any())
  86. ->method('getEMailAddress')
  87. ->willReturn('test@example.com');
  88. $this->existingUser->expects($this->any())
  89. ->method('getUID')
  90. ->willReturn('ExistingUser');
  91. $this->existingUser->expects($this->any())
  92. ->method('isEnabled')
  93. ->willReturn(true);
  94. $this->config = $this->createMock(IConfig::class);
  95. $this->config->expects($this->any())
  96. ->method('getSystemValue')
  97. ->willReturnMap([
  98. ['secret', null, 'SECRET'],
  99. ['secret', '', 'SECRET'],
  100. ['lost_password_link', '', ''],
  101. ]);
  102. $this->l10n = $this->createMock(IL10N::class);
  103. $this->l10n
  104. ->expects($this->any())
  105. ->method('t')
  106. ->will($this->returnCallback(function($text, $parameters = array()) {
  107. return vsprintf($text, $parameters);
  108. }));
  109. $this->defaults = $this->getMockBuilder('\OCP\Defaults')
  110. ->disableOriginalConstructor()->getMock();
  111. $this->userManager = $this->getMockBuilder(IUserManager::class)
  112. ->disableOriginalConstructor()->getMock();
  113. $this->urlGenerator = $this->getMockBuilder(IURLGenerator::class)
  114. ->disableOriginalConstructor()->getMock();
  115. $this->mailer = $this->getMockBuilder('\OCP\Mail\IMailer')
  116. ->disableOriginalConstructor()->getMock();
  117. $this->secureRandom = $this->getMockBuilder('\OCP\Security\ISecureRandom')
  118. ->disableOriginalConstructor()->getMock();
  119. $this->timeFactory = $this->getMockBuilder('\OCP\AppFramework\Utility\ITimeFactory')
  120. ->disableOriginalConstructor()->getMock();
  121. $this->request = $this->getMockBuilder(IRequest::class)
  122. ->disableOriginalConstructor()->getMock();
  123. $this->encryptionManager = $this->getMockBuilder(IManager::class)
  124. ->disableOriginalConstructor()->getMock();
  125. $this->encryptionManager->expects($this->any())
  126. ->method('isEnabled')
  127. ->willReturn(true);
  128. $this->crypto = $this->createMock(ICrypto::class);
  129. $this->logger = $this->createMock(ILogger::class);
  130. $this->twofactorManager = $this->createMock(Manager::class);
  131. $this->initialStateService = $this->createMock(IInitialStateService::class);
  132. $this->lostController = new LostController(
  133. 'Core',
  134. $this->request,
  135. $this->urlGenerator,
  136. $this->userManager,
  137. $this->defaults,
  138. $this->l10n,
  139. $this->config,
  140. $this->secureRandom,
  141. 'lostpassword-noreply@localhost',
  142. $this->encryptionManager,
  143. $this->mailer,
  144. $this->timeFactory,
  145. $this->crypto,
  146. $this->logger,
  147. $this->twofactorManager,
  148. $this->initialStateService
  149. );
  150. }
  151. public function testResetFormWithNotExistingUser() {
  152. $this->userManager->method('get')
  153. ->with('NotExistingUser')
  154. ->willReturn(null);
  155. $expectedResponse = new TemplateResponse(
  156. 'core',
  157. 'error',
  158. [
  159. 'errors' => [
  160. ['error' => 'Couldn\'t reset password because the token is invalid'],
  161. ]
  162. ],
  163. 'guest'
  164. );
  165. $this->assertEquals($expectedResponse, $this->lostController->resetform('MySecretToken', 'NotExistingUser'));
  166. }
  167. public function testResetFormInvalidTokenMatch() {
  168. $this->config->method('getUserValue')
  169. ->with('ValidTokenUser', 'core', 'lostpassword', null)
  170. ->willReturn('encryptedToken');
  171. $this->existingUser->method('getLastLogin')
  172. ->will($this->returnValue(12344));
  173. $this->userManager->method('get')
  174. ->with('ValidTokenUser')
  175. ->willReturn($this->existingUser);
  176. $this->crypto->method('decrypt')
  177. ->with(
  178. $this->equalTo('encryptedToken'),
  179. $this->equalTo('test@example.comSECRET')
  180. )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword');
  181. $response = $this->lostController->resetform('12345:MySecretToken', 'ValidTokenUser');
  182. $expectedResponse = new TemplateResponse('core',
  183. 'error',
  184. [
  185. 'errors' => [
  186. ['error' => 'Couldn\'t reset password because the token is invalid'],
  187. ]
  188. ],
  189. 'guest');
  190. $this->assertEquals($expectedResponse, $response);
  191. }
  192. public function testResetFormExpiredToken() {
  193. $this->userManager->method('get')
  194. ->with('ValidTokenUser')
  195. ->willReturn($this->existingUser);
  196. $this->config
  197. ->expects($this->once())
  198. ->method('getUserValue')
  199. ->with('ValidTokenUser', 'core', 'lostpassword', null)
  200. ->will($this->returnValue('encryptedToken'));
  201. $this->crypto->method('decrypt')
  202. ->with(
  203. $this->equalTo('encryptedToken'),
  204. $this->equalTo('test@example.comSECRET')
  205. )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword');
  206. $this->timeFactory
  207. ->expects($this->once())
  208. ->method('getTime')
  209. ->willReturn(999999);
  210. $response = $this->lostController->resetform('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser');
  211. $expectedResponse = new TemplateResponse('core',
  212. 'error',
  213. [
  214. 'errors' => [
  215. ['error' => 'Couldn\'t reset password because the token is expired'],
  216. ]
  217. ],
  218. 'guest');
  219. $this->assertEquals($expectedResponse, $response);
  220. }
  221. public function testResetFormValidToken() {
  222. $this->existingUser->method('getLastLogin')
  223. ->willReturn(12344);
  224. $this->userManager->method('get')
  225. ->with('ValidTokenUser')
  226. ->willReturn($this->existingUser);
  227. $this->timeFactory
  228. ->expects($this->once())
  229. ->method('getTime')
  230. ->willReturn(12348);
  231. $this->config->method('getUserValue')
  232. ->with('ValidTokenUser', 'core', 'lostpassword', null)
  233. ->willReturn('encryptedToken');
  234. $this->crypto->method('decrypt')
  235. ->with(
  236. $this->equalTo('encryptedToken'),
  237. $this->equalTo('test@example.comSECRET')
  238. )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword');
  239. $this->urlGenerator
  240. ->expects($this->once())
  241. ->method('linkToRouteAbsolute')
  242. ->with('core.lost.setPassword', array('userId' => 'ValidTokenUser', 'token' => 'TheOnlyAndOnlyOneTokenToResetThePassword'))
  243. ->will($this->returnValue('https://example.tld/index.php/lostpassword/'));
  244. $this->initialStateService->expects($this->at(0))
  245. ->method('provideInitialState')
  246. ->with('core', 'resetPasswordUser', 'ValidTokenUser');
  247. $this->initialStateService->expects($this->at(1))
  248. ->method('provideInitialState')
  249. ->with('core', 'resetPasswordTarget', 'https://example.tld/index.php/lostpassword/');
  250. $response = $this->lostController->resetform('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser');
  251. $expectedResponse = new TemplateResponse('core',
  252. 'login',
  253. [],
  254. 'guest');
  255. $this->assertEquals($expectedResponse, $response);
  256. }
  257. public function testEmailUnsuccessful() {
  258. $existingUser = 'ExistingUser';
  259. $nonExistingUser = 'NonExistingUser';
  260. $this->userManager
  261. ->expects($this->any())
  262. ->method('userExists')
  263. ->will($this->returnValueMap(array(
  264. array(true, $existingUser),
  265. array(false, $nonExistingUser)
  266. )));
  267. $this->logger->expects($this->exactly(0))
  268. ->method('logException');
  269. $this->logger->expects($this->exactly(2))
  270. ->method('warning');
  271. $this->userManager
  272. ->method('getByEmail')
  273. ->willReturn([]);
  274. // With a non existing user
  275. $response = $this->lostController->email($nonExistingUser);
  276. $expectedResponse = new JSONResponse([
  277. 'status' => 'success',
  278. ]);
  279. $expectedResponse->throttle();
  280. $this->assertEquals($expectedResponse, $response);
  281. // With no mail address
  282. $this->config
  283. ->expects($this->any())
  284. ->method('getUserValue')
  285. ->with($existingUser, 'settings', 'email')
  286. ->will($this->returnValue(null));
  287. $response = $this->lostController->email($existingUser);
  288. $expectedResponse = new JSONResponse([
  289. 'status' => 'success',
  290. ]);
  291. $expectedResponse->throttle();
  292. $this->assertEquals($expectedResponse, $response);
  293. }
  294. public function testEmailSuccessful() {
  295. $this->secureRandom
  296. ->expects($this->once())
  297. ->method('generate')
  298. ->with('21')
  299. ->will($this->returnValue('ThisIsMaybeANotSoSecretToken!'));
  300. $this->userManager
  301. ->expects($this->any())
  302. ->method('get')
  303. ->with('ExistingUser')
  304. ->willReturn($this->existingUser);
  305. $this->timeFactory
  306. ->expects($this->once())
  307. ->method('getTime')
  308. ->will($this->returnValue(12348));
  309. $this->config
  310. ->expects($this->once())
  311. ->method('setUserValue')
  312. ->with('ExistingUser', 'core', 'lostpassword', 'encryptedToken');
  313. $this->urlGenerator
  314. ->expects($this->once())
  315. ->method('linkToRouteAbsolute')
  316. ->with('core.lost.resetform', array('userId' => 'ExistingUser', 'token' => 'ThisIsMaybeANotSoSecretToken!'))
  317. ->will($this->returnValue('https://example.tld/index.php/lostpassword/'));
  318. $message = $this->getMockBuilder('\OC\Mail\Message')
  319. ->disableOriginalConstructor()->getMock();
  320. $message
  321. ->expects($this->at(0))
  322. ->method('setTo')
  323. ->with(['test@example.com' => 'ExistingUser']);
  324. $message
  325. ->expects($this->at(1))
  326. ->method('setFrom')
  327. ->with(['lostpassword-noreply@localhost' => null]);
  328. $emailTemplate = $this->createMock(IEMailTemplate::class);
  329. $emailTemplate->expects($this->any())
  330. ->method('renderHtml')
  331. ->willReturn('HTML body');
  332. $emailTemplate->expects($this->any())
  333. ->method('renderText')
  334. ->willReturn('text body');
  335. $message
  336. ->expects($this->at(2))
  337. ->method('useTemplate')
  338. ->with($emailTemplate);
  339. $this->mailer
  340. ->expects($this->at(0))
  341. ->method('createEMailTemplate')
  342. ->willReturn($emailTemplate);
  343. $this->mailer
  344. ->expects($this->at(1))
  345. ->method('createMessage')
  346. ->will($this->returnValue($message));
  347. $this->mailer
  348. ->expects($this->at(2))
  349. ->method('send')
  350. ->with($message);
  351. $this->crypto->method('encrypt')
  352. ->with(
  353. $this->equalTo('12348:ThisIsMaybeANotSoSecretToken!'),
  354. $this->equalTo('test@example.comSECRET')
  355. )->willReturn('encryptedToken');
  356. $response = $this->lostController->email('ExistingUser');
  357. $expectedResponse = new JSONResponse(['status' => 'success']);
  358. $expectedResponse->throttle();
  359. $this->assertEquals($expectedResponse, $response);
  360. }
  361. public function testEmailWithMailSuccessful() {
  362. $this->secureRandom
  363. ->expects($this->once())
  364. ->method('generate')
  365. ->with('21')
  366. ->will($this->returnValue('ThisIsMaybeANotSoSecretToken!'));
  367. $this->userManager
  368. ->expects($this->any())
  369. ->method('get')
  370. ->with('test@example.com')
  371. ->willReturn(null);
  372. $this->userManager
  373. ->expects($this->any())
  374. ->method('getByEmail')
  375. ->with('test@example.com')
  376. ->willReturn([$this->existingUser]);
  377. $this->timeFactory
  378. ->expects($this->once())
  379. ->method('getTime')
  380. ->will($this->returnValue(12348));
  381. $this->config
  382. ->expects($this->once())
  383. ->method('setUserValue')
  384. ->with('ExistingUser', 'core', 'lostpassword', 'encryptedToken');
  385. $this->urlGenerator
  386. ->expects($this->once())
  387. ->method('linkToRouteAbsolute')
  388. ->with('core.lost.resetform', array('userId' => 'ExistingUser', 'token' => 'ThisIsMaybeANotSoSecretToken!'))
  389. ->will($this->returnValue('https://example.tld/index.php/lostpassword/'));
  390. $message = $this->getMockBuilder('\OC\Mail\Message')
  391. ->disableOriginalConstructor()->getMock();
  392. $message
  393. ->expects($this->at(0))
  394. ->method('setTo')
  395. ->with(['test@example.com' => 'ExistingUser']);
  396. $message
  397. ->expects($this->at(1))
  398. ->method('setFrom')
  399. ->with(['lostpassword-noreply@localhost' => null]);
  400. $emailTemplate = $this->createMock(IEMailTemplate::class);
  401. $emailTemplate->expects($this->any())
  402. ->method('renderHtml')
  403. ->willReturn('HTML body');
  404. $emailTemplate->expects($this->any())
  405. ->method('renderText')
  406. ->willReturn('text body');
  407. $message
  408. ->expects($this->at(2))
  409. ->method('useTemplate')
  410. ->with($emailTemplate);
  411. $this->mailer
  412. ->expects($this->at(0))
  413. ->method('createEMailTemplate')
  414. ->willReturn($emailTemplate);
  415. $this->mailer
  416. ->expects($this->at(1))
  417. ->method('createMessage')
  418. ->will($this->returnValue($message));
  419. $this->mailer
  420. ->expects($this->at(2))
  421. ->method('send')
  422. ->with($message);
  423. $this->crypto->method('encrypt')
  424. ->with(
  425. $this->equalTo('12348:ThisIsMaybeANotSoSecretToken!'),
  426. $this->equalTo('test@example.comSECRET')
  427. )->willReturn('encryptedToken');
  428. $response = $this->lostController->email('test@example.com');
  429. $expectedResponse = new JSONResponse(['status' => 'success']);
  430. $expectedResponse->throttle();
  431. $this->assertEquals($expectedResponse, $response);
  432. }
  433. public function testEmailCantSendException() {
  434. $this->secureRandom
  435. ->expects($this->once())
  436. ->method('generate')
  437. ->with('21')
  438. ->will($this->returnValue('ThisIsMaybeANotSoSecretToken!'));
  439. $this->userManager
  440. ->expects($this->any())
  441. ->method('get')
  442. ->with('ExistingUser')
  443. ->willReturn($this->existingUser);
  444. $this->config
  445. ->expects($this->once())
  446. ->method('setUserValue')
  447. ->with('ExistingUser', 'core', 'lostpassword', 'encryptedToken');
  448. $this->timeFactory
  449. ->expects($this->once())
  450. ->method('getTime')
  451. ->will($this->returnValue(12348));
  452. $this->urlGenerator
  453. ->expects($this->once())
  454. ->method('linkToRouteAbsolute')
  455. ->with('core.lost.resetform', array('userId' => 'ExistingUser', 'token' => 'ThisIsMaybeANotSoSecretToken!'))
  456. ->will($this->returnValue('https://example.tld/index.php/lostpassword/'));
  457. $message = $this->createMock(Message::class);
  458. $message
  459. ->expects($this->at(0))
  460. ->method('setTo')
  461. ->with(['test@example.com' => 'ExistingUser']);
  462. $message
  463. ->expects($this->at(1))
  464. ->method('setFrom')
  465. ->with(['lostpassword-noreply@localhost' => null]);
  466. $emailTemplate = $this->createMock(IEMailTemplate::class);
  467. $emailTemplate->expects($this->any())
  468. ->method('renderHtml')
  469. ->willReturn('HTML body');
  470. $emailTemplate->expects($this->any())
  471. ->method('renderText')
  472. ->willReturn('text body');
  473. $message
  474. ->expects($this->at(2))
  475. ->method('useTemplate')
  476. ->with($emailTemplate);
  477. $this->mailer
  478. ->expects($this->at(0))
  479. ->method('createEMailTemplate')
  480. ->willReturn($emailTemplate);
  481. $this->mailer
  482. ->expects($this->at(1))
  483. ->method('createMessage')
  484. ->will($this->returnValue($message));
  485. $this->mailer
  486. ->expects($this->at(2))
  487. ->method('send')
  488. ->with($message)
  489. ->will($this->throwException(new \Exception()));
  490. $this->crypto->method('encrypt')
  491. ->with(
  492. $this->equalTo('12348:ThisIsMaybeANotSoSecretToken!'),
  493. $this->equalTo('test@example.comSECRET')
  494. )->willReturn('encryptedToken');
  495. $this->logger->expects($this->exactly(1))
  496. ->method('logException');
  497. $response = $this->lostController->email('ExistingUser');
  498. $expectedResponse = new JSONResponse(['status' => 'success']);
  499. $expectedResponse->throttle();
  500. $this->assertEquals($expectedResponse, $response);
  501. }
  502. public function testSetPasswordUnsuccessful() {
  503. $this->config->method('getUserValue')
  504. ->with('ValidTokenUser', 'core', 'lostpassword', null)
  505. ->willReturn('encryptedData');
  506. $this->existingUser->method('getLastLogin')
  507. ->will($this->returnValue(12344));
  508. $this->existingUser->expects($this->once())
  509. ->method('setPassword')
  510. ->with('NewPassword')
  511. ->willReturn(false);
  512. $this->userManager->method('get')
  513. ->with('ValidTokenUser')
  514. ->willReturn($this->existingUser);
  515. $this->config->expects($this->never())
  516. ->method('deleteUserValue');
  517. $this->timeFactory->method('getTime')
  518. ->will($this->returnValue(12348));
  519. $this->crypto->method('decrypt')
  520. ->with(
  521. $this->equalTo('encryptedData'),
  522. $this->equalTo('test@example.comSECRET')
  523. )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword');
  524. $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', true);
  525. $expectedResponse = array('status' => 'error', 'msg' => '');
  526. $this->assertSame($expectedResponse, $response);
  527. }
  528. public function testSetPasswordSuccessful() {
  529. $this->config->method('getUserValue')
  530. ->with('ValidTokenUser', 'core', 'lostpassword', null)
  531. ->willReturn('encryptedData');
  532. $this->existingUser->method('getLastLogin')
  533. ->will($this->returnValue(12344));
  534. $this->existingUser->expects($this->once())
  535. ->method('setPassword')
  536. ->with('NewPassword')
  537. ->willReturn(true);
  538. $this->userManager->method('get')
  539. ->with('ValidTokenUser')
  540. ->willReturn($this->existingUser);
  541. $this->config->expects($this->once())
  542. ->method('deleteUserValue')
  543. ->with('ValidTokenUser', 'core', 'lostpassword');
  544. $this->timeFactory->method('getTime')
  545. ->will($this->returnValue(12348));
  546. $this->crypto->method('decrypt')
  547. ->with(
  548. $this->equalTo('encryptedData'),
  549. $this->equalTo('test@example.comSECRET')
  550. )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword');
  551. $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', true);
  552. $expectedResponse = array('user' => 'ValidTokenUser', 'status' => 'success');
  553. $this->assertSame($expectedResponse, $response);
  554. }
  555. public function testSetPasswordExpiredToken() {
  556. $this->config->method('getUserValue')
  557. ->with('ValidTokenUser', 'core', 'lostpassword', null)
  558. ->willReturn('encryptedData');
  559. $this->userManager->method('get')
  560. ->with('ValidTokenUser')
  561. ->willReturn($this->existingUser);
  562. $this->timeFactory->method('getTime')
  563. ->willReturn(617146);
  564. $this->crypto->method('decrypt')
  565. ->with(
  566. $this->equalTo('encryptedData'),
  567. $this->equalTo('test@example.comSECRET')
  568. )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword');
  569. $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', true);
  570. $expectedResponse = [
  571. 'status' => 'error',
  572. 'msg' => 'Couldn\'t reset password because the token is expired',
  573. ];
  574. $this->assertSame($expectedResponse, $response);
  575. }
  576. public function testSetPasswordInvalidDataInDb() {
  577. $this->config->method('getUserValue')
  578. ->with('ValidTokenUser', 'core', 'lostpassword', null)
  579. ->willReturn('invalidEncryptedData');
  580. $this->userManager
  581. ->method('get')
  582. ->with('ValidTokenUser')
  583. ->willReturn($this->existingUser);
  584. $this->crypto->method('decrypt')
  585. ->with(
  586. $this->equalTo('invalidEncryptedData'),
  587. $this->equalTo('test@example.comSECRET')
  588. )->willReturn('TheOnlyAndOnlyOneTokenToResetThePassword');
  589. $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', true);
  590. $expectedResponse = [
  591. 'status' => 'error',
  592. 'msg' => 'Couldn\'t reset password because the token is invalid',
  593. ];
  594. $this->assertSame($expectedResponse, $response);
  595. }
  596. public function testSetPasswordExpiredTokenDueToLogin() {
  597. $this->config->method('getUserValue')
  598. ->with('ValidTokenUser', 'core', 'lostpassword', null)
  599. ->willReturn('encryptedData');
  600. $this->existingUser->method('getLastLogin')
  601. ->will($this->returnValue(12346));
  602. $this->userManager
  603. ->method('get')
  604. ->with('ValidTokenUser')
  605. ->willReturn($this->existingUser);
  606. $this->timeFactory
  607. ->method('getTime')
  608. ->will($this->returnValue(12345));
  609. $this->crypto->method('decrypt')
  610. ->with(
  611. $this->equalTo('encryptedData'),
  612. $this->equalTo('test@example.comSECRET')
  613. )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword');
  614. $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', true);
  615. $expectedResponse = [
  616. 'status' => 'error',
  617. 'msg' => 'Couldn\'t reset password because the token is expired',
  618. ];
  619. $this->assertSame($expectedResponse, $response);
  620. }
  621. public function testIsSetPasswordWithoutTokenFailing() {
  622. $this->config->method('getUserValue')
  623. ->with('ValidTokenUser', 'core', 'lostpassword', null)
  624. ->willReturn('aValidtoken');
  625. $this->userManager->method('get')
  626. ->with('ValidTokenUser')
  627. ->willReturn($this->existingUser);
  628. $this->crypto->method('decrypt')
  629. ->with(
  630. $this->equalTo('aValidtoken'),
  631. $this->equalTo('test@example.comSECRET')
  632. )->willThrowException(new \Exception());
  633. $response = $this->lostController->setPassword('', 'ValidTokenUser', 'NewPassword', true);
  634. $expectedResponse = [
  635. 'status' => 'error',
  636. 'msg' => 'Couldn\'t reset password because the token is invalid'
  637. ];
  638. $this->assertSame($expectedResponse, $response);
  639. }
  640. public function testIsSetPasswordTokenNullFailing() {
  641. $this->config->method('getUserValue')
  642. ->with('ValidTokenUser', 'core', 'lostpassword', null)
  643. ->willReturn(null);
  644. $this->userManager->method('get')
  645. ->with('ValidTokenUser')
  646. ->willReturn($this->existingUser);
  647. $response = $this->lostController->setPassword('', 'ValidTokenUser', 'NewPassword', true);
  648. $expectedResponse = [
  649. 'status' => 'error',
  650. 'msg' => 'Couldn\'t reset password because the token is invalid'
  651. ];
  652. $this->assertSame($expectedResponse, $response);
  653. }
  654. public function testSetPasswordForDisabledUser() {
  655. $user = $this->createMock(IUser::class);
  656. $user->expects($this->any())
  657. ->method('isEnabled')
  658. ->willReturn(false);
  659. $user->expects($this->never())
  660. ->method('setPassword');
  661. $this->config->method('getUserValue')
  662. ->with('ValidTokenUser', 'core', 'lostpassword', null)
  663. ->willReturn('encryptedData');
  664. $this->userManager->method('get')
  665. ->with('DisabledUser')
  666. ->willReturn($user);
  667. $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'DisabledUser', 'NewPassword', true);
  668. $expectedResponse = [
  669. 'status' => 'error',
  670. 'msg' => 'Couldn\'t reset password because the token is invalid'
  671. ];
  672. $this->assertSame($expectedResponse, $response);
  673. }
  674. public function testSendEmailNoEmail() {
  675. $user = $this->createMock(IUser::class);
  676. $user->expects($this->any())
  677. ->method('isEnabled')
  678. ->willReturn(true);
  679. $this->userManager->method('userExists')
  680. ->with('ExistingUser')
  681. ->willReturn(true);
  682. $this->userManager->method('get')
  683. ->with('ExistingUser')
  684. ->willReturn($user);
  685. $this->logger->expects($this->exactly(0))
  686. ->method('logException');
  687. $this->logger->expects($this->once())
  688. ->method('warning');
  689. $response = $this->lostController->email('ExistingUser');
  690. $expectedResponse = new JSONResponse(['status' => 'success']);
  691. $expectedResponse->throttle();
  692. $this->assertEquals($expectedResponse, $response);
  693. }
  694. public function testSetPasswordEncryptionDontProceedPerUserKey() {
  695. /** @var IEncryptionModule|PHPUnit_Framework_MockObject_MockObject $encryptionModule */
  696. $encryptionModule = $this->createMock(IEncryptionModule::class);
  697. $encryptionModule->expects($this->once())->method('needDetailedAccessList')->willReturn(true);
  698. $this->encryptionManager->expects($this->once())->method('getEncryptionModules')
  699. ->willReturn([0 => ['callback' => function() use ($encryptionModule) { return $encryptionModule; }]]);
  700. $response = $this->lostController->setPassword('myToken', 'user', 'newpass', false);
  701. $expectedResponse = ['status' => 'error', 'msg' => '', 'encryption' => true];
  702. $this->assertSame($expectedResponse, $response);
  703. }
  704. public function testSetPasswordDontProceedMasterKey() {
  705. $encryptionModule = $this->createMock(IEncryptionModule::class);
  706. $encryptionModule->expects($this->once())->method('needDetailedAccessList')->willReturn(false);
  707. $this->encryptionManager->expects($this->once())->method('getEncryptionModules')
  708. ->willReturn([0 => ['callback' => function() use ($encryptionModule) { return $encryptionModule; }]]);
  709. $this->config->method('getUserValue')
  710. ->with('ValidTokenUser', 'core', 'lostpassword', null)
  711. ->willReturn('encryptedData');
  712. $this->existingUser->method('getLastLogin')
  713. ->will($this->returnValue(12344));
  714. $this->existingUser->expects($this->once())
  715. ->method('setPassword')
  716. ->with('NewPassword')
  717. ->willReturn(true);
  718. $this->userManager->method('get')
  719. ->with('ValidTokenUser')
  720. ->willReturn($this->existingUser);
  721. $this->config->expects($this->once())
  722. ->method('deleteUserValue')
  723. ->with('ValidTokenUser', 'core', 'lostpassword');
  724. $this->timeFactory->method('getTime')
  725. ->will($this->returnValue(12348));
  726. $this->crypto->method('decrypt')
  727. ->with(
  728. $this->equalTo('encryptedData'),
  729. $this->equalTo('test@example.comSECRET')
  730. )->willReturn('12345:TheOnlyAndOnlyOneTokenToResetThePassword');
  731. $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', false);
  732. $expectedResponse = array('user' => 'ValidTokenUser', 'status' => 'success');
  733. $this->assertSame($expectedResponse, $response);
  734. }
  735. public function testTwoUsersWithSameEmail() {
  736. $user1 = $this->createMock(IUser::class);
  737. $user1->expects($this->any())
  738. ->method('getEMailAddress')
  739. ->willReturn('test@example.com');
  740. $user1->expects($this->any())
  741. ->method('getUID')
  742. ->willReturn('User1');
  743. $user1->expects($this->any())
  744. ->method('isEnabled')
  745. ->willReturn(true);
  746. $user2 = $this->createMock(IUser::class);
  747. $user2->expects($this->any())
  748. ->method('getEMailAddress')
  749. ->willReturn('test@example.com');
  750. $user2->expects($this->any())
  751. ->method('getUID')
  752. ->willReturn('User2');
  753. $user2->expects($this->any())
  754. ->method('isEnabled')
  755. ->willReturn(true);
  756. $this->userManager
  757. ->method('get')
  758. ->willReturn(null);
  759. $this->userManager
  760. ->method('getByEmail')
  761. ->willReturn([$user1, $user2]);
  762. $this->logger->expects($this->exactly(0))
  763. ->method('logException');
  764. $this->logger->expects($this->once())
  765. ->method('warning');
  766. // request password reset for test@example.com
  767. $response = $this->lostController->email('test@example.com');
  768. $expectedResponse = new JSONResponse([
  769. 'status' => 'success'
  770. ]);
  771. $expectedResponse->throttle();
  772. $this->assertEquals($expectedResponse, $response);
  773. }
  774. /**
  775. * @return array
  776. */
  777. public function dataTwoUserswithSameEmailOneDisabled(): array {
  778. return [
  779. ['user1' => true, 'user2' => false],
  780. ['user1' => false, 'user2' => true]
  781. ];
  782. }
  783. /**
  784. * @dataProvider dataTwoUserswithSameEmailOneDisabled
  785. * @param bool $userEnabled1
  786. * @param bool $userEnabled2
  787. */
  788. public function testTwoUsersWithSameEmailOneDisabled(bool $userEnabled1, bool $userEnabled2): void {
  789. $user1 = $this->createMock(IUser::class);
  790. $user1->method('getEMailAddress')
  791. ->willReturn('test@example.com');
  792. $user1->method('getUID')
  793. ->willReturn('User1');
  794. $user1->method('isEnabled')
  795. ->willReturn($userEnabled1);
  796. $user2 = $this->createMock(IUser::class);
  797. $user2->method('getEMailAddress')
  798. ->willReturn('test@example.com');
  799. $user2->method('getUID')
  800. ->willReturn('User2');
  801. $user2->method('isEnabled')
  802. ->willReturn($userEnabled2);
  803. $this->userManager
  804. ->method('get')
  805. ->willReturn(null);
  806. $this->userManager
  807. ->method('getByEmail')
  808. ->willReturn([$user1, $user2]);
  809. $result = self::invokePrivate($this->lostController, 'findUserByIdOrMail', ['test@example.com']);
  810. $this->assertInstanceOf(IUser::class, $result);
  811. }
  812. }