SessionTest.php 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276
  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-or-later
  6. */
  7. namespace Test\User;
  8. use OC\AppFramework\Http\Request;
  9. use OC\Authentication\Events\LoginFailed;
  10. use OC\Authentication\Exceptions\InvalidTokenException;
  11. use OC\Authentication\Exceptions\PasswordlessTokenException;
  12. use OC\Authentication\Exceptions\PasswordLoginForbiddenException;
  13. use OC\Authentication\Token\IProvider;
  14. use OC\Authentication\Token\IToken;
  15. use OC\Authentication\Token\PublicKeyToken;
  16. use OC\Security\CSRF\CsrfTokenManager;
  17. use OC\Session\Memory;
  18. use OC\User\LoginException;
  19. use OC\User\Manager;
  20. use OC\User\Session;
  21. use OC\User\User;
  22. use OCA\DAV\Connector\Sabre\Auth;
  23. use OCP\AppFramework\Utility\ITimeFactory;
  24. use OCP\EventDispatcher\IEventDispatcher;
  25. use OCP\ICacheFactory;
  26. use OCP\IConfig;
  27. use OCP\IRequest;
  28. use OCP\IRequestId;
  29. use OCP\ISession;
  30. use OCP\IUser;
  31. use OCP\Lockdown\ILockdownManager;
  32. use OCP\Security\Bruteforce\IThrottler;
  33. use OCP\Security\ISecureRandom;
  34. use OCP\User\Events\PostLoginEvent;
  35. use PHPUnit\Framework\MockObject\MockObject;
  36. use Psr\Log\LoggerInterface;
  37. use function array_diff;
  38. use function get_class_methods;
  39. /**
  40. * @group DB
  41. * @package Test\User
  42. */
  43. class SessionTest extends \Test\TestCase {
  44. /** @var ITimeFactory|MockObject */
  45. private $timeFactory;
  46. /** @var IProvider|MockObject */
  47. private $tokenProvider;
  48. /** @var IConfig|MockObject */
  49. private $config;
  50. /** @var IThrottler|MockObject */
  51. private $throttler;
  52. /** @var ISecureRandom|MockObject */
  53. private $random;
  54. /** @var Manager|MockObject */
  55. private $manager;
  56. /** @var ISession|MockObject */
  57. private $session;
  58. /** @var Session|MockObject */
  59. private $userSession;
  60. /** @var ILockdownManager|MockObject */
  61. private $lockdownManager;
  62. /** @var LoggerInterface|MockObject */
  63. private $logger;
  64. /** @var IEventDispatcher|MockObject */
  65. private $dispatcher;
  66. protected function setUp(): void {
  67. parent::setUp();
  68. $this->timeFactory = $this->createMock(ITimeFactory::class);
  69. $this->timeFactory->expects($this->any())
  70. ->method('getTime')
  71. ->willReturn(10000);
  72. $this->tokenProvider = $this->createMock(IProvider::class);
  73. $this->config = $this->createMock(IConfig::class);
  74. $this->throttler = $this->createMock(IThrottler::class);
  75. $this->random = $this->createMock(ISecureRandom::class);
  76. $this->manager = $this->createMock(Manager::class);
  77. $this->session = $this->createMock(ISession::class);
  78. $this->lockdownManager = $this->createMock(ILockdownManager::class);
  79. $this->logger = $this->createMock(LoggerInterface::class);
  80. $this->dispatcher = $this->createMock(IEventDispatcher::class);
  81. $this->userSession = $this->getMockBuilder(Session::class)
  82. ->setConstructorArgs([
  83. $this->manager,
  84. $this->session,
  85. $this->timeFactory,
  86. $this->tokenProvider,
  87. $this->config,
  88. $this->random,
  89. $this->lockdownManager,
  90. $this->logger,
  91. $this->dispatcher
  92. ])
  93. ->setMethods([
  94. 'setMagicInCookie',
  95. ])
  96. ->getMock();
  97. \OC_User::setIncognitoMode(false);
  98. }
  99. public function isLoggedInData() {
  100. return [
  101. [true],
  102. [false],
  103. ];
  104. }
  105. /**
  106. * @dataProvider isLoggedInData
  107. */
  108. public function testIsLoggedIn($isLoggedIn): void {
  109. $session = $this->createMock(Memory::class);
  110. $manager = $this->createMock(Manager::class);
  111. $userSession = $this->getMockBuilder(Session::class)
  112. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  113. ->setMethods([
  114. 'getUser'
  115. ])
  116. ->getMock();
  117. $user = new User('sepp', null, $this->createMock(IEventDispatcher::class));
  118. $userSession->expects($this->once())
  119. ->method('getUser')
  120. ->willReturn($isLoggedIn ? $user : null);
  121. $this->assertEquals($isLoggedIn, $userSession->isLoggedIn());
  122. }
  123. public function testSetUser(): void {
  124. $session = $this->createMock(Memory::class);
  125. $session->expects($this->once())
  126. ->method('set')
  127. ->with('user_id', 'foo');
  128. $manager = $this->createMock(Manager::class);
  129. $backend = $this->createMock(\Test\Util\User\Dummy::class);
  130. $user = $this->createMock(IUser::class);
  131. $user->expects($this->once())
  132. ->method('getUID')
  133. ->willReturn('foo');
  134. $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher);
  135. $userSession->setUser($user);
  136. }
  137. public function testLoginValidPasswordEnabled(): void {
  138. $session = $this->createMock(Memory::class);
  139. $session->expects($this->once())
  140. ->method('regenerateId');
  141. $this->tokenProvider->expects($this->once())
  142. ->method('getToken')
  143. ->with('bar')
  144. ->will($this->throwException(new InvalidTokenException()));
  145. $session->expects($this->exactly(2))
  146. ->method('set')
  147. ->with($this->callback(function ($key) {
  148. switch ($key) {
  149. case 'user_id':
  150. case 'loginname':
  151. return true;
  152. break;
  153. default:
  154. return false;
  155. break;
  156. }
  157. }, 'foo'));
  158. $managerMethods = get_class_methods(Manager::class);
  159. //keep following methods intact in order to ensure hooks are working
  160. $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
  161. $manager = $this->getMockBuilder(Manager::class)
  162. ->setMethods($mockedManagerMethods)
  163. ->setConstructorArgs([
  164. $this->config,
  165. $this->createMock(ICacheFactory::class),
  166. $this->createMock(IEventDispatcher::class),
  167. ])
  168. ->getMock();
  169. $backend = $this->createMock(\Test\Util\User\Dummy::class);
  170. $user = $this->createMock(IUser::class);
  171. $user->expects($this->any())
  172. ->method('isEnabled')
  173. ->willReturn(true);
  174. $user->expects($this->any())
  175. ->method('getUID')
  176. ->willReturn('foo');
  177. $user->expects($this->once())
  178. ->method('updateLastLoginTimestamp');
  179. $manager->expects($this->once())
  180. ->method('checkPasswordNoLogging')
  181. ->with('foo', 'bar')
  182. ->willReturn($user);
  183. $userSession = $this->getMockBuilder(Session::class)
  184. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  185. ->setMethods([
  186. 'prepareUserLogin'
  187. ])
  188. ->getMock();
  189. $userSession->expects($this->once())
  190. ->method('prepareUserLogin');
  191. $this->dispatcher->expects($this->once())
  192. ->method('dispatchTyped')
  193. ->with(
  194. $this->callback(function (PostLoginEvent $e) {
  195. return $e->getUser()->getUID() === 'foo' &&
  196. $e->getPassword() === 'bar' &&
  197. $e->isTokenLogin() === false;
  198. })
  199. );
  200. $userSession->login('foo', 'bar');
  201. $this->assertEquals($user, $userSession->getUser());
  202. }
  203. public function testLoginValidPasswordDisabled(): void {
  204. $this->expectException(LoginException::class);
  205. $session = $this->createMock(Memory::class);
  206. $session->expects($this->never())
  207. ->method('set');
  208. $session->expects($this->once())
  209. ->method('regenerateId');
  210. $this->tokenProvider->expects($this->once())
  211. ->method('getToken')
  212. ->with('bar')
  213. ->will($this->throwException(new InvalidTokenException()));
  214. $managerMethods = get_class_methods(Manager::class);
  215. //keep following methods intact in order to ensure hooks are working
  216. $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
  217. $manager = $this->getMockBuilder(Manager::class)
  218. ->setMethods($mockedManagerMethods)
  219. ->setConstructorArgs([
  220. $this->config,
  221. $this->createMock(ICacheFactory::class),
  222. $this->createMock(IEventDispatcher::class),
  223. ])
  224. ->getMock();
  225. $user = $this->createMock(IUser::class);
  226. $user->expects($this->any())
  227. ->method('isEnabled')
  228. ->willReturn(false);
  229. $user->expects($this->never())
  230. ->method('updateLastLoginTimestamp');
  231. $manager->expects($this->once())
  232. ->method('checkPasswordNoLogging')
  233. ->with('foo', 'bar')
  234. ->willReturn($user);
  235. $this->dispatcher->expects($this->never())
  236. ->method('dispatch');
  237. $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher);
  238. $userSession->login('foo', 'bar');
  239. }
  240. public function testLoginInvalidPassword(): void {
  241. $session = $this->createMock(Memory::class);
  242. $managerMethods = get_class_methods(Manager::class);
  243. //keep following methods intact in order to ensure hooks are working
  244. $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
  245. $manager = $this->getMockBuilder(Manager::class)
  246. ->setMethods($mockedManagerMethods)
  247. ->setConstructorArgs([
  248. $this->config,
  249. $this->createMock(ICacheFactory::class),
  250. $this->createMock(IEventDispatcher::class),
  251. ])
  252. ->getMock();
  253. $backend = $this->createMock(\Test\Util\User\Dummy::class);
  254. $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher);
  255. $user = $this->createMock(IUser::class);
  256. $session->expects($this->never())
  257. ->method('set');
  258. $session->expects($this->once())
  259. ->method('regenerateId');
  260. $this->tokenProvider->expects($this->once())
  261. ->method('getToken')
  262. ->with('bar')
  263. ->will($this->throwException(new InvalidTokenException()));
  264. $user->expects($this->never())
  265. ->method('isEnabled');
  266. $user->expects($this->never())
  267. ->method('updateLastLoginTimestamp');
  268. $manager->expects($this->once())
  269. ->method('checkPasswordNoLogging')
  270. ->with('foo', 'bar')
  271. ->willReturn(false);
  272. $this->dispatcher->expects($this->never())
  273. ->method('dispatch');
  274. $userSession->login('foo', 'bar');
  275. }
  276. public function testPasswordlessLoginNoLastCheckUpdate(): void {
  277. $session = $this->createMock(Memory::class);
  278. $managerMethods = get_class_methods(Manager::class);
  279. // Keep following methods intact in order to ensure hooks are working
  280. $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
  281. $manager = $this->getMockBuilder(Manager::class)
  282. ->setMethods($mockedManagerMethods)
  283. ->setConstructorArgs([
  284. $this->config,
  285. $this->createMock(ICacheFactory::class),
  286. $this->createMock(IEventDispatcher::class),
  287. ])
  288. ->getMock();
  289. $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher);
  290. $session->expects($this->never())
  291. ->method('set');
  292. $session->expects($this->once())
  293. ->method('regenerateId');
  294. $token = new PublicKeyToken();
  295. $token->setLoginName('foo');
  296. $token->setLastCheck(0); // Never
  297. $token->setUid('foo');
  298. $this->tokenProvider
  299. ->method('getPassword')
  300. ->with($token)
  301. ->willThrowException(new PasswordlessTokenException());
  302. $this->tokenProvider
  303. ->method('getToken')
  304. ->with('app-password')
  305. ->willReturn($token);
  306. $this->tokenProvider->expects(self::never())
  307. ->method('updateToken');
  308. $userSession->login('foo', 'app-password');
  309. }
  310. public function testLoginLastCheckUpdate(): void {
  311. $session = $this->createMock(Memory::class);
  312. $managerMethods = get_class_methods(Manager::class);
  313. // Keep following methods intact in order to ensure hooks are working
  314. $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
  315. $manager = $this->getMockBuilder(Manager::class)
  316. ->setMethods($mockedManagerMethods)
  317. ->setConstructorArgs([
  318. $this->config,
  319. $this->createMock(ICacheFactory::class),
  320. $this->createMock(IEventDispatcher::class),
  321. ])
  322. ->getMock();
  323. $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher);
  324. $session->expects($this->never())
  325. ->method('set');
  326. $session->expects($this->once())
  327. ->method('regenerateId');
  328. $token = new PublicKeyToken();
  329. $token->setLoginName('foo');
  330. $token->setLastCheck(0); // Never
  331. $token->setUid('foo');
  332. $this->tokenProvider
  333. ->method('getPassword')
  334. ->with($token)
  335. ->willReturn('secret');
  336. $this->tokenProvider
  337. ->method('getToken')
  338. ->with('app-password')
  339. ->willReturn($token);
  340. $this->tokenProvider->expects(self::once())
  341. ->method('updateToken');
  342. $userSession->login('foo', 'app-password');
  343. }
  344. public function testLoginNonExisting(): void {
  345. $session = $this->createMock(Memory::class);
  346. $manager = $this->createMock(Manager::class);
  347. $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher);
  348. $session->expects($this->never())
  349. ->method('set');
  350. $session->expects($this->once())
  351. ->method('regenerateId');
  352. $this->tokenProvider->expects($this->once())
  353. ->method('getToken')
  354. ->with('bar')
  355. ->will($this->throwException(new InvalidTokenException()));
  356. $manager->expects($this->once())
  357. ->method('checkPasswordNoLogging')
  358. ->with('foo', 'bar')
  359. ->willReturn(false);
  360. $userSession->login('foo', 'bar');
  361. }
  362. public function testLogClientInNoTokenPasswordWith2fa(): void {
  363. $this->expectException(PasswordLoginForbiddenException::class);
  364. $manager = $this->createMock(Manager::class);
  365. $session = $this->createMock(ISession::class);
  366. $request = $this->createMock(IRequest::class);
  367. /** @var Session $userSession */
  368. $userSession = $this->getMockBuilder(Session::class)
  369. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  370. ->setMethods(['login', 'supportsCookies', 'createSessionToken', 'getUser'])
  371. ->getMock();
  372. $this->tokenProvider->expects($this->once())
  373. ->method('getToken')
  374. ->with('doe')
  375. ->will($this->throwException(new InvalidTokenException()));
  376. $this->config->expects($this->once())
  377. ->method('getSystemValueBool')
  378. ->with('token_auth_enforced', false)
  379. ->willReturn(true);
  380. $request
  381. ->expects($this->any())
  382. ->method('getRemoteAddress')
  383. ->willReturn('192.168.0.1');
  384. $this->throttler
  385. ->expects($this->once())
  386. ->method('sleepDelayOrThrowOnMax')
  387. ->with('192.168.0.1');
  388. $this->throttler
  389. ->expects($this->any())
  390. ->method('getDelay')
  391. ->with('192.168.0.1')
  392. ->willReturn(0);
  393. $userSession->logClientIn('john', 'doe', $request, $this->throttler);
  394. }
  395. public function testLogClientInUnexist(): void {
  396. $manager = $this->createMock(Manager::class);
  397. $session = $this->createMock(ISession::class);
  398. $request = $this->createMock(IRequest::class);
  399. /** @var Session $userSession */
  400. $userSession = $this->getMockBuilder(Session::class)
  401. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  402. ->setMethods(['login', 'supportsCookies', 'createSessionToken', 'getUser'])
  403. ->getMock();
  404. $this->tokenProvider->expects($this->once())
  405. ->method('getToken')
  406. ->with('doe')
  407. ->will($this->throwException(new InvalidTokenException()));
  408. $this->config->expects($this->once())
  409. ->method('getSystemValueBool')
  410. ->with('token_auth_enforced', false)
  411. ->willReturn(false);
  412. $manager->method('getByEmail')
  413. ->with('unexist')
  414. ->willReturn([]);
  415. $this->assertFalse($userSession->logClientIn('unexist', 'doe', $request, $this->throttler));
  416. }
  417. public function testLogClientInWithTokenPassword(): void {
  418. $manager = $this->createMock(Manager::class);
  419. $session = $this->createMock(ISession::class);
  420. $request = $this->createMock(IRequest::class);
  421. /** @var Session $userSession */
  422. $userSession = $this->getMockBuilder(Session::class)
  423. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  424. ->setMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser'])
  425. ->getMock();
  426. $userSession->expects($this->once())
  427. ->method('isTokenPassword')
  428. ->willReturn(true);
  429. $userSession->expects($this->once())
  430. ->method('login')
  431. ->with('john', 'I-AM-AN-APP-PASSWORD')
  432. ->willReturn(true);
  433. $session->expects($this->once())
  434. ->method('set')
  435. ->with('app_password', 'I-AM-AN-APP-PASSWORD');
  436. $request
  437. ->expects($this->any())
  438. ->method('getRemoteAddress')
  439. ->willReturn('192.168.0.1');
  440. $this->throttler
  441. ->expects($this->once())
  442. ->method('sleepDelayOrThrowOnMax')
  443. ->with('192.168.0.1');
  444. $this->throttler
  445. ->expects($this->any())
  446. ->method('getDelay')
  447. ->with('192.168.0.1')
  448. ->willReturn(0);
  449. $this->assertTrue($userSession->logClientIn('john', 'I-AM-AN-APP-PASSWORD', $request, $this->throttler));
  450. }
  451. public function testLogClientInNoTokenPasswordNo2fa(): void {
  452. $this->expectException(PasswordLoginForbiddenException::class);
  453. $manager = $this->createMock(Manager::class);
  454. $session = $this->createMock(ISession::class);
  455. $request = $this->createMock(IRequest::class);
  456. /** @var Session $userSession */
  457. $userSession = $this->getMockBuilder(Session::class)
  458. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  459. ->setMethods(['login', 'isTwoFactorEnforced'])
  460. ->getMock();
  461. $this->tokenProvider->expects($this->once())
  462. ->method('getToken')
  463. ->with('doe')
  464. ->will($this->throwException(new InvalidTokenException()));
  465. $this->config->expects($this->once())
  466. ->method('getSystemValueBool')
  467. ->with('token_auth_enforced', false)
  468. ->willReturn(false);
  469. $userSession->expects($this->once())
  470. ->method('isTwoFactorEnforced')
  471. ->with('john')
  472. ->willReturn(true);
  473. $request
  474. ->expects($this->any())
  475. ->method('getRemoteAddress')
  476. ->willReturn('192.168.0.1');
  477. $this->throttler
  478. ->expects($this->once())
  479. ->method('sleepDelayOrThrowOnMax')
  480. ->with('192.168.0.1');
  481. $this->throttler
  482. ->expects($this->any())
  483. ->method('getDelay')
  484. ->with('192.168.0.1')
  485. ->willReturn(0);
  486. $userSession->logClientIn('john', 'doe', $request, $this->throttler);
  487. }
  488. public function testTryTokenLoginNoHeaderNoSessionCookie(): void {
  489. $request = $this->createMock(IRequest::class);
  490. $this->config->expects(self::once())
  491. ->method('getSystemValueString')
  492. ->with('instanceid')
  493. ->willReturn('abc123');
  494. $request->method('getHeader')->with('Authorization')->willReturn('');
  495. $request->method('getCookie')->with('abc123')->willReturn(null);
  496. $this->tokenProvider->expects(self::never())
  497. ->method('getToken');
  498. $loginResult = $this->userSession->tryTokenLogin($request);
  499. self::assertFalse($loginResult);
  500. }
  501. public function testTryTokenLoginAuthorizationHeaderTokenNotFound(): void {
  502. $request = $this->createMock(IRequest::class);
  503. $request->method('getHeader')->with('Authorization')->willReturn('Bearer abcde-12345');
  504. $this->tokenProvider->expects(self::once())
  505. ->method('getToken')
  506. ->with('abcde-12345')
  507. ->willThrowException(new InvalidTokenException());
  508. $loginResult = $this->userSession->tryTokenLogin($request);
  509. self::assertFalse($loginResult);
  510. }
  511. public function testTryTokenLoginSessionIdTokenNotFound(): void {
  512. $request = $this->createMock(IRequest::class);
  513. $this->config->expects(self::once())
  514. ->method('getSystemValueString')
  515. ->with('instanceid')
  516. ->willReturn('abc123');
  517. $request->method('getHeader')->with('Authorization')->willReturn('');
  518. $request->method('getCookie')->with('abc123')->willReturn('abcde12345');
  519. $this->session->expects(self::once())
  520. ->method('getId')
  521. ->willReturn('abcde12345');
  522. $this->tokenProvider->expects(self::once())
  523. ->method('getToken')
  524. ->with('abcde12345')
  525. ->willThrowException(new InvalidTokenException());
  526. $loginResult = $this->userSession->tryTokenLogin($request);
  527. self::assertFalse($loginResult);
  528. }
  529. public function testRememberLoginValidToken(): void {
  530. $session = $this->createMock(Memory::class);
  531. $managerMethods = get_class_methods(Manager::class);
  532. //keep following methods intact in order to ensure hooks are working
  533. $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
  534. $manager = $this->getMockBuilder(Manager::class)
  535. ->setMethods($mockedManagerMethods)
  536. ->setConstructorArgs([
  537. $this->config,
  538. $this->createMock(ICacheFactory::class),
  539. $this->createMock(IEventDispatcher::class),
  540. ])
  541. ->getMock();
  542. $userSession = $this->getMockBuilder(Session::class)
  543. //override, otherwise tests will fail because of setcookie()
  544. ->setMethods(['setMagicInCookie', 'setLoginName'])
  545. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  546. ->getMock();
  547. $user = $this->createMock(IUser::class);
  548. $token = 'goodToken';
  549. $oldSessionId = 'sess321';
  550. $sessionId = 'sess123';
  551. $session->expects($this->once())
  552. ->method('regenerateId');
  553. $manager->expects($this->once())
  554. ->method('get')
  555. ->with('foo')
  556. ->willReturn($user);
  557. $this->config->expects($this->once())
  558. ->method('getUserKeys')
  559. ->with('foo', 'login_token')
  560. ->willReturn([$token]);
  561. $this->config->expects($this->once())
  562. ->method('deleteUserValue')
  563. ->with('foo', 'login_token', $token);
  564. $this->random->expects($this->once())
  565. ->method('generate')
  566. ->with(32)
  567. ->willReturn('abcdefg123456');
  568. $this->config->expects($this->once())
  569. ->method('setUserValue')
  570. ->with('foo', 'login_token', 'abcdefg123456', 10000);
  571. $tokenObject = $this->createMock(IToken::class);
  572. $tokenObject->expects($this->once())
  573. ->method('getLoginName')
  574. ->willReturn('foobar');
  575. $tokenObject->method('getId')
  576. ->willReturn(42);
  577. $session->expects($this->once())
  578. ->method('getId')
  579. ->willReturn($sessionId);
  580. $this->tokenProvider->expects($this->once())
  581. ->method('renewSessionToken')
  582. ->with($oldSessionId, $sessionId)
  583. ->willReturn($tokenObject);
  584. $this->tokenProvider->expects($this->never())
  585. ->method('getToken');
  586. $user->expects($this->any())
  587. ->method('getUID')
  588. ->willReturn('foo');
  589. $userSession->expects($this->once())
  590. ->method('setMagicInCookie');
  591. $user->expects($this->once())
  592. ->method('updateLastLoginTimestamp');
  593. $setUID = false;
  594. $session
  595. ->method('set')
  596. ->willReturnCallback(function ($k, $v) use (&$setUID) {
  597. if ($k === 'user_id' && $v === 'foo') {
  598. $setUID = true;
  599. }
  600. });
  601. $userSession->expects($this->once())
  602. ->method('setLoginName')
  603. ->willReturn('foobar');
  604. $granted = $userSession->loginWithCookie('foo', $token, $oldSessionId);
  605. $this->assertTrue($setUID);
  606. $this->assertTrue($granted);
  607. }
  608. public function testRememberLoginInvalidSessionToken(): void {
  609. $session = $this->createMock(Memory::class);
  610. $managerMethods = get_class_methods(Manager::class);
  611. //keep following methods intact in order to ensure hooks are working
  612. $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
  613. $manager = $this->getMockBuilder(Manager::class)
  614. ->setMethods($mockedManagerMethods)
  615. ->setConstructorArgs([
  616. $this->config,
  617. $this->createMock(ICacheFactory::class),
  618. $this->createMock(IEventDispatcher::class),
  619. ])
  620. ->getMock();
  621. $userSession = $this->getMockBuilder(Session::class)
  622. //override, otherwise tests will fail because of setcookie()
  623. ->setMethods(['setMagicInCookie'])
  624. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  625. ->getMock();
  626. $user = $this->createMock(IUser::class);
  627. $token = 'goodToken';
  628. $oldSessionId = 'sess321';
  629. $sessionId = 'sess123';
  630. $session->expects($this->once())
  631. ->method('regenerateId');
  632. $manager->expects($this->once())
  633. ->method('get')
  634. ->with('foo')
  635. ->willReturn($user);
  636. $this->config->expects($this->once())
  637. ->method('getUserKeys')
  638. ->with('foo', 'login_token')
  639. ->willReturn([$token]);
  640. $this->config->expects($this->once())
  641. ->method('deleteUserValue')
  642. ->with('foo', 'login_token', $token);
  643. $this->config->expects($this->once())
  644. ->method('setUserValue'); // TODO: mock new random value
  645. $session->expects($this->once())
  646. ->method('getId')
  647. ->willReturn($sessionId);
  648. $this->tokenProvider->expects($this->once())
  649. ->method('renewSessionToken')
  650. ->with($oldSessionId, $sessionId)
  651. ->will($this->throwException(new InvalidTokenException()));
  652. $user->expects($this->never())
  653. ->method('getUID')
  654. ->willReturn('foo');
  655. $userSession->expects($this->never())
  656. ->method('setMagicInCookie');
  657. $user->expects($this->never())
  658. ->method('updateLastLoginTimestamp');
  659. $session->expects($this->never())
  660. ->method('set')
  661. ->with('user_id', 'foo');
  662. $granted = $userSession->loginWithCookie('foo', $token, $oldSessionId);
  663. $this->assertFalse($granted);
  664. }
  665. public function testRememberLoginInvalidToken(): void {
  666. $session = $this->createMock(Memory::class);
  667. $managerMethods = get_class_methods(Manager::class);
  668. //keep following methods intact in order to ensure hooks are working
  669. $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
  670. $manager = $this->getMockBuilder(Manager::class)
  671. ->setMethods($mockedManagerMethods)
  672. ->setConstructorArgs([
  673. $this->config,
  674. $this->createMock(ICacheFactory::class),
  675. $this->createMock(IEventDispatcher::class),
  676. ])
  677. ->getMock();
  678. $userSession = $this->getMockBuilder(Session::class)
  679. //override, otherwise tests will fail because of setcookie()
  680. ->setMethods(['setMagicInCookie'])
  681. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  682. ->getMock();
  683. $user = $this->createMock(IUser::class);
  684. $token = 'goodToken';
  685. $oldSessionId = 'sess321';
  686. $session->expects($this->once())
  687. ->method('regenerateId');
  688. $manager->expects($this->once())
  689. ->method('get')
  690. ->with('foo')
  691. ->willReturn($user);
  692. $this->config->expects($this->once())
  693. ->method('getUserKeys')
  694. ->with('foo', 'login_token')
  695. ->willReturn(['anothertoken']);
  696. $this->config->expects($this->never())
  697. ->method('deleteUserValue')
  698. ->with('foo', 'login_token', $token);
  699. $this->tokenProvider->expects($this->never())
  700. ->method('renewSessionToken');
  701. $userSession->expects($this->never())
  702. ->method('setMagicInCookie');
  703. $user->expects($this->never())
  704. ->method('updateLastLoginTimestamp');
  705. $session->expects($this->never())
  706. ->method('set')
  707. ->with('user_id', 'foo');
  708. $granted = $userSession->loginWithCookie('foo', $token, $oldSessionId);
  709. $this->assertFalse($granted);
  710. }
  711. public function testRememberLoginInvalidUser(): void {
  712. $session = $this->createMock(Memory::class);
  713. $managerMethods = get_class_methods(Manager::class);
  714. //keep following methods intact in order to ensure hooks are working
  715. $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
  716. $manager = $this->getMockBuilder(Manager::class)
  717. ->setMethods($mockedManagerMethods)
  718. ->setConstructorArgs([
  719. $this->config,
  720. $this->createMock(ICacheFactory::class),
  721. $this->createMock(IEventDispatcher::class),
  722. ])
  723. ->getMock();
  724. $userSession = $this->getMockBuilder(Session::class)
  725. //override, otherwise tests will fail because of setcookie()
  726. ->setMethods(['setMagicInCookie'])
  727. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  728. ->getMock();
  729. $token = 'goodToken';
  730. $oldSessionId = 'sess321';
  731. $session->expects($this->once())
  732. ->method('regenerateId');
  733. $manager->expects($this->once())
  734. ->method('get')
  735. ->with('foo')
  736. ->willReturn(null);
  737. $this->config->expects($this->never())
  738. ->method('getUserKeys')
  739. ->with('foo', 'login_token')
  740. ->willReturn(['anothertoken']);
  741. $this->tokenProvider->expects($this->never())
  742. ->method('renewSessionToken');
  743. $userSession->expects($this->never())
  744. ->method('setMagicInCookie');
  745. $session->expects($this->never())
  746. ->method('set')
  747. ->with('user_id', 'foo');
  748. $granted = $userSession->loginWithCookie('foo', $token, $oldSessionId);
  749. $this->assertFalse($granted);
  750. }
  751. public function testActiveUserAfterSetSession(): void {
  752. $users = [
  753. 'foo' => new User('foo', null, $this->createMock(IEventDispatcher::class)),
  754. 'bar' => new User('bar', null, $this->createMock(IEventDispatcher::class))
  755. ];
  756. $manager = $this->getMockBuilder(Manager::class)
  757. ->disableOriginalConstructor()
  758. ->getMock();
  759. $manager->expects($this->any())
  760. ->method('get')
  761. ->willReturnCallback(function ($uid) use ($users) {
  762. return $users[$uid];
  763. });
  764. $session = new Memory();
  765. $session->set('user_id', 'foo');
  766. $userSession = $this->getMockBuilder(Session::class)
  767. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  768. ->setMethods([
  769. 'validateSession'
  770. ])
  771. ->getMock();
  772. $userSession->expects($this->any())
  773. ->method('validateSession');
  774. $this->assertEquals($users['foo'], $userSession->getUser());
  775. $session2 = new Memory();
  776. $session2->set('user_id', 'bar');
  777. $userSession->setSession($session2);
  778. $this->assertEquals($users['bar'], $userSession->getUser());
  779. }
  780. public function testCreateSessionToken(): void {
  781. $manager = $this->createMock(Manager::class);
  782. $session = $this->createMock(ISession::class);
  783. $user = $this->createMock(IUser::class);
  784. $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher);
  785. $requestId = $this->createMock(IRequestId::class);
  786. $config = $this->createMock(IConfig::class);
  787. $csrf = $this->getMockBuilder(CsrfTokenManager::class)
  788. ->disableOriginalConstructor()
  789. ->getMock();
  790. $request = new Request([
  791. 'server' => [
  792. 'HTTP_USER_AGENT' => 'Firefox',
  793. ]
  794. ], $requestId, $config, $csrf);
  795. $uid = 'user123';
  796. $loginName = 'User123';
  797. $password = 'passme';
  798. $sessionId = 'abcxyz';
  799. $manager->expects($this->once())
  800. ->method('get')
  801. ->with($uid)
  802. ->willReturn($user);
  803. $session->expects($this->once())
  804. ->method('getId')
  805. ->willReturn($sessionId);
  806. $this->tokenProvider->expects($this->once())
  807. ->method('getToken')
  808. ->with($password)
  809. ->will($this->throwException(new InvalidTokenException()));
  810. $this->tokenProvider->expects($this->once())
  811. ->method('generateToken')
  812. ->with($sessionId, $uid, $loginName, $password, 'Firefox', IToken::TEMPORARY_TOKEN, IToken::DO_NOT_REMEMBER);
  813. $this->assertTrue($userSession->createSessionToken($request, $uid, $loginName, $password));
  814. }
  815. public function testCreateRememberedSessionToken(): void {
  816. $manager = $this->createMock(Manager::class);
  817. $session = $this->createMock(ISession::class);
  818. $user = $this->createMock(IUser::class);
  819. $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher);
  820. $requestId = $this->createMock(IRequestId::class);
  821. $config = $this->createMock(IConfig::class);
  822. $csrf = $this->getMockBuilder(CsrfTokenManager::class)
  823. ->disableOriginalConstructor()
  824. ->getMock();
  825. $request = new Request([
  826. 'server' => [
  827. 'HTTP_USER_AGENT' => 'Firefox',
  828. ]
  829. ], $requestId, $config, $csrf);
  830. $uid = 'user123';
  831. $loginName = 'User123';
  832. $password = 'passme';
  833. $sessionId = 'abcxyz';
  834. $manager->expects($this->once())
  835. ->method('get')
  836. ->with($uid)
  837. ->willReturn($user);
  838. $session->expects($this->once())
  839. ->method('getId')
  840. ->willReturn($sessionId);
  841. $this->tokenProvider->expects($this->once())
  842. ->method('getToken')
  843. ->with($password)
  844. ->will($this->throwException(new InvalidTokenException()));
  845. $this->tokenProvider->expects($this->once())
  846. ->method('generateToken')
  847. ->with($sessionId, $uid, $loginName, $password, 'Firefox', IToken::TEMPORARY_TOKEN, IToken::REMEMBER);
  848. $this->assertTrue($userSession->createSessionToken($request, $uid, $loginName, $password, true));
  849. }
  850. public function testCreateSessionTokenWithTokenPassword(): void {
  851. $manager = $this->getMockBuilder(Manager::class)
  852. ->disableOriginalConstructor()
  853. ->getMock();
  854. $session = $this->createMock(ISession::class);
  855. $token = $this->createMock(IToken::class);
  856. $user = $this->createMock(IUser::class);
  857. $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher);
  858. $requestId = $this->createMock(IRequestId::class);
  859. $config = $this->createMock(IConfig::class);
  860. $csrf = $this->getMockBuilder(CsrfTokenManager::class)
  861. ->disableOriginalConstructor()
  862. ->getMock();
  863. $request = new Request([
  864. 'server' => [
  865. 'HTTP_USER_AGENT' => 'Firefox',
  866. ]
  867. ], $requestId, $config, $csrf);
  868. $uid = 'user123';
  869. $loginName = 'User123';
  870. $password = 'iamatoken';
  871. $realPassword = 'passme';
  872. $sessionId = 'abcxyz';
  873. $manager->expects($this->once())
  874. ->method('get')
  875. ->with($uid)
  876. ->willReturn($user);
  877. $session->expects($this->once())
  878. ->method('getId')
  879. ->willReturn($sessionId);
  880. $this->tokenProvider->expects($this->once())
  881. ->method('getToken')
  882. ->with($password)
  883. ->willReturn($token);
  884. $this->tokenProvider->expects($this->once())
  885. ->method('getPassword')
  886. ->with($token, $password)
  887. ->willReturn($realPassword);
  888. $this->tokenProvider->expects($this->once())
  889. ->method('generateToken')
  890. ->with($sessionId, $uid, $loginName, $realPassword, 'Firefox', IToken::TEMPORARY_TOKEN, IToken::DO_NOT_REMEMBER);
  891. $this->assertTrue($userSession->createSessionToken($request, $uid, $loginName, $password));
  892. }
  893. public function testCreateSessionTokenWithNonExistentUser(): void {
  894. $manager = $this->getMockBuilder(Manager::class)
  895. ->disableOriginalConstructor()
  896. ->getMock();
  897. $session = $this->createMock(ISession::class);
  898. $userSession = new Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher);
  899. $request = $this->createMock(IRequest::class);
  900. $uid = 'user123';
  901. $loginName = 'User123';
  902. $password = 'passme';
  903. $manager->expects($this->once())
  904. ->method('get')
  905. ->with($uid)
  906. ->willReturn(null);
  907. $this->assertFalse($userSession->createSessionToken($request, $uid, $loginName, $password));
  908. }
  909. public function testCreateRememberMeToken(): void {
  910. $user = $this->createMock(IUser::class);
  911. $user
  912. ->expects($this->exactly(2))
  913. ->method('getUID')
  914. ->willReturn('UserUid');
  915. $this->random
  916. ->expects($this->once())
  917. ->method('generate')
  918. ->with(32)
  919. ->willReturn('LongRandomToken');
  920. $this->config
  921. ->expects($this->once())
  922. ->method('setUserValue')
  923. ->with('UserUid', 'login_token', 'LongRandomToken', 10000);
  924. $this->userSession
  925. ->expects($this->once())
  926. ->method('setMagicInCookie')
  927. ->with('UserUid', 'LongRandomToken');
  928. $this->userSession->createRememberMeToken($user);
  929. }
  930. public function testTryBasicAuthLoginValid(): void {
  931. $request = $this->createMock(Request::class);
  932. $request->method('__get')
  933. ->willReturn([
  934. 'PHP_AUTH_USER' => 'username',
  935. 'PHP_AUTH_PW' => 'password',
  936. ]);
  937. $request->method('__isset')
  938. ->with('server')
  939. ->willReturn(true);
  940. $davAuthenticatedSet = false;
  941. $lastPasswordConfirmSet = false;
  942. $this->session
  943. ->method('set')
  944. ->willReturnCallback(function ($k, $v) use (&$davAuthenticatedSet, &$lastPasswordConfirmSet) {
  945. switch ($k) {
  946. case Auth::DAV_AUTHENTICATED:
  947. $davAuthenticatedSet = $v;
  948. return;
  949. case 'last-password-confirm':
  950. $lastPasswordConfirmSet = 1000;
  951. return;
  952. default:
  953. throw new \Exception();
  954. }
  955. });
  956. $userSession = $this->getMockBuilder(Session::class)
  957. ->setConstructorArgs([
  958. $this->manager,
  959. $this->session,
  960. $this->timeFactory,
  961. $this->tokenProvider,
  962. $this->config,
  963. $this->random,
  964. $this->lockdownManager,
  965. $this->logger,
  966. $this->dispatcher
  967. ])
  968. ->setMethods([
  969. 'logClientIn',
  970. 'getUser',
  971. ])
  972. ->getMock();
  973. /** @var Session|MockObject */
  974. $userSession->expects($this->once())
  975. ->method('logClientIn')
  976. ->with(
  977. $this->equalTo('username'),
  978. $this->equalTo('password'),
  979. $this->equalTo($request),
  980. $this->equalTo($this->throttler)
  981. )->willReturn(true);
  982. $user = $this->createMock(IUser::class);
  983. $user->method('getUID')->willReturn('username');
  984. $userSession->expects($this->once())
  985. ->method('getUser')
  986. ->willReturn($user);
  987. $this->assertTrue($userSession->tryBasicAuthLogin($request, $this->throttler));
  988. $this->assertSame('username', $davAuthenticatedSet);
  989. $this->assertSame(1000, $lastPasswordConfirmSet);
  990. }
  991. public function testTryBasicAuthLoginNoLogin(): void {
  992. $request = $this->createMock(Request::class);
  993. $request->method('__get')
  994. ->willReturn([]);
  995. $request->method('__isset')
  996. ->with('server')
  997. ->willReturn(true);
  998. $this->session->expects($this->never())
  999. ->method($this->anything());
  1000. $userSession = $this->getMockBuilder(Session::class)
  1001. ->setConstructorArgs([
  1002. $this->manager,
  1003. $this->session,
  1004. $this->timeFactory,
  1005. $this->tokenProvider,
  1006. $this->config,
  1007. $this->random,
  1008. $this->lockdownManager,
  1009. $this->logger,
  1010. $this->dispatcher
  1011. ])
  1012. ->setMethods([
  1013. 'logClientIn',
  1014. ])
  1015. ->getMock();
  1016. /** @var Session|MockObject */
  1017. $userSession->expects($this->never())
  1018. ->method('logClientIn');
  1019. $this->assertFalse($userSession->tryBasicAuthLogin($request, $this->throttler));
  1020. }
  1021. public function testUpdateTokens(): void {
  1022. $this->tokenProvider->expects($this->once())
  1023. ->method('updatePasswords')
  1024. ->with('uid', 'pass');
  1025. $this->userSession->updateTokens('uid', 'pass');
  1026. }
  1027. public function testLogClientInThrottlerUsername(): void {
  1028. $manager = $this->createMock(Manager::class);
  1029. $session = $this->createMock(ISession::class);
  1030. $request = $this->createMock(IRequest::class);
  1031. /** @var Session $userSession */
  1032. $userSession = $this->getMockBuilder(Session::class)
  1033. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  1034. ->setMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser'])
  1035. ->getMock();
  1036. $userSession->expects($this->once())
  1037. ->method('isTokenPassword')
  1038. ->willReturn(true);
  1039. $userSession->expects($this->once())
  1040. ->method('login')
  1041. ->with('john', 'I-AM-AN-PASSWORD')
  1042. ->willReturn(false);
  1043. $session->expects($this->never())
  1044. ->method('set');
  1045. $request
  1046. ->method('getRemoteAddress')
  1047. ->willReturn('192.168.0.1');
  1048. $this->throttler
  1049. ->expects($this->exactly(2))
  1050. ->method('sleepDelayOrThrowOnMax')
  1051. ->with('192.168.0.1');
  1052. $this->throttler
  1053. ->expects($this->any())
  1054. ->method('getDelay')
  1055. ->with('192.168.0.1')
  1056. ->willReturn(0);
  1057. $this->throttler
  1058. ->expects($this->once())
  1059. ->method('registerAttempt')
  1060. ->with('login', '192.168.0.1', ['user' => 'john']);
  1061. $this->dispatcher
  1062. ->expects($this->once())
  1063. ->method('dispatchTyped')
  1064. ->with(new LoginFailed('john', 'I-AM-AN-PASSWORD'));
  1065. $this->assertFalse($userSession->logClientIn('john', 'I-AM-AN-PASSWORD', $request, $this->throttler));
  1066. }
  1067. public function testLogClientInThrottlerEmail(): void {
  1068. $manager = $this->createMock(Manager::class);
  1069. $session = $this->createMock(ISession::class);
  1070. $request = $this->createMock(IRequest::class);
  1071. /** @var Session $userSession */
  1072. $userSession = $this->getMockBuilder(Session::class)
  1073. ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
  1074. ->setMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser'])
  1075. ->getMock();
  1076. $userSession->expects($this->once())
  1077. ->method('isTokenPassword')
  1078. ->willReturn(false);
  1079. $userSession->expects($this->once())
  1080. ->method('login')
  1081. ->with('john@foo.bar', 'I-AM-AN-PASSWORD')
  1082. ->willReturn(false);
  1083. $manager
  1084. ->method('getByEmail')
  1085. ->with('john@foo.bar')
  1086. ->willReturn([]);
  1087. $session->expects($this->never())
  1088. ->method('set');
  1089. $request
  1090. ->method('getRemoteAddress')
  1091. ->willReturn('192.168.0.1');
  1092. $this->throttler
  1093. ->expects($this->exactly(2))
  1094. ->method('sleepDelayOrThrowOnMax')
  1095. ->with('192.168.0.1');
  1096. $this->throttler
  1097. ->expects($this->any())
  1098. ->method('getDelay')
  1099. ->with('192.168.0.1')
  1100. ->willReturn(0);
  1101. $this->throttler
  1102. ->expects($this->once())
  1103. ->method('registerAttempt')
  1104. ->with('login', '192.168.0.1', ['user' => 'john@foo.bar']);
  1105. $this->dispatcher
  1106. ->expects($this->once())
  1107. ->method('dispatchTyped')
  1108. ->with(new LoginFailed('john@foo.bar', 'I-AM-AN-PASSWORD'));
  1109. $this->assertFalse($userSession->logClientIn('john@foo.bar', 'I-AM-AN-PASSWORD', $request, $this->throttler));
  1110. }
  1111. }