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.

LoginControllerTest.php 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. <?php
  2. /**
  3. * @author Lukas Reschke <lukas@owncloud.com>
  4. *
  5. * @copyright Copyright (c) 2016, 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\Token\IToken;
  23. use OC\Authentication\TwoFactorAuth\Manager;
  24. use OC\Authentication\TwoFactorAuth\ProviderSet;
  25. use OC\Core\Controller\LoginController;
  26. use OC\Security\Bruteforce\Throttler;
  27. use OC\User\Session;
  28. use OCP\AppFramework\Http\RedirectResponse;
  29. use OCP\AppFramework\Http\TemplateResponse;
  30. use OCP\Authentication\TwoFactorAuth\IProvider;
  31. use OCP\Defaults;
  32. use OCP\IConfig;
  33. use OCP\ILogger;
  34. use OCP\IRequest;
  35. use OCP\ISession;
  36. use OCP\IURLGenerator;
  37. use OCP\IUser;
  38. use OCP\IUserManager;
  39. use Test\TestCase;
  40. class LoginControllerTest extends TestCase {
  41. /** @var LoginController */
  42. private $loginController;
  43. /** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */
  44. private $request;
  45. /** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */
  46. private $userManager;
  47. /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
  48. private $config;
  49. /** @var ISession|\PHPUnit_Framework_MockObject_MockObject */
  50. private $session;
  51. /** @var Session|\PHPUnit_Framework_MockObject_MockObject */
  52. private $userSession;
  53. /** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */
  54. private $urlGenerator;
  55. /** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */
  56. private $logger;
  57. /** @var Manager|\PHPUnit_Framework_MockObject_MockObject */
  58. private $twoFactorManager;
  59. /** @var Defaults|\PHPUnit_Framework_MockObject_MockObject */
  60. private $defaults;
  61. /** @var Throttler|\PHPUnit_Framework_MockObject_MockObject */
  62. private $throttler;
  63. public function setUp() {
  64. parent::setUp();
  65. $this->request = $this->createMock(IRequest::class);
  66. $this->userManager = $this->createMock(\OC\User\Manager::class);
  67. $this->config = $this->createMock(IConfig::class);
  68. $this->session = $this->createMock(ISession::class);
  69. $this->userSession = $this->createMock(Session::class);
  70. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  71. $this->logger = $this->createMock(ILogger::class);
  72. $this->twoFactorManager = $this->createMock(Manager::class);
  73. $this->defaults = $this->createMock(Defaults::class);
  74. $this->throttler = $this->createMock(Throttler::class);
  75. $this->request->method('getRemoteAddress')
  76. ->willReturn('1.2.3.4');
  77. $this->throttler->method('getDelay')
  78. ->with(
  79. $this->equalTo('1.2.3.4'),
  80. $this->equalTo('')
  81. )->willReturn(1000);
  82. $this->loginController = new LoginController(
  83. 'core',
  84. $this->request,
  85. $this->userManager,
  86. $this->config,
  87. $this->session,
  88. $this->userSession,
  89. $this->urlGenerator,
  90. $this->logger,
  91. $this->twoFactorManager,
  92. $this->defaults,
  93. $this->throttler
  94. );
  95. }
  96. public function testLogoutWithoutToken() {
  97. $this->request
  98. ->expects($this->once())
  99. ->method('getCookie')
  100. ->with('nc_token')
  101. ->willReturn(null);
  102. $this->config
  103. ->expects($this->never())
  104. ->method('deleteUserValue');
  105. $this->urlGenerator
  106. ->expects($this->once())
  107. ->method('linkToRouteAbsolute')
  108. ->with('core.login.showLoginForm')
  109. ->willReturn('/login');
  110. $expected = new RedirectResponse('/login');
  111. $expected->addHeader('Clear-Site-Data', '"cache", "cookies", "storage", "executionContexts"');
  112. $this->assertEquals($expected, $this->loginController->logout());
  113. }
  114. public function testLogoutWithToken() {
  115. $this->request
  116. ->expects($this->once())
  117. ->method('getCookie')
  118. ->with('nc_token')
  119. ->willReturn('MyLoginToken');
  120. $user = $this->createMock(IUser::class);
  121. $user
  122. ->expects($this->once())
  123. ->method('getUID')
  124. ->willReturn('JohnDoe');
  125. $this->userSession
  126. ->expects($this->once())
  127. ->method('getUser')
  128. ->willReturn($user);
  129. $this->config
  130. ->expects($this->once())
  131. ->method('deleteUserValue')
  132. ->with('JohnDoe', 'login_token', 'MyLoginToken');
  133. $this->urlGenerator
  134. ->expects($this->once())
  135. ->method('linkToRouteAbsolute')
  136. ->with('core.login.showLoginForm')
  137. ->willReturn('/login');
  138. $expected = new RedirectResponse('/login');
  139. $expected->addHeader('Clear-Site-Data', '"cache", "cookies", "storage", "executionContexts"');
  140. $this->assertEquals($expected, $this->loginController->logout());
  141. }
  142. public function testShowLoginFormForLoggedInUsers() {
  143. $this->userSession
  144. ->expects($this->once())
  145. ->method('isLoggedIn')
  146. ->willReturn(true);
  147. $expectedResponse = new RedirectResponse(\OC_Util::getDefaultPageUrl());
  148. $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('', '', ''));
  149. }
  150. public function testShowLoginFormWithErrorsInSession() {
  151. $this->userSession
  152. ->expects($this->once())
  153. ->method('isLoggedIn')
  154. ->willReturn(false);
  155. $this->session
  156. ->expects($this->once())
  157. ->method('get')
  158. ->with('loginMessages')
  159. ->willReturn(
  160. [
  161. [
  162. 'ErrorArray1',
  163. 'ErrorArray2',
  164. ],
  165. [
  166. 'MessageArray1',
  167. 'MessageArray2',
  168. ],
  169. ]
  170. );
  171. $expectedResponse = new TemplateResponse(
  172. 'core',
  173. 'login',
  174. [
  175. 'ErrorArray1' => true,
  176. 'ErrorArray2' => true,
  177. 'messages' => [
  178. 'MessageArray1',
  179. 'MessageArray2',
  180. ],
  181. 'loginName' => '',
  182. 'user_autofocus' => true,
  183. 'canResetPassword' => true,
  184. 'alt_login' => [],
  185. 'resetPasswordLink' => null,
  186. 'throttle_delay' => 1000,
  187. ],
  188. 'guest'
  189. );
  190. $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('', '', ''));
  191. }
  192. public function testShowLoginFormForFlowAuth() {
  193. $this->userSession
  194. ->expects($this->once())
  195. ->method('isLoggedIn')
  196. ->willReturn(false);
  197. $expectedResponse = new TemplateResponse(
  198. 'core',
  199. 'login',
  200. [
  201. 'messages' => [],
  202. 'redirect_url' => 'login/flow',
  203. 'loginName' => '',
  204. 'user_autofocus' => true,
  205. 'canResetPassword' => true,
  206. 'alt_login' => [],
  207. 'resetPasswordLink' => null,
  208. 'throttle_delay' => 1000,
  209. ],
  210. 'guest'
  211. );
  212. $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('', 'login/flow', ''));
  213. }
  214. /**
  215. * @return array
  216. */
  217. public function passwordResetDataProvider() {
  218. return [
  219. [
  220. true,
  221. true,
  222. ],
  223. [
  224. false,
  225. false,
  226. ],
  227. ];
  228. }
  229. /**
  230. * @dataProvider passwordResetDataProvider
  231. */
  232. public function testShowLoginFormWithPasswordResetOption($canChangePassword,
  233. $expectedResult) {
  234. $this->userSession
  235. ->expects($this->once())
  236. ->method('isLoggedIn')
  237. ->willReturn(false);
  238. $this->config
  239. ->expects($this->once())
  240. ->method('getSystemValue')
  241. ->with('lost_password_link')
  242. ->willReturn(false);
  243. $user = $this->createMock(IUser::class);
  244. $user
  245. ->expects($this->once())
  246. ->method('canChangePassword')
  247. ->willReturn($canChangePassword);
  248. $this->userManager
  249. ->expects($this->once())
  250. ->method('get')
  251. ->with('LdapUser')
  252. ->willReturn($user);
  253. $expectedResponse = new TemplateResponse(
  254. 'core',
  255. 'login',
  256. [
  257. 'messages' => [],
  258. 'loginName' => 'LdapUser',
  259. 'user_autofocus' => false,
  260. 'canResetPassword' => $expectedResult,
  261. 'alt_login' => [],
  262. 'resetPasswordLink' => false,
  263. 'throttle_delay' => 1000,
  264. ],
  265. 'guest'
  266. );
  267. $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('LdapUser', '', ''));
  268. }
  269. public function testShowLoginFormForUserNamedNull() {
  270. $this->userSession
  271. ->expects($this->once())
  272. ->method('isLoggedIn')
  273. ->willReturn(false);
  274. $this->config
  275. ->expects($this->once())
  276. ->method('getSystemValue')
  277. ->with('lost_password_link')
  278. ->willReturn(false);
  279. $user = $this->createMock(IUser::class);
  280. $user
  281. ->expects($this->once())
  282. ->method('canChangePassword')
  283. ->willReturn(false);
  284. $this->userManager
  285. ->expects($this->once())
  286. ->method('get')
  287. ->with('0')
  288. ->willReturn($user);
  289. $expectedResponse = new TemplateResponse(
  290. 'core',
  291. 'login',
  292. [
  293. 'messages' => [],
  294. 'loginName' => '0',
  295. 'user_autofocus' => false,
  296. 'canResetPassword' => false,
  297. 'alt_login' => [],
  298. 'resetPasswordLink' => false,
  299. 'throttle_delay' => 1000,
  300. ],
  301. 'guest'
  302. );
  303. $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('0', '', ''));
  304. }
  305. public function testLoginWithInvalidCredentials() {
  306. $user = 'MyUserName';
  307. $password = 'secret';
  308. $loginPageUrl = '/login?redirect_url=/apps/files';
  309. $this->request
  310. ->expects($this->once())
  311. ->method('passesCSRFCheck')
  312. ->willReturn(true);
  313. $this->userManager->expects($this->once())
  314. ->method('checkPasswordNoLogging')
  315. ->will($this->returnValue(false));
  316. $this->userManager->expects($this->once())
  317. ->method('getByEmail')
  318. ->with($user)
  319. ->willReturn([]);
  320. $this->urlGenerator->expects($this->once())
  321. ->method('linkToRoute')
  322. ->with('core.login.showLoginForm', [
  323. 'user' => 'MyUserName',
  324. 'redirect_url' => '/apps/files',
  325. ])
  326. ->will($this->returnValue($loginPageUrl));
  327. $this->userSession->expects($this->never())
  328. ->method('createSessionToken');
  329. $this->userSession->expects($this->never())
  330. ->method('createRememberMeToken');
  331. $this->config->expects($this->never())
  332. ->method('deleteUserValue');
  333. $expected = new \OCP\AppFramework\Http\RedirectResponse($loginPageUrl);
  334. $expected->throttle(['user' => 'MyUserName']);
  335. $this->assertEquals($expected, $this->loginController->tryLogin($user, $password, '/apps/files'));
  336. }
  337. public function testLoginWithValidCredentials() {
  338. /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
  339. $user = $this->createMock(IUser::class);
  340. $user->expects($this->any())
  341. ->method('getUID')
  342. ->will($this->returnValue('uid'));
  343. $loginName = 'loginli';
  344. $user->expects($this->any())
  345. ->method('getLastLogin')
  346. ->willReturn(123456);
  347. $password = 'secret';
  348. $indexPageUrl = \OC_Util::getDefaultPageUrl();
  349. $this->request
  350. ->expects($this->once())
  351. ->method('passesCSRFCheck')
  352. ->willReturn(true);
  353. $this->userManager->expects($this->once())
  354. ->method('checkPasswordNoLogging')
  355. ->will($this->returnValue($user));
  356. $this->userSession->expects($this->once())
  357. ->method('completeLogin')
  358. ->with($user, ['loginName' => $loginName, 'password' => $password]);
  359. $this->userSession->expects($this->once())
  360. ->method('createSessionToken')
  361. ->with($this->request, $user->getUID(), $loginName, $password, IToken::REMEMBER);
  362. $this->twoFactorManager->expects($this->once())
  363. ->method('isTwoFactorAuthenticated')
  364. ->with($user)
  365. ->will($this->returnValue(false));
  366. $this->config->expects($this->once())
  367. ->method('deleteUserValue')
  368. ->with('uid', 'core', 'lostpassword');
  369. $this->config->expects($this->once())
  370. ->method('setUserValue')
  371. ->with('uid', 'core', 'timezone', 'Europe/Berlin');
  372. $this->userSession->expects($this->never())
  373. ->method('createRememberMeToken');
  374. $this->session->expects($this->exactly(2))
  375. ->method('set')
  376. ->withConsecutive(
  377. ['last-password-confirm', 123456],
  378. ['timezone', '1']
  379. );
  380. $expected = new \OCP\AppFramework\Http\RedirectResponse($indexPageUrl);
  381. $this->assertEquals($expected, $this->loginController->tryLogin($loginName, $password, null, false, 'Europe/Berlin', '1'));
  382. }
  383. public function testLoginWithValidCredentialsAndRememberMe() {
  384. /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
  385. $user = $this->createMock(IUser::class);
  386. $user->expects($this->any())
  387. ->method('getUID')
  388. ->will($this->returnValue('uid'));
  389. $loginName = 'loginli';
  390. $password = 'secret';
  391. $indexPageUrl = \OC_Util::getDefaultPageUrl();
  392. $this->request
  393. ->expects($this->once())
  394. ->method('passesCSRFCheck')
  395. ->willReturn(true);
  396. $this->userManager->expects($this->once())
  397. ->method('checkPasswordNoLogging')
  398. ->will($this->returnValue($user));
  399. $this->userSession->expects($this->once())
  400. ->method('completeLogin')
  401. ->with($user, ['loginName' => $loginName, 'password' => $password]);
  402. $this->userSession->expects($this->once())
  403. ->method('createSessionToken')
  404. ->with($this->request, $user->getUID(), $loginName, $password, true);
  405. $this->twoFactorManager->expects($this->once())
  406. ->method('isTwoFactorAuthenticated')
  407. ->with($user)
  408. ->will($this->returnValue(false));
  409. $this->config->expects($this->once())
  410. ->method('deleteUserValue')
  411. ->with('uid', 'core', 'lostpassword');
  412. $this->userSession->expects($this->once())
  413. ->method('createRememberMeToken')
  414. ->with($user);
  415. $expected = new \OCP\AppFramework\Http\RedirectResponse($indexPageUrl);
  416. $this->assertEquals($expected, $this->loginController->tryLogin($loginName, $password, null, true));
  417. }
  418. public function testLoginWithoutPassedCsrfCheckAndNotLoggedIn() {
  419. /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
  420. $user = $this->createMock(IUser::class);
  421. $user->expects($this->any())
  422. ->method('getUID')
  423. ->will($this->returnValue('jane'));
  424. $password = 'secret';
  425. $originalUrl = 'another%20url';
  426. $this->request
  427. ->expects($this->once())
  428. ->method('passesCSRFCheck')
  429. ->willReturn(false);
  430. $this->userSession->expects($this->once())
  431. ->method('isLoggedIn')
  432. ->with()
  433. ->will($this->returnValue(false));
  434. $this->config->expects($this->never())
  435. ->method('deleteUserValue');
  436. $this->userSession->expects($this->never())
  437. ->method('createRememberMeToken');
  438. $expected = new \OCP\AppFramework\Http\RedirectResponse(\OC_Util::getDefaultPageUrl());
  439. $this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl));
  440. }
  441. public function testLoginWithoutPassedCsrfCheckAndLoggedIn() {
  442. /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
  443. $user = $this->createMock(IUser::class);
  444. $user->expects($this->any())
  445. ->method('getUID')
  446. ->will($this->returnValue('jane'));
  447. $password = 'secret';
  448. $originalUrl = 'another%20url';
  449. $redirectUrl = 'http://localhost/another url';
  450. $this->request
  451. ->expects($this->once())
  452. ->method('passesCSRFCheck')
  453. ->willReturn(false);
  454. $this->userSession->expects($this->once())
  455. ->method('isLoggedIn')
  456. ->with()
  457. ->will($this->returnValue(true));
  458. $this->urlGenerator->expects($this->once())
  459. ->method('getAbsoluteURL')
  460. ->with(urldecode($originalUrl))
  461. ->will($this->returnValue($redirectUrl));
  462. $this->config->expects($this->never())
  463. ->method('deleteUserValue');
  464. $this->userSession->expects($this->never())
  465. ->method('createRememberMeToken');
  466. $expected = new \OCP\AppFramework\Http\RedirectResponse($redirectUrl);
  467. $this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl));
  468. }
  469. public function testLoginWithValidCredentialsAndRedirectUrl() {
  470. /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
  471. $user = $this->createMock(IUser::class);
  472. $user->expects($this->any())
  473. ->method('getUID')
  474. ->will($this->returnValue('jane'));
  475. $password = 'secret';
  476. $originalUrl = 'another%20url';
  477. $redirectUrl = 'http://localhost/another url';
  478. $this->request
  479. ->expects($this->once())
  480. ->method('passesCSRFCheck')
  481. ->willReturn(true);
  482. $this->userManager->expects($this->once())
  483. ->method('checkPasswordNoLogging')
  484. ->with('Jane', $password)
  485. ->will($this->returnValue($user));
  486. $this->userSession->expects($this->once())
  487. ->method('createSessionToken')
  488. ->with($this->request, $user->getUID(), 'Jane', $password, IToken::REMEMBER);
  489. $this->userSession->expects($this->once())
  490. ->method('isLoggedIn')
  491. ->with()
  492. ->will($this->returnValue(true));
  493. $this->urlGenerator->expects($this->once())
  494. ->method('getAbsoluteURL')
  495. ->with(urldecode($originalUrl))
  496. ->will($this->returnValue($redirectUrl));
  497. $this->config->expects($this->once())
  498. ->method('deleteUserValue')
  499. ->with('jane', 'core', 'lostpassword');
  500. $expected = new \OCP\AppFramework\Http\RedirectResponse(urldecode($redirectUrl));
  501. $this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl));
  502. }
  503. public function testLoginWithOneTwoFactorProvider() {
  504. /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
  505. $user = $this->createMock(IUser::class);
  506. $user->expects($this->any())
  507. ->method('getUID')
  508. ->will($this->returnValue('john'));
  509. $password = 'secret';
  510. $challengeUrl = 'challenge/url';
  511. $provider = $this->createMock(IProvider::class);
  512. $this->request
  513. ->expects($this->once())
  514. ->method('passesCSRFCheck')
  515. ->willReturn(true);
  516. $this->userManager->expects($this->once())
  517. ->method('checkPasswordNoLogging')
  518. ->will($this->returnValue($user));
  519. $this->userSession->expects($this->once())
  520. ->method('completeLogin')
  521. ->with($user, ['loginName' => 'john@doe.com', 'password' => $password]);
  522. $this->userSession->expects($this->once())
  523. ->method('createSessionToken')
  524. ->with($this->request, $user->getUID(), 'john@doe.com', $password, IToken::REMEMBER);
  525. $this->twoFactorManager->expects($this->once())
  526. ->method('isTwoFactorAuthenticated')
  527. ->with($user)
  528. ->will($this->returnValue(true));
  529. $this->twoFactorManager->expects($this->once())
  530. ->method('prepareTwoFactorLogin')
  531. ->with($user);
  532. $providerSet = new ProviderSet([$provider], false);
  533. $this->twoFactorManager->expects($this->once())
  534. ->method('getProviderSet')
  535. ->with($user)
  536. ->willReturn($providerSet);
  537. $provider->expects($this->once())
  538. ->method('getId')
  539. ->will($this->returnValue('u2f'));
  540. $this->urlGenerator->expects($this->once())
  541. ->method('linkToRoute')
  542. ->with('core.TwoFactorChallenge.showChallenge', [
  543. 'challengeProviderId' => 'u2f',
  544. ])
  545. ->will($this->returnValue($challengeUrl));
  546. $this->config->expects($this->once())
  547. ->method('deleteUserValue')
  548. ->with('john', 'core', 'lostpassword');
  549. $this->userSession->expects($this->never())
  550. ->method('createRememberMeToken');
  551. $expected = new RedirectResponse($challengeUrl);
  552. $this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', $password, null));
  553. }
  554. public function testLoginWithMultipleTwoFactorProviders() {
  555. /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
  556. $user = $this->createMock(IUser::class);
  557. $user->expects($this->any())
  558. ->method('getUID')
  559. ->will($this->returnValue('john'));
  560. $password = 'secret';
  561. $challengeUrl = 'challenge/url';
  562. $provider1 = $this->createMock(IProvider::class);
  563. $provider2 = $this->createMock(IProvider::class);
  564. $provider1->method('getId')->willReturn('prov1');
  565. $provider2->method('getId')->willReturn('prov2');
  566. $this->request
  567. ->expects($this->once())
  568. ->method('passesCSRFCheck')
  569. ->willReturn(true);
  570. $this->userManager->expects($this->once())
  571. ->method('checkPasswordNoLogging')
  572. ->will($this->returnValue($user));
  573. $this->userSession->expects($this->once())
  574. ->method('completeLogin')
  575. ->with($user, ['loginName' => 'john@doe.com', 'password' => $password]);
  576. $this->userSession->expects($this->once())
  577. ->method('createSessionToken')
  578. ->with($this->request, $user->getUID(), 'john@doe.com', $password, IToken::REMEMBER);
  579. $this->twoFactorManager->expects($this->once())
  580. ->method('isTwoFactorAuthenticated')
  581. ->with($user)
  582. ->will($this->returnValue(true));
  583. $this->twoFactorManager->expects($this->once())
  584. ->method('prepareTwoFactorLogin')
  585. ->with($user);
  586. $providerSet = new ProviderSet([$provider1, $provider2], false);
  587. $this->twoFactorManager->expects($this->once())
  588. ->method('getProviderSet')
  589. ->with($user)
  590. ->willReturn($providerSet);
  591. $this->urlGenerator->expects($this->once())
  592. ->method('linkToRoute')
  593. ->with('core.TwoFactorChallenge.selectChallenge')
  594. ->will($this->returnValue($challengeUrl));
  595. $this->config->expects($this->once())
  596. ->method('deleteUserValue')
  597. ->with('john', 'core', 'lostpassword');
  598. $this->userSession->expects($this->never())
  599. ->method('createRememberMeToken');
  600. $expected = new RedirectResponse($challengeUrl);
  601. $this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', $password, null));
  602. }
  603. public function testToNotLeakLoginName() {
  604. /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
  605. $user = $this->createMock(IUser::class);
  606. $user->expects($this->any())
  607. ->method('getUID')
  608. ->will($this->returnValue('john'));
  609. $this->userManager->expects($this->once())
  610. ->method('checkPasswordNoLogging')
  611. ->with('john@doe.com', 'just wrong')
  612. ->willReturn(false);
  613. $this->userManager->expects($this->once())
  614. ->method('checkPassword')
  615. ->with('john', 'just wrong')
  616. ->willReturn(false);
  617. $this->userManager->expects($this->once())
  618. ->method('getByEmail')
  619. ->with('john@doe.com')
  620. ->willReturn([$user]);
  621. $this->urlGenerator->expects($this->once())
  622. ->method('linkToRoute')
  623. ->with('core.login.showLoginForm', ['user' => 'john@doe.com'])
  624. ->will($this->returnValue(''));
  625. $this->request
  626. ->expects($this->once())
  627. ->method('passesCSRFCheck')
  628. ->willReturn(true);
  629. $this->config->expects($this->never())
  630. ->method('deleteUserValue');
  631. $this->userSession->expects($this->never())
  632. ->method('createRememberMeToken');
  633. $expected = new RedirectResponse('');
  634. $expected->throttle(['user' => 'john']);
  635. $this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', 'just wrong', null));
  636. }
  637. }