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 23KB

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