PublicKeyTokenProviderTest.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl>
  5. *
  6. * @author Roeland Jago Douma <roeland@famdouma.nl>
  7. *
  8. * @license GNU AGPL version 3 or any later version
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License as
  12. * published by the Free Software Foundation, either version 3 of the
  13. * License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Affero General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Affero General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. *
  23. */
  24. namespace Test\Authentication\Token;
  25. use OC\Authentication\Exceptions\ExpiredTokenException;
  26. use OC\Authentication\Exceptions\InvalidTokenException;
  27. use OC\Authentication\Exceptions\PasswordlessTokenException;
  28. use OC\Authentication\Token\IToken;
  29. use OC\Authentication\Token\PublicKeyToken;
  30. use OC\Authentication\Token\PublicKeyTokenMapper;
  31. use OC\Authentication\Token\PublicKeyTokenProvider;
  32. use OCP\AppFramework\Db\DoesNotExistException;
  33. use OCP\AppFramework\Utility\ITimeFactory;
  34. use OCP\IConfig;
  35. use OCP\IDBConnection;
  36. use OCP\Security\ICrypto;
  37. use PHPUnit\Framework\MockObject\MockObject;
  38. use Psr\Log\LoggerInterface;
  39. use Test\TestCase;
  40. class PublicKeyTokenProviderTest extends TestCase {
  41. /** @var PublicKeyTokenProvider|\PHPUnit\Framework\MockObject\MockObject */
  42. private $tokenProvider;
  43. /** @var PublicKeyTokenMapper|\PHPUnit\Framework\MockObject\MockObject */
  44. private $mapper;
  45. /** @var ICrypto */
  46. private $crypto;
  47. /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
  48. private $config;
  49. /** @var IDBConnection|MockObject */
  50. private IDBConnection $db;
  51. /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */
  52. private $logger;
  53. /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */
  54. private $timeFactory;
  55. /** @var int */
  56. private $time;
  57. protected function setUp(): void {
  58. parent::setUp();
  59. $this->mapper = $this->createMock(PublicKeyTokenMapper::class);
  60. $this->hasher = \OC::$server->getHasher();
  61. $this->crypto = \OC::$server->getCrypto();
  62. $this->config = $this->createMock(IConfig::class);
  63. $this->config->method('getSystemValue')
  64. ->willReturnMap([
  65. ['session_lifetime', 60 * 60 * 24, 150],
  66. ['remember_login_cookie_lifetime', 60 * 60 * 24 * 15, 300],
  67. ['secret', '', '1f4h9s'],
  68. ['openssl', [], []],
  69. ]);
  70. $this->db = $this->createMock(IDBConnection::class);
  71. $this->logger = $this->createMock(LoggerInterface::class);
  72. $this->timeFactory = $this->createMock(ITimeFactory::class);
  73. $this->time = 1313131;
  74. $this->timeFactory->method('getTime')
  75. ->willReturn($this->time);
  76. $this->tokenProvider = new PublicKeyTokenProvider(
  77. $this->mapper,
  78. $this->crypto,
  79. $this->config,
  80. $this->db,
  81. $this->logger,
  82. $this->timeFactory,
  83. $this->hasher,
  84. );
  85. }
  86. public function testGenerateToken() {
  87. $token = 'tokentokentokentokentoken';
  88. $uid = 'user';
  89. $user = 'User';
  90. $password = 'passme';
  91. $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12';
  92. $type = IToken::PERMANENT_TOKEN;
  93. $this->config->method('getSystemValueBool')
  94. ->willReturnMap([
  95. ['auth.storeCryptedPassword', true, true],
  96. ]);
  97. $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
  98. $this->assertInstanceOf(PublicKeyToken::class, $actual);
  99. $this->assertSame($uid, $actual->getUID());
  100. $this->assertSame($user, $actual->getLoginName());
  101. $this->assertSame($name, $actual->getName());
  102. $this->assertSame(IToken::DO_NOT_REMEMBER, $actual->getRemember());
  103. $this->assertSame($password, $this->tokenProvider->getPassword($actual, $token));
  104. }
  105. public function testGenerateTokenNoPassword(): void {
  106. $token = 'tokentokentokentokentoken';
  107. $uid = 'user';
  108. $user = 'User';
  109. $password = 'passme';
  110. $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12';
  111. $type = IToken::PERMANENT_TOKEN;
  112. $this->config->method('getSystemValueBool')
  113. ->willReturnMap([
  114. ['auth.storeCryptedPassword', true, false],
  115. ]);
  116. $this->expectException(PasswordlessTokenException::class);
  117. $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
  118. $this->assertInstanceOf(PublicKeyToken::class, $actual);
  119. $this->assertSame($uid, $actual->getUID());
  120. $this->assertSame($user, $actual->getLoginName());
  121. $this->assertSame($name, $actual->getName());
  122. $this->assertSame(IToken::DO_NOT_REMEMBER, $actual->getRemember());
  123. $this->tokenProvider->getPassword($actual, $token);
  124. }
  125. public function testGenerateTokenLongPassword() {
  126. $token = 'tokentokentokentokentoken';
  127. $uid = 'user';
  128. $user = 'User';
  129. $password = '';
  130. for ($i = 0; $i < 500; $i++) {
  131. $password .= 'e';
  132. }
  133. $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12';
  134. $type = IToken::PERMANENT_TOKEN;
  135. $this->config->method('getSystemValueBool')
  136. ->willReturnMap([
  137. ['auth.storeCryptedPassword', true, true],
  138. ]);
  139. $this->expectException(\RuntimeException::class);
  140. $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
  141. }
  142. public function testGenerateTokenInvalidName() {
  143. $token = 'tokentokentokentokentoken';
  144. $uid = 'user';
  145. $user = 'User';
  146. $password = 'passme';
  147. $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'
  148. . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'
  149. . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'
  150. . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12';
  151. $type = IToken::PERMANENT_TOKEN;
  152. $this->config->method('getSystemValueBool')
  153. ->willReturnMap([
  154. ['auth.storeCryptedPassword', true, true],
  155. ]);
  156. $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
  157. $this->assertInstanceOf(PublicKeyToken::class, $actual);
  158. $this->assertSame($uid, $actual->getUID());
  159. $this->assertSame($user, $actual->getLoginName());
  160. $this->assertSame('User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12User-Agent: Mozill…', $actual->getName());
  161. $this->assertSame(IToken::DO_NOT_REMEMBER, $actual->getRemember());
  162. $this->assertSame($password, $this->tokenProvider->getPassword($actual, $token));
  163. }
  164. public function testUpdateToken() {
  165. $tk = new PublicKeyToken();
  166. $this->mapper->expects($this->once())
  167. ->method('updateActivity')
  168. ->with($tk, $this->time);
  169. $tk->setLastActivity($this->time - 200);
  170. $this->config->method('getSystemValueBool')
  171. ->willReturnMap([
  172. ['auth.storeCryptedPassword', true, true],
  173. ]);
  174. $this->tokenProvider->updateTokenActivity($tk);
  175. $this->assertEquals($this->time, $tk->getLastActivity());
  176. }
  177. public function testUpdateTokenDebounce() {
  178. $tk = new PublicKeyToken();
  179. $this->config->method('getSystemValueInt')
  180. ->willReturnCallback(function ($value, $default) {
  181. return $default;
  182. });
  183. $tk->setLastActivity($this->time - 30);
  184. $this->mapper->expects($this->never())
  185. ->method('updateActivity')
  186. ->with($tk, $this->time);
  187. $this->tokenProvider->updateTokenActivity($tk);
  188. }
  189. public function testGetTokenByUser() {
  190. $this->mapper->expects($this->once())
  191. ->method('getTokenByUser')
  192. ->with('uid')
  193. ->willReturn(['token']);
  194. $this->assertEquals(['token'], $this->tokenProvider->getTokenByUser('uid'));
  195. }
  196. public function testGetPassword() {
  197. $token = 'tokentokentokentokentoken';
  198. $uid = 'user';
  199. $user = 'User';
  200. $password = 'passme';
  201. $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12';
  202. $type = IToken::PERMANENT_TOKEN;
  203. $this->config->method('getSystemValueBool')
  204. ->willReturnMap([
  205. ['auth.storeCryptedPassword', true, true],
  206. ]);
  207. $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
  208. $this->assertSame($password, $this->tokenProvider->getPassword($actual, $token));
  209. }
  210. public function testGetPasswordPasswordLessToken() {
  211. $this->expectException(\OC\Authentication\Exceptions\PasswordlessTokenException::class);
  212. $token = 'token1234';
  213. $tk = new PublicKeyToken();
  214. $tk->setPassword(null);
  215. $this->tokenProvider->getPassword($tk, $token);
  216. }
  217. public function testGetPasswordInvalidToken() {
  218. $this->expectException(\OC\Authentication\Exceptions\InvalidTokenException::class);
  219. $token = 'tokentokentokentokentoken';
  220. $uid = 'user';
  221. $user = 'User';
  222. $password = 'passme';
  223. $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12';
  224. $type = IToken::PERMANENT_TOKEN;
  225. $this->config->method('getSystemValueBool')
  226. ->willReturnMap([
  227. ['auth.storeCryptedPassword', true, true],
  228. ]);
  229. $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
  230. $this->tokenProvider->getPassword($actual, 'wrongtoken');
  231. }
  232. public function testSetPassword() {
  233. $token = 'tokentokentokentokentoken';
  234. $uid = 'user';
  235. $user = 'User';
  236. $password = 'passme';
  237. $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12';
  238. $type = IToken::PERMANENT_TOKEN;
  239. $this->config->method('getSystemValueBool')
  240. ->willReturnMap([
  241. ['auth.storeCryptedPassword', true, true],
  242. ]);
  243. $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
  244. $this->mapper->method('getTokenByUser')
  245. ->with('user')
  246. ->willReturn([$actual]);
  247. $newpass = 'newpass';
  248. $this->mapper->expects($this->once())
  249. ->method('update')
  250. ->with($this->callback(function ($token) use ($newpass) {
  251. return $newpass === $this->tokenProvider->getPassword($token, 'tokentokentokentokentoken');
  252. }));
  253. $this->tokenProvider->setPassword($actual, $token, $newpass);
  254. $this->assertSame($newpass, $this->tokenProvider->getPassword($actual, 'tokentokentokentokentoken'));
  255. }
  256. public function testSetPasswordInvalidToken() {
  257. $this->expectException(\OC\Authentication\Exceptions\InvalidTokenException::class);
  258. $token = $this->createMock(IToken::class);
  259. $tokenId = 'token123';
  260. $password = '123456';
  261. $this->tokenProvider->setPassword($token, $tokenId, $password);
  262. }
  263. public function testInvalidateToken() {
  264. $this->mapper->expects($this->exactly(2))
  265. ->method('invalidate')
  266. ->withConsecutive(
  267. [hash('sha512', 'token7'.'1f4h9s')],
  268. [hash('sha512', 'token7')]
  269. );
  270. $this->tokenProvider->invalidateToken('token7');
  271. }
  272. public function testInvaildateTokenById() {
  273. $id = 123;
  274. $this->mapper->expects($this->once())
  275. ->method('deleteById')
  276. ->with('uid', $id);
  277. $this->tokenProvider->invalidateTokenById('uid', $id);
  278. }
  279. public function testInvalidateOldTokens() {
  280. $defaultSessionLifetime = 60 * 60 * 24;
  281. $defaultRememberMeLifetime = 60 * 60 * 24 * 15;
  282. $this->config->expects($this->exactly(2))
  283. ->method('getSystemValue')
  284. ->willReturnMap([
  285. ['session_lifetime', $defaultSessionLifetime, 150],
  286. ['remember_login_cookie_lifetime', $defaultRememberMeLifetime, 300],
  287. ]);
  288. $this->mapper->expects($this->exactly(2))
  289. ->method('invalidateOld')
  290. ->withConsecutive(
  291. [$this->time - 150],
  292. [$this->time - 300]
  293. );
  294. $this->tokenProvider->invalidateOldTokens();
  295. }
  296. public function testRenewSessionTokenWithoutPassword() {
  297. $token = 'oldIdtokentokentokentoken';
  298. $uid = 'user';
  299. $user = 'User';
  300. $password = null;
  301. $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12';
  302. $type = IToken::PERMANENT_TOKEN;
  303. $oldToken = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
  304. $this->mapper
  305. ->expects($this->once())
  306. ->method('getToken')
  307. ->with(hash('sha512', 'oldIdtokentokentokentoken' . '1f4h9s'))
  308. ->willReturn($oldToken);
  309. $this->mapper
  310. ->expects($this->once())
  311. ->method('insert')
  312. ->with($this->callback(function (PublicKeyToken $token) use ($user, $uid, $name) {
  313. return $token->getUID() === $uid &&
  314. $token->getLoginName() === $user &&
  315. $token->getName() === $name &&
  316. $token->getType() === IToken::DO_NOT_REMEMBER &&
  317. $token->getLastActivity() === $this->time &&
  318. $token->getPassword() === null;
  319. }));
  320. $this->mapper
  321. ->expects($this->once())
  322. ->method('delete')
  323. ->with($this->callback(function ($token) use ($oldToken) {
  324. return $token === $oldToken;
  325. }));
  326. $this->tokenProvider->renewSessionToken('oldIdtokentokentokentoken', 'newIdtokentokentokentoken');
  327. }
  328. public function testRenewSessionTokenWithPassword(): void {
  329. $token = 'oldIdtokentokentokentoken';
  330. $uid = 'user';
  331. $user = 'User';
  332. $password = 'password';
  333. $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12';
  334. $type = IToken::PERMANENT_TOKEN;
  335. $this->config->method('getSystemValueBool')
  336. ->willReturnMap([
  337. ['auth.storeCryptedPassword', true, true],
  338. ]);
  339. $oldToken = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
  340. $this->mapper
  341. ->expects($this->once())
  342. ->method('getToken')
  343. ->with(hash('sha512', 'oldIdtokentokentokentoken' . '1f4h9s'))
  344. ->willReturn($oldToken);
  345. $this->mapper
  346. ->expects($this->once())
  347. ->method('insert')
  348. ->with($this->callback(function (PublicKeyToken $token) use ($user, $uid, $name): bool {
  349. return $token->getUID() === $uid &&
  350. $token->getLoginName() === $user &&
  351. $token->getName() === $name &&
  352. $token->getType() === IToken::DO_NOT_REMEMBER &&
  353. $token->getLastActivity() === $this->time &&
  354. $token->getPassword() !== null &&
  355. $this->tokenProvider->getPassword($token, 'newIdtokentokentokentoken') === 'password';
  356. }));
  357. $this->mapper
  358. ->expects($this->once())
  359. ->method('delete')
  360. ->with($this->callback(function ($token) use ($oldToken): bool {
  361. return $token === $oldToken;
  362. }));
  363. $this->tokenProvider->renewSessionToken('oldIdtokentokentokentoken', 'newIdtokentokentokentoken');
  364. }
  365. public function testGetToken(): void {
  366. $token = new PublicKeyToken();
  367. $this->config->method('getSystemValue')
  368. ->with('secret')
  369. ->willReturn('mysecret');
  370. $this->mapper->method('getToken')
  371. ->with(
  372. $this->callback(function (string $token) {
  373. return hash('sha512', 'unhashedTokentokentokentokentoken'.'1f4h9s') === $token;
  374. })
  375. )->willReturn($token);
  376. $this->assertSame($token, $this->tokenProvider->getToken('unhashedTokentokentokentokentoken'));
  377. }
  378. public function testGetInvalidToken() {
  379. $this->expectException(InvalidTokenException::class);
  380. $this->mapper->expects($this->exactly(2))
  381. ->method('getToken')
  382. ->withConsecutive(
  383. [$this->callback(function (string $token): bool {
  384. return hash('sha512', 'unhashedTokentokentokentokentoken'.'1f4h9s') === $token;
  385. })],
  386. [$this->callback(function (string $token): bool {
  387. return hash('sha512', 'unhashedTokentokentokentokentoken') === $token;
  388. })]
  389. )->willThrowException(new DoesNotExistException('nope'));
  390. $this->tokenProvider->getToken('unhashedTokentokentokentokentoken');
  391. }
  392. public function testGetExpiredToken() {
  393. $token = 'tokentokentokentokentoken';
  394. $uid = 'user';
  395. $user = 'User';
  396. $password = 'passme';
  397. $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12';
  398. $type = IToken::PERMANENT_TOKEN;
  399. $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
  400. $actual->setExpires(42);
  401. $this->mapper->method('getToken')
  402. ->with(
  403. $this->callback(function (string $token) {
  404. return hash('sha512', 'tokentokentokentokentoken'.'1f4h9s') === $token;
  405. })
  406. )->willReturn($actual);
  407. try {
  408. $this->tokenProvider->getToken('tokentokentokentokentoken');
  409. $this->fail();
  410. } catch (ExpiredTokenException $e) {
  411. $this->assertSame($actual, $e->getToken());
  412. }
  413. }
  414. public function testGetTokenById() {
  415. $token = $this->createMock(PublicKeyToken::class);
  416. $this->mapper->expects($this->once())
  417. ->method('getTokenById')
  418. ->with($this->equalTo(42))
  419. ->willReturn($token);
  420. $this->assertSame($token, $this->tokenProvider->getTokenById(42));
  421. }
  422. public function testGetInvalidTokenById() {
  423. $this->expectException(InvalidTokenException::class);
  424. $this->mapper->expects($this->once())
  425. ->method('getTokenById')
  426. ->with($this->equalTo(42))
  427. ->willThrowException(new DoesNotExistException('nope'));
  428. $this->tokenProvider->getTokenById(42);
  429. }
  430. public function testGetExpiredTokenById() {
  431. $token = new PublicKeyToken();
  432. $token->setExpires(42);
  433. $this->mapper->expects($this->once())
  434. ->method('getTokenById')
  435. ->with($this->equalTo(42))
  436. ->willReturn($token);
  437. try {
  438. $this->tokenProvider->getTokenById(42);
  439. $this->fail();
  440. } catch (ExpiredTokenException $e) {
  441. $this->assertSame($token, $e->getToken());
  442. }
  443. }
  444. public function testRotate() {
  445. $token = 'oldtokentokentokentokentoken';
  446. $uid = 'user';
  447. $user = 'User';
  448. $password = 'password';
  449. $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12';
  450. $type = IToken::PERMANENT_TOKEN;
  451. $this->config->method('getSystemValueBool')
  452. ->willReturnMap([
  453. ['auth.storeCryptedPassword', true, true],
  454. ]);
  455. $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
  456. $new = $this->tokenProvider->rotate($actual, 'oldtokentokentokentokentoken', 'newtokentokentokentokentoken');
  457. $this->assertSame('password', $this->tokenProvider->getPassword($new, 'newtokentokentokentokentoken'));
  458. }
  459. public function testRotateNoPassword() {
  460. $token = 'oldtokentokentokentokentoken';
  461. $uid = 'user';
  462. $user = 'User';
  463. $password = null;
  464. $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12';
  465. $type = IToken::PERMANENT_TOKEN;
  466. $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
  467. $oldPrivate = $actual->getPrivateKey();
  468. $new = $this->tokenProvider->rotate($actual, 'oldtokentokentokentokentoken', 'newtokentokentokentokentoken');
  469. $newPrivate = $new->getPrivateKey();
  470. $this->assertNotSame($newPrivate, $oldPrivate);
  471. $this->assertNull($new->getPassword());
  472. }
  473. public function testMarkPasswordInvalidInvalidToken() {
  474. $token = $this->createMock(IToken::class);
  475. $this->expectException(InvalidTokenException::class);
  476. $this->tokenProvider->markPasswordInvalid($token, 'tokenId');
  477. }
  478. public function testMarkPasswordInvalid() {
  479. $token = $this->createMock(PublicKeyToken::class);
  480. $token->expects($this->once())
  481. ->method('setPasswordInvalid')
  482. ->with(true);
  483. $this->mapper->expects($this->once())
  484. ->method('update')
  485. ->with($token);
  486. $this->tokenProvider->markPasswordInvalid($token, 'tokenId');
  487. }
  488. public function testUpdatePasswords() {
  489. $uid = 'myUID';
  490. $token1 = $this->tokenProvider->generateToken(
  491. 'foobetokentokentokentoken',
  492. $uid,
  493. $uid,
  494. 'bar',
  495. 'random1',
  496. IToken::PERMANENT_TOKEN,
  497. IToken::REMEMBER);
  498. $token2 = $this->tokenProvider->generateToken(
  499. 'foobartokentokentokentoken',
  500. $uid,
  501. $uid,
  502. 'bar',
  503. 'random2',
  504. IToken::PERMANENT_TOKEN,
  505. IToken::REMEMBER);
  506. $this->config->method('getSystemValueBool')
  507. ->willReturnMap([
  508. ['auth.storeCryptedPassword', true, true],
  509. ]);
  510. $this->mapper->method('hasExpiredTokens')
  511. ->with($uid)
  512. ->willReturn(true);
  513. $this->mapper->expects($this->once())
  514. ->method('getTokenByUser')
  515. ->with($uid)
  516. ->willReturn([$token1, $token2]);
  517. $this->mapper->expects($this->exactly(2))
  518. ->method('update')
  519. ->with($this->callback(function (PublicKeyToken $t) use ($token1, $token2) {
  520. return $t === $token1 || $t === $token2;
  521. }));
  522. $this->tokenProvider->updatePasswords($uid, 'bar2');
  523. }
  524. }