ManagerTest.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace Test\Authentication\TwoFactorAuth;
  8. use OC;
  9. use OC\Authentication\Token\IProvider as TokenProvider;
  10. use OC\Authentication\TwoFactorAuth\Manager;
  11. use OC\Authentication\TwoFactorAuth\MandatoryTwoFactor;
  12. use OC\Authentication\TwoFactorAuth\ProviderLoader;
  13. use OCP\Activity\IEvent;
  14. use OCP\Activity\IManager;
  15. use OCP\AppFramework\Db\DoesNotExistException;
  16. use OCP\AppFramework\Utility\ITimeFactory;
  17. use OCP\Authentication\TwoFactorAuth\IActivatableAtLogin;
  18. use OCP\Authentication\TwoFactorAuth\IProvider;
  19. use OCP\Authentication\TwoFactorAuth\IRegistry;
  20. use OCP\EventDispatcher\IEventDispatcher;
  21. use OCP\IConfig;
  22. use OCP\ISession;
  23. use OCP\IUser;
  24. use PHPUnit\Framework\MockObject\MockObject;
  25. use Psr\Log\LoggerInterface;
  26. use Test\TestCase;
  27. use function reset;
  28. class ManagerTest extends TestCase {
  29. /** @var IUser|MockObject */
  30. private $user;
  31. /** @var ProviderLoader|MockObject */
  32. private $providerLoader;
  33. /** @var IRegistry|MockObject */
  34. private $providerRegistry;
  35. /** @var MandatoryTwoFactor|MockObject */
  36. private $mandatoryTwoFactor;
  37. /** @var ISession|MockObject */
  38. private $session;
  39. /** @var Manager */
  40. private $manager;
  41. /** @var IConfig|MockObject */
  42. private $config;
  43. /** @var IManager|MockObject */
  44. private $activityManager;
  45. /** @var LoggerInterface|MockObject */
  46. private $logger;
  47. /** @var IProvider|MockObject */
  48. private $fakeProvider;
  49. /** @var IProvider|MockObject */
  50. private $backupProvider;
  51. /** @var TokenProvider|MockObject */
  52. private $tokenProvider;
  53. /** @var ITimeFactory|MockObject */
  54. private $timeFactory;
  55. /** @var IEventDispatcher|MockObject */
  56. private $dispatcher;
  57. protected function setUp(): void {
  58. parent::setUp();
  59. $this->user = $this->createMock(IUser::class);
  60. $this->providerLoader = $this->createMock(ProviderLoader::class);
  61. $this->providerRegistry = $this->createMock(IRegistry::class);
  62. $this->mandatoryTwoFactor = $this->createMock(MandatoryTwoFactor::class);
  63. $this->session = $this->createMock(ISession::class);
  64. $this->config = $this->createMock(IConfig::class);
  65. $this->activityManager = $this->createMock(IManager::class);
  66. $this->logger = $this->createMock(LoggerInterface::class);
  67. $this->tokenProvider = $this->createMock(TokenProvider::class);
  68. $this->timeFactory = $this->createMock(ITimeFactory::class);
  69. $this->dispatcher = $this->createMock(IEventDispatcher::class);
  70. $this->manager = new Manager(
  71. $this->providerLoader,
  72. $this->providerRegistry,
  73. $this->mandatoryTwoFactor,
  74. $this->session,
  75. $this->config,
  76. $this->activityManager,
  77. $this->logger,
  78. $this->tokenProvider,
  79. $this->timeFactory,
  80. $this->dispatcher,
  81. );
  82. $this->fakeProvider = $this->createMock(IProvider::class);
  83. $this->fakeProvider->method('getId')->willReturn('email');
  84. $this->backupProvider = $this->getMockBuilder('\OCP\Authentication\TwoFactorAuth\IProvider')->getMock();
  85. $this->backupProvider->method('getId')->willReturn('backup_codes');
  86. $this->backupProvider->method('isTwoFactorAuthEnabledForUser')->willReturn(true);
  87. }
  88. private function prepareNoProviders() {
  89. $this->providerLoader->method('getProviders')
  90. ->with($this->user)
  91. ->willReturn([]);
  92. }
  93. private function prepareProviders() {
  94. $this->providerRegistry->expects($this->once())
  95. ->method('getProviderStates')
  96. ->with($this->user)
  97. ->willReturn([
  98. $this->fakeProvider->getId() => true,
  99. ]);
  100. $this->providerLoader->expects($this->once())
  101. ->method('getProviders')
  102. ->with($this->user)
  103. ->willReturn([$this->fakeProvider]);
  104. }
  105. private function prepareProvidersWitBackupProvider() {
  106. $this->providerLoader->method('getProviders')
  107. ->with($this->user)
  108. ->willReturn([
  109. $this->fakeProvider,
  110. $this->backupProvider,
  111. ]);
  112. }
  113. public function testIsTwoFactorAuthenticatedEnforced(): void {
  114. $this->mandatoryTwoFactor->expects($this->once())
  115. ->method('isEnforcedFor')
  116. ->with($this->user)
  117. ->willReturn(true);
  118. $enabled = $this->manager->isTwoFactorAuthenticated($this->user);
  119. $this->assertTrue($enabled);
  120. }
  121. public function testIsTwoFactorAuthenticatedNoProviders(): void {
  122. $this->mandatoryTwoFactor->expects($this->once())
  123. ->method('isEnforcedFor')
  124. ->with($this->user)
  125. ->willReturn(false);
  126. $this->providerRegistry->expects($this->once())
  127. ->method('getProviderStates')
  128. ->willReturn([]); // No providers registered
  129. $this->providerLoader->expects($this->once())
  130. ->method('getProviders')
  131. ->willReturn([]); // No providers loadable
  132. $this->assertFalse($this->manager->isTwoFactorAuthenticated($this->user));
  133. }
  134. public function testIsTwoFactorAuthenticatedOnlyBackupCodes(): void {
  135. $this->mandatoryTwoFactor->expects($this->once())
  136. ->method('isEnforcedFor')
  137. ->with($this->user)
  138. ->willReturn(false);
  139. $this->providerRegistry->expects($this->once())
  140. ->method('getProviderStates')
  141. ->willReturn([
  142. 'backup_codes' => true,
  143. ]);
  144. $backupCodesProvider = $this->createMock(IProvider::class);
  145. $backupCodesProvider
  146. ->method('getId')
  147. ->willReturn('backup_codes');
  148. $this->providerLoader->expects($this->once())
  149. ->method('getProviders')
  150. ->willReturn([
  151. $backupCodesProvider,
  152. ]);
  153. $this->assertFalse($this->manager->isTwoFactorAuthenticated($this->user));
  154. }
  155. public function testIsTwoFactorAuthenticatedFailingProviders(): void {
  156. $this->mandatoryTwoFactor->expects($this->once())
  157. ->method('isEnforcedFor')
  158. ->with($this->user)
  159. ->willReturn(false);
  160. $this->providerRegistry->expects($this->once())
  161. ->method('getProviderStates')
  162. ->willReturn([
  163. 'twofactor_totp' => true,
  164. 'twofactor_u2f' => false,
  165. ]); // Two providers registered, but …
  166. $this->providerLoader->expects($this->once())
  167. ->method('getProviders')
  168. ->willReturn([]); // … none of them is able to load, however …
  169. // … 2FA is still enforced
  170. $this->assertTrue($this->manager->isTwoFactorAuthenticated($this->user));
  171. }
  172. public function providerStatesFixData(): array {
  173. return [
  174. [false, false],
  175. [true, true],
  176. ];
  177. }
  178. /**
  179. * If the 2FA registry has not been populated when a user logs in,
  180. * the 2FA manager has to first fix the state before it checks for
  181. * enabled providers.
  182. *
  183. * If any of these providers is active, 2FA is enabled
  184. *
  185. * @dataProvider providerStatesFixData
  186. */
  187. public function testIsTwoFactorAuthenticatedFixesProviderStates(bool $providerEnabled, bool $expected): void {
  188. $this->providerRegistry->expects($this->once())
  189. ->method('getProviderStates')
  190. ->willReturn([]); // Nothing registered yet
  191. $this->providerLoader->expects($this->once())
  192. ->method('getProviders')
  193. ->willReturn([
  194. $this->fakeProvider
  195. ]);
  196. $this->fakeProvider->expects($this->once())
  197. ->method('isTwoFactorAuthEnabledForUser')
  198. ->with($this->user)
  199. ->willReturn($providerEnabled);
  200. if ($providerEnabled) {
  201. $this->providerRegistry->expects($this->once())
  202. ->method('enableProviderFor')
  203. ->with(
  204. $this->fakeProvider,
  205. $this->user
  206. );
  207. } else {
  208. $this->providerRegistry->expects($this->once())
  209. ->method('disableProviderFor')
  210. ->with(
  211. $this->fakeProvider,
  212. $this->user
  213. );
  214. }
  215. $this->assertEquals($expected, $this->manager->isTwoFactorAuthenticated($this->user));
  216. }
  217. public function testGetProvider(): void {
  218. $this->providerRegistry->expects($this->once())
  219. ->method('getProviderStates')
  220. ->with($this->user)
  221. ->willReturn([
  222. $this->fakeProvider->getId() => true,
  223. ]);
  224. $this->providerLoader->expects($this->once())
  225. ->method('getProviders')
  226. ->with($this->user)
  227. ->willReturn([$this->fakeProvider]);
  228. $provider = $this->manager->getProvider($this->user, $this->fakeProvider->getId());
  229. $this->assertSame($this->fakeProvider, $provider);
  230. }
  231. public function testGetInvalidProvider(): void {
  232. $this->providerRegistry->expects($this->once())
  233. ->method('getProviderStates')
  234. ->with($this->user)
  235. ->willReturn([]);
  236. $this->providerLoader->expects($this->once())
  237. ->method('getProviders')
  238. ->with($this->user)
  239. ->willReturn([]);
  240. $provider = $this->manager->getProvider($this->user, 'nonexistent');
  241. $this->assertNull($provider);
  242. }
  243. public function testGetLoginSetupProviders(): void {
  244. $provider1 = $this->createMock(IProvider::class);
  245. $provider2 = $this->createMock(IActivatableAtLogin::class);
  246. $this->providerLoader->expects($this->once())
  247. ->method('getProviders')
  248. ->with($this->user)
  249. ->willReturn([
  250. $provider1,
  251. $provider2,
  252. ]);
  253. $providers = $this->manager->getLoginSetupProviders($this->user);
  254. $this->assertCount(1, $providers);
  255. $this->assertSame($provider2, reset($providers));
  256. }
  257. public function testGetProviders(): void {
  258. $this->providerRegistry->expects($this->once())
  259. ->method('getProviderStates')
  260. ->with($this->user)
  261. ->willReturn([
  262. $this->fakeProvider->getId() => true,
  263. ]);
  264. $this->providerLoader->expects($this->once())
  265. ->method('getProviders')
  266. ->with($this->user)
  267. ->willReturn([$this->fakeProvider]);
  268. $expectedProviders = [
  269. 'email' => $this->fakeProvider,
  270. ];
  271. $providerSet = $this->manager->getProviderSet($this->user);
  272. $providers = $providerSet->getProviders();
  273. $this->assertEquals($expectedProviders, $providers);
  274. $this->assertFalse($providerSet->isProviderMissing());
  275. }
  276. public function testGetProvidersOneMissing(): void {
  277. $this->providerRegistry->expects($this->once())
  278. ->method('getProviderStates')
  279. ->with($this->user)
  280. ->willReturn([
  281. $this->fakeProvider->getId() => true,
  282. ]);
  283. $this->providerLoader->expects($this->once())
  284. ->method('getProviders')
  285. ->with($this->user)
  286. ->willReturn([]);
  287. $expectedProviders = [
  288. 'email' => $this->fakeProvider,
  289. ];
  290. $providerSet = $this->manager->getProviderSet($this->user);
  291. $this->assertTrue($providerSet->isProviderMissing());
  292. }
  293. public function testVerifyChallenge(): void {
  294. $this->prepareProviders();
  295. $challenge = 'passme';
  296. $event = $this->createMock(IEvent::class);
  297. $this->fakeProvider->expects($this->once())
  298. ->method('verifyChallenge')
  299. ->with($this->user, $challenge)
  300. ->willReturn(true);
  301. $this->session->expects($this->once())
  302. ->method('get')
  303. ->with('two_factor_remember_login')
  304. ->willReturn(false);
  305. $this->session->expects($this->exactly(2))
  306. ->method('remove')
  307. ->withConsecutive(
  308. ['two_factor_auth_uid'],
  309. ['two_factor_remember_login']
  310. );
  311. $this->session->expects($this->once())
  312. ->method('set')
  313. ->with(Manager::SESSION_UID_DONE, 'jos');
  314. $this->session->method('getId')
  315. ->willReturn('mysessionid');
  316. $this->activityManager->expects($this->once())
  317. ->method('generateEvent')
  318. ->willReturn($event);
  319. $this->user->expects($this->any())
  320. ->method('getUID')
  321. ->willReturn('jos');
  322. $event->expects($this->once())
  323. ->method('setApp')
  324. ->with($this->equalTo('core'))
  325. ->willReturnSelf();
  326. $event->expects($this->once())
  327. ->method('setType')
  328. ->with($this->equalTo('security'))
  329. ->willReturnSelf();
  330. $event->expects($this->once())
  331. ->method('setAuthor')
  332. ->with($this->equalTo('jos'))
  333. ->willReturnSelf();
  334. $event->expects($this->once())
  335. ->method('setAffectedUser')
  336. ->with($this->equalTo('jos'))
  337. ->willReturnSelf();
  338. $this->fakeProvider
  339. ->method('getDisplayName')
  340. ->willReturn('Fake 2FA');
  341. $event->expects($this->once())
  342. ->method('setSubject')
  343. ->with($this->equalTo('twofactor_success'), $this->equalTo([
  344. 'provider' => 'Fake 2FA',
  345. ]))
  346. ->willReturnSelf();
  347. $token = $this->createMock(OC\Authentication\Token\IToken::class);
  348. $this->tokenProvider->method('getToken')
  349. ->with('mysessionid')
  350. ->willReturn($token);
  351. $token->method('getId')
  352. ->willReturn(42);
  353. $this->config->expects($this->once())
  354. ->method('deleteUserValue')
  355. ->with('jos', 'login_token_2fa', '42');
  356. $result = $this->manager->verifyChallenge('email', $this->user, $challenge);
  357. $this->assertTrue($result);
  358. }
  359. public function testVerifyChallengeInvalidProviderId(): void {
  360. $this->prepareProviders();
  361. $challenge = 'passme';
  362. $this->fakeProvider->expects($this->never())
  363. ->method('verifyChallenge')
  364. ->with($this->user, $challenge);
  365. $this->session->expects($this->never())
  366. ->method('remove');
  367. $this->assertFalse($this->manager->verifyChallenge('dontexist', $this->user, $challenge));
  368. }
  369. public function testVerifyInvalidChallenge(): void {
  370. $this->prepareProviders();
  371. $challenge = 'dontpassme';
  372. $event = $this->createMock(IEvent::class);
  373. $this->fakeProvider->expects($this->once())
  374. ->method('verifyChallenge')
  375. ->with($this->user, $challenge)
  376. ->willReturn(false);
  377. $this->session->expects($this->never())
  378. ->method('remove');
  379. $this->activityManager->expects($this->once())
  380. ->method('generateEvent')
  381. ->willReturn($event);
  382. $this->user->expects($this->any())
  383. ->method('getUID')
  384. ->willReturn('jos');
  385. $event->expects($this->once())
  386. ->method('setApp')
  387. ->with($this->equalTo('core'))
  388. ->willReturnSelf();
  389. $event->expects($this->once())
  390. ->method('setType')
  391. ->with($this->equalTo('security'))
  392. ->willReturnSelf();
  393. $event->expects($this->once())
  394. ->method('setAuthor')
  395. ->with($this->equalTo('jos'))
  396. ->willReturnSelf();
  397. $event->expects($this->once())
  398. ->method('setAffectedUser')
  399. ->with($this->equalTo('jos'))
  400. ->willReturnSelf();
  401. $this->fakeProvider
  402. ->method('getDisplayName')
  403. ->willReturn('Fake 2FA');
  404. $event->expects($this->once())
  405. ->method('setSubject')
  406. ->with($this->equalTo('twofactor_failed'), $this->equalTo([
  407. 'provider' => 'Fake 2FA',
  408. ]))
  409. ->willReturnSelf();
  410. $this->assertFalse($this->manager->verifyChallenge('email', $this->user, $challenge));
  411. }
  412. public function testNeedsSecondFactor(): void {
  413. $user = $this->createMock(IUser::class);
  414. $this->session->expects($this->exactly(3))
  415. ->method('exists')
  416. ->withConsecutive(
  417. ['app_password'],
  418. ['two_factor_auth_uid'],
  419. [Manager::SESSION_UID_DONE],
  420. )
  421. ->willReturn(false);
  422. $this->session->method('getId')
  423. ->willReturn('mysessionid');
  424. $token = $this->createMock(OC\Authentication\Token\IToken::class);
  425. $this->tokenProvider->method('getToken')
  426. ->with('mysessionid')
  427. ->willReturn($token);
  428. $token->method('getId')
  429. ->willReturn(42);
  430. $user->method('getUID')
  431. ->willReturn('user');
  432. $this->config->method('getUserKeys')
  433. ->with('user', 'login_token_2fa')
  434. ->willReturn([
  435. '42'
  436. ]);
  437. $manager = $this->getMockBuilder(Manager::class)
  438. ->setConstructorArgs([
  439. $this->providerLoader,
  440. $this->providerRegistry,
  441. $this->mandatoryTwoFactor,
  442. $this->session,
  443. $this->config,
  444. $this->activityManager,
  445. $this->logger,
  446. $this->tokenProvider,
  447. $this->timeFactory,
  448. $this->dispatcher,
  449. ])
  450. ->setMethods(['loadTwoFactorApp', 'isTwoFactorAuthenticated'])// Do not actually load the apps
  451. ->getMock();
  452. $manager->method('isTwoFactorAuthenticated')
  453. ->with($user)
  454. ->willReturn(true);
  455. $this->assertTrue($manager->needsSecondFactor($user));
  456. }
  457. public function testNeedsSecondFactorUserIsNull(): void {
  458. $user = null;
  459. $this->session->expects($this->never())
  460. ->method('exists');
  461. $this->assertFalse($this->manager->needsSecondFactor($user));
  462. }
  463. public function testNeedsSecondFactorWithNoProviderAvailableAnymore(): void {
  464. $this->prepareNoProviders();
  465. $user = null;
  466. $this->session->expects($this->never())
  467. ->method('exists')
  468. ->with('two_factor_auth_uid')
  469. ->willReturn(true);
  470. $this->session->expects($this->never())
  471. ->method('remove')
  472. ->with('two_factor_auth_uid');
  473. $this->assertFalse($this->manager->needsSecondFactor($user));
  474. }
  475. public function testPrepareTwoFactorLogin(): void {
  476. $this->user->method('getUID')
  477. ->willReturn('ferdinand');
  478. $this->session->expects($this->exactly(2))
  479. ->method('set')
  480. ->withConsecutive(
  481. ['two_factor_auth_uid', 'ferdinand'],
  482. ['two_factor_remember_login', true]
  483. );
  484. $this->session->method('getId')
  485. ->willReturn('mysessionid');
  486. $token = $this->createMock(OC\Authentication\Token\IToken::class);
  487. $this->tokenProvider->method('getToken')
  488. ->with('mysessionid')
  489. ->willReturn($token);
  490. $token->method('getId')
  491. ->willReturn(42);
  492. $this->timeFactory->method('getTime')
  493. ->willReturn(1337);
  494. $this->config->method('setUserValue')
  495. ->with('ferdinand', 'login_token_2fa', '42', '1337');
  496. $this->manager->prepareTwoFactorLogin($this->user, true);
  497. }
  498. public function testPrepareTwoFactorLoginDontRemember(): void {
  499. $this->user->method('getUID')
  500. ->willReturn('ferdinand');
  501. $this->session->expects($this->exactly(2))
  502. ->method('set')
  503. ->withConsecutive(
  504. ['two_factor_auth_uid', 'ferdinand'],
  505. ['two_factor_remember_login', false]
  506. );
  507. $this->session->method('getId')
  508. ->willReturn('mysessionid');
  509. $token = $this->createMock(OC\Authentication\Token\IToken::class);
  510. $this->tokenProvider->method('getToken')
  511. ->with('mysessionid')
  512. ->willReturn($token);
  513. $token->method('getId')
  514. ->willReturn(42);
  515. $this->timeFactory->method('getTime')
  516. ->willReturn(1337);
  517. $this->config->method('setUserValue')
  518. ->with('ferdinand', 'login_token_2fa', '42', '1337');
  519. $this->manager->prepareTwoFactorLogin($this->user, false);
  520. }
  521. public function testNeedsSecondFactorSessionAuth(): void {
  522. $user = $this->createMock(IUser::class);
  523. $user->method('getUID')
  524. ->willReturn('user');
  525. $this->session->method('exists')
  526. ->willReturnCallback(function ($var) {
  527. if ($var === Manager::SESSION_UID_KEY) {
  528. return false;
  529. } elseif ($var === 'app_password') {
  530. return false;
  531. } elseif ($var === 'app_api') {
  532. return false;
  533. }
  534. return true;
  535. });
  536. $this->session->method('get')
  537. ->willReturnCallback(function ($var) {
  538. if ($var === Manager::SESSION_UID_KEY) {
  539. return 'user';
  540. } elseif ($var === 'app_api') {
  541. return true;
  542. }
  543. return null;
  544. });
  545. $this->session->expects($this->once())
  546. ->method('get')
  547. ->willReturnMap([
  548. [Manager::SESSION_UID_DONE, 'user'],
  549. ['app_api', true]
  550. ]);
  551. $this->assertFalse($this->manager->needsSecondFactor($user));
  552. }
  553. public function testNeedsSecondFactorSessionAuthFailDBPass(): void {
  554. $user = $this->createMock(IUser::class);
  555. $user->method('getUID')
  556. ->willReturn('user');
  557. $this->session->method('exists')
  558. ->willReturn(false);
  559. $this->session->method('getId')
  560. ->willReturn('mysessionid');
  561. $token = $this->createMock(OC\Authentication\Token\IToken::class);
  562. $token->method('getId')
  563. ->willReturn(40);
  564. $this->tokenProvider->method('getToken')
  565. ->with('mysessionid')
  566. ->willReturn($token);
  567. $this->config->method('getUserKeys')
  568. ->with('user', 'login_token_2fa')
  569. ->willReturn([
  570. '42', '43', '44'
  571. ]);
  572. $this->session->expects($this->once())
  573. ->method('set')
  574. ->with(Manager::SESSION_UID_DONE, 'user');
  575. $this->assertFalse($this->manager->needsSecondFactor($user));
  576. }
  577. public function testNeedsSecondFactorInvalidToken(): void {
  578. $this->prepareNoProviders();
  579. $user = $this->createMock(IUser::class);
  580. $user->method('getUID')
  581. ->willReturn('user');
  582. $this->session->method('exists')
  583. ->willReturn(false);
  584. $this->session->method('getId')
  585. ->willReturn('mysessionid');
  586. $this->tokenProvider->method('getToken')
  587. ->with('mysessionid')
  588. ->willThrowException(new OC\Authentication\Exceptions\InvalidTokenException());
  589. $this->config->method('getUserKeys')->willReturn([]);
  590. $this->assertFalse($this->manager->needsSecondFactor($user));
  591. }
  592. public function testNeedsSecondFactorAppPassword(): void {
  593. $user = $this->createMock(IUser::class);
  594. $this->session->method('exists')
  595. ->willReturnMap([
  596. ['app_password', true],
  597. ['app_api', true]
  598. ]);
  599. $this->assertFalse($this->manager->needsSecondFactor($user));
  600. }
  601. public function testClearTwoFactorPending() {
  602. $this->config->method('getUserKeys')
  603. ->with('theUserId', 'login_token_2fa')
  604. ->willReturn([
  605. '42', '43', '44'
  606. ]);
  607. $this->config->expects($this->exactly(3))
  608. ->method('deleteUserValue')
  609. ->withConsecutive(
  610. ['theUserId', 'login_token_2fa', '42'],
  611. ['theUserId', 'login_token_2fa', '43'],
  612. ['theUserId', 'login_token_2fa', '44'],
  613. );
  614. $this->tokenProvider->expects($this->exactly(3))
  615. ->method('invalidateTokenById')
  616. ->withConsecutive(
  617. ['theUserId', 42],
  618. ['theUserId', 43],
  619. ['theUserId', 44],
  620. );
  621. $this->manager->clearTwoFactorPending('theUserId');
  622. }
  623. public function testClearTwoFactorPendingTokenDoesNotExist() {
  624. $this->config->method('getUserKeys')
  625. ->with('theUserId', 'login_token_2fa')
  626. ->willReturn([
  627. '42', '43', '44'
  628. ]);
  629. $this->config->expects($this->exactly(3))
  630. ->method('deleteUserValue')
  631. ->withConsecutive(
  632. ['theUserId', 'login_token_2fa', '42'],
  633. ['theUserId', 'login_token_2fa', '43'],
  634. ['theUserId', 'login_token_2fa', '44'],
  635. );
  636. $this->tokenProvider->expects($this->exactly(3))
  637. ->method('invalidateTokenById')
  638. ->withConsecutive(
  639. ['theUserId', 42],
  640. ['theUserId', 43],
  641. ['theUserId', 44],
  642. )
  643. ->willReturnCallback(function ($user, $tokenId) {
  644. if ($tokenId === 43) {
  645. throw new DoesNotExistException('token does not exist');
  646. }
  647. });
  648. $this->manager->clearTwoFactorPending('theUserId');
  649. }
  650. }