ClientFlowLoginControllerTest.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
  4. *
  5. * @license GNU AGPL version 3 or any later version
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Affero General Public License as
  9. * published by the Free Software Foundation, either version 3 of the
  10. * License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. namespace Tests\Core\Controller;
  22. use OC\Authentication\Exceptions\InvalidTokenException;
  23. use OC\Authentication\Exceptions\PasswordlessTokenException;
  24. use OC\Authentication\Token\IProvider;
  25. use OC\Authentication\Token\IToken;
  26. use OC\Core\Controller\ClientFlowLoginController;
  27. use OCA\OAuth2\Db\AccessTokenMapper;
  28. use OCA\OAuth2\Db\Client;
  29. use OCA\OAuth2\Db\ClientMapper;
  30. use OCP\AppFramework\Http;
  31. use OCP\AppFramework\Http\StandaloneTemplateResponse;
  32. use OCP\AppFramework\Utility\ITimeFactory;
  33. use OCP\Defaults;
  34. use OCP\EventDispatcher\IEventDispatcher;
  35. use OCP\IL10N;
  36. use OCP\IRequest;
  37. use OCP\ISession;
  38. use OCP\IURLGenerator;
  39. use OCP\IUser;
  40. use OCP\IUserSession;
  41. use OCP\Security\ICrypto;
  42. use OCP\Security\ISecureRandom;
  43. use OCP\Session\Exceptions\SessionNotAvailableException;
  44. use Test\TestCase;
  45. class ClientFlowLoginControllerTest extends TestCase {
  46. /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */
  47. private $request;
  48. /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
  49. private $userSession;
  50. /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */
  51. private $l10n;
  52. /** @var Defaults|\PHPUnit\Framework\MockObject\MockObject */
  53. private $defaults;
  54. /** @var ISession|\PHPUnit\Framework\MockObject\MockObject */
  55. private $session;
  56. /** @var IProvider|\PHPUnit\Framework\MockObject\MockObject */
  57. private $tokenProvider;
  58. /** @var ISecureRandom|\PHPUnit\Framework\MockObject\MockObject */
  59. private $random;
  60. /** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */
  61. private $urlGenerator;
  62. /** @var ClientMapper|\PHPUnit\Framework\MockObject\MockObject */
  63. private $clientMapper;
  64. /** @var AccessTokenMapper|\PHPUnit\Framework\MockObject\MockObject */
  65. private $accessTokenMapper;
  66. /** @var ICrypto|\PHPUnit\Framework\MockObject\MockObject */
  67. private $crypto;
  68. /** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */
  69. private $eventDispatcher;
  70. /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */
  71. private $timeFactory;
  72. /** @var ClientFlowLoginController */
  73. private $clientFlowLoginController;
  74. protected function setUp(): void {
  75. parent::setUp();
  76. $this->request = $this->createMock(IRequest::class);
  77. $this->userSession = $this->createMock(IUserSession::class);
  78. $this->l10n = $this->createMock(IL10N::class);
  79. $this->l10n
  80. ->expects($this->any())
  81. ->method('t')
  82. ->willReturnCallback(function ($text, $parameters = []) {
  83. return vsprintf($text, $parameters);
  84. });
  85. $this->defaults = $this->createMock(Defaults::class);
  86. $this->session = $this->createMock(ISession::class);
  87. $this->tokenProvider = $this->createMock(IProvider::class);
  88. $this->random = $this->createMock(ISecureRandom::class);
  89. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  90. $this->clientMapper = $this->createMock(ClientMapper::class);
  91. $this->accessTokenMapper = $this->createMock(AccessTokenMapper::class);
  92. $this->crypto = $this->createMock(ICrypto::class);
  93. $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
  94. $this->timeFactory = $this->createMock(ITimeFactory::class);
  95. $this->clientFlowLoginController = new ClientFlowLoginController(
  96. 'core',
  97. $this->request,
  98. $this->userSession,
  99. $this->l10n,
  100. $this->defaults,
  101. $this->session,
  102. $this->tokenProvider,
  103. $this->random,
  104. $this->urlGenerator,
  105. $this->clientMapper,
  106. $this->accessTokenMapper,
  107. $this->crypto,
  108. $this->eventDispatcher,
  109. $this->timeFactory
  110. );
  111. }
  112. public function testShowAuthPickerPageNoClientOrOauthRequest() {
  113. $expected = new StandaloneTemplateResponse(
  114. 'core',
  115. 'error',
  116. [
  117. 'errors' =>
  118. [
  119. [
  120. 'error' => 'Access Forbidden',
  121. 'hint' => 'Invalid request',
  122. ],
  123. ],
  124. ],
  125. 'guest'
  126. );
  127. $this->assertEquals($expected, $this->clientFlowLoginController->showAuthPickerPage());
  128. }
  129. public function testShowAuthPickerPageWithOcsHeader() {
  130. $this->request
  131. ->method('getHeader')
  132. ->withConsecutive(
  133. ['USER_AGENT'],
  134. ['OCS-APIREQUEST']
  135. )
  136. ->willReturnMap([
  137. ['USER_AGENT', 'Mac OS X Sync Client'],
  138. ['OCS-APIREQUEST', 'true'],
  139. ]);
  140. $this->random
  141. ->expects($this->once())
  142. ->method('generate')
  143. ->with(
  144. 64,
  145. ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS
  146. )
  147. ->willReturn('StateToken');
  148. $this->session
  149. ->expects($this->once())
  150. ->method('set')
  151. ->with('client.flow.state.token', 'StateToken');
  152. $this->session
  153. ->expects($this->once())
  154. ->method('get')
  155. ->with('oauth.state')
  156. ->willReturn('OauthStateToken');
  157. $this->defaults
  158. ->expects($this->once())
  159. ->method('getName')
  160. ->willReturn('ExampleCloud');
  161. $this->request
  162. ->expects($this->once())
  163. ->method('getServerHost')
  164. ->willReturn('example.com');
  165. $this->request
  166. ->method('getServerProtocol')
  167. ->willReturn('https');
  168. $expected = new StandaloneTemplateResponse(
  169. 'core',
  170. 'loginflow/authpicker',
  171. [
  172. 'client' => 'Mac OS X Sync Client',
  173. 'clientIdentifier' => '',
  174. 'instanceName' => 'ExampleCloud',
  175. 'urlGenerator' => $this->urlGenerator,
  176. 'stateToken' => 'StateToken',
  177. 'serverHost' => 'https://example.com',
  178. 'oauthState' => 'OauthStateToken',
  179. 'user' => '',
  180. 'direct' => 0
  181. ],
  182. 'guest'
  183. );
  184. $csp = new Http\ContentSecurityPolicy();
  185. $csp->addAllowedFormActionDomain('nc://*');
  186. $expected->setContentSecurityPolicy($csp);
  187. $this->assertEquals($expected, $this->clientFlowLoginController->showAuthPickerPage());
  188. }
  189. public function testShowAuthPickerPageWithOauth() {
  190. $this->request
  191. ->method('getHeader')
  192. ->withConsecutive(
  193. ['USER_AGENT'],
  194. ['OCS-APIREQUEST']
  195. )
  196. ->willReturnMap([
  197. ['USER_AGENT', 'Mac OS X Sync Client'],
  198. ['OCS-APIREQUEST', 'false'],
  199. ]);
  200. $client = new Client();
  201. $client->setName('My external service');
  202. $client->setRedirectUri('https://example.com/redirect.php');
  203. $this->clientMapper
  204. ->expects($this->once())
  205. ->method('getByIdentifier')
  206. ->with('MyClientIdentifier')
  207. ->willReturn($client);
  208. $this->random
  209. ->expects($this->once())
  210. ->method('generate')
  211. ->with(
  212. 64,
  213. ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS
  214. )
  215. ->willReturn('StateToken');
  216. $this->session
  217. ->expects($this->once())
  218. ->method('set')
  219. ->with('client.flow.state.token', 'StateToken');
  220. $this->session
  221. ->expects($this->once())
  222. ->method('get')
  223. ->with('oauth.state')
  224. ->willReturn('OauthStateToken');
  225. $this->defaults
  226. ->expects($this->once())
  227. ->method('getName')
  228. ->willReturn('ExampleCloud');
  229. $this->request
  230. ->expects($this->once())
  231. ->method('getServerHost')
  232. ->willReturn('example.com');
  233. $this->request
  234. ->method('getServerProtocol')
  235. ->willReturn('https');
  236. $expected = new StandaloneTemplateResponse(
  237. 'core',
  238. 'loginflow/authpicker',
  239. [
  240. 'client' => 'My external service',
  241. 'clientIdentifier' => 'MyClientIdentifier',
  242. 'instanceName' => 'ExampleCloud',
  243. 'urlGenerator' => $this->urlGenerator,
  244. 'stateToken' => 'StateToken',
  245. 'serverHost' => 'https://example.com',
  246. 'oauthState' => 'OauthStateToken',
  247. 'user' => '',
  248. 'direct' => 0
  249. ],
  250. 'guest'
  251. );
  252. $csp = new Http\ContentSecurityPolicy();
  253. $csp->addAllowedFormActionDomain('https://example.com/redirect.php');
  254. $expected->setContentSecurityPolicy($csp);
  255. $this->assertEquals($expected, $this->clientFlowLoginController->showAuthPickerPage('MyClientIdentifier'));
  256. }
  257. public function testGenerateAppPasswordWithInvalidToken() {
  258. $this->session
  259. ->expects($this->once())
  260. ->method('get')
  261. ->with('client.flow.state.token')
  262. ->willReturn('OtherToken');
  263. $this->session
  264. ->expects($this->once())
  265. ->method('remove')
  266. ->with('client.flow.state.token');
  267. $expected = new StandaloneTemplateResponse(
  268. 'core',
  269. '403',
  270. [
  271. 'message' => 'State token does not match',
  272. ],
  273. 'guest'
  274. );
  275. $expected->setStatus(Http::STATUS_FORBIDDEN);
  276. $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken'));
  277. }
  278. public function testGenerateAppPasswordWithSessionNotAvailableException() {
  279. $this->session
  280. ->expects($this->once())
  281. ->method('get')
  282. ->with('client.flow.state.token')
  283. ->willReturn('MyStateToken');
  284. $this->session
  285. ->expects($this->once())
  286. ->method('remove')
  287. ->with('client.flow.state.token');
  288. $this->session
  289. ->expects($this->once())
  290. ->method('getId')
  291. ->willThrowException(new SessionNotAvailableException());
  292. $expected = new Http\Response();
  293. $expected->setStatus(Http::STATUS_FORBIDDEN);
  294. $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken'));
  295. }
  296. public function testGenerateAppPasswordWithInvalidTokenException() {
  297. $this->session
  298. ->expects($this->once())
  299. ->method('get')
  300. ->with('client.flow.state.token')
  301. ->willReturn('MyStateToken');
  302. $this->session
  303. ->expects($this->once())
  304. ->method('remove')
  305. ->with('client.flow.state.token');
  306. $this->session
  307. ->expects($this->once())
  308. ->method('getId')
  309. ->willReturn('SessionId');
  310. $this->tokenProvider
  311. ->expects($this->once())
  312. ->method('getToken')
  313. ->with('SessionId')
  314. ->willThrowException(new InvalidTokenException());
  315. $expected = new Http\Response();
  316. $expected->setStatus(Http::STATUS_FORBIDDEN);
  317. $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken'));
  318. }
  319. public function testGeneratePasswordWithPassword() {
  320. $this->session
  321. ->expects($this->once())
  322. ->method('get')
  323. ->with('client.flow.state.token')
  324. ->willReturn('MyStateToken');
  325. $this->session
  326. ->expects($this->once())
  327. ->method('remove')
  328. ->with('client.flow.state.token');
  329. $this->session
  330. ->expects($this->once())
  331. ->method('getId')
  332. ->willReturn('SessionId');
  333. $myToken = $this->createMock(IToken::class);
  334. $myToken
  335. ->expects($this->once())
  336. ->method('getLoginName')
  337. ->willReturn('MyLoginName');
  338. $this->tokenProvider
  339. ->expects($this->once())
  340. ->method('getToken')
  341. ->with('SessionId')
  342. ->willReturn($myToken);
  343. $this->tokenProvider
  344. ->expects($this->once())
  345. ->method('getPassword')
  346. ->with($myToken, 'SessionId')
  347. ->willReturn('MyPassword');
  348. $this->random
  349. ->expects($this->once())
  350. ->method('generate')
  351. ->with(72)
  352. ->willReturn('MyGeneratedToken');
  353. $user = $this->createMock(IUser::class);
  354. $user
  355. ->expects($this->once())
  356. ->method('getUID')
  357. ->willReturn('MyUid');
  358. $this->userSession
  359. ->expects($this->once())
  360. ->method('getUser')
  361. ->willReturn($user);
  362. $this->tokenProvider
  363. ->expects($this->once())
  364. ->method('generateToken')
  365. ->with(
  366. 'MyGeneratedToken',
  367. 'MyUid',
  368. 'MyLoginName',
  369. 'MyPassword',
  370. 'unknown',
  371. IToken::PERMANENT_TOKEN,
  372. IToken::DO_NOT_REMEMBER
  373. );
  374. $this->request
  375. ->expects($this->once())
  376. ->method('getServerProtocol')
  377. ->willReturn('http');
  378. $this->request
  379. ->expects($this->once())
  380. ->method('getServerHost')
  381. ->willReturn('example.com');
  382. $this->request
  383. ->expects($this->any())
  384. ->method('getHeader')
  385. ->willReturn('');
  386. $this->eventDispatcher->expects($this->once())
  387. ->method('dispatchTyped');
  388. $expected = new Http\RedirectResponse('nc://login/server:http://example.com&user:MyLoginName&password:MyGeneratedToken');
  389. $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken'));
  390. }
  391. /**
  392. * @param string $redirectUri
  393. * @param string $redirectUrl
  394. *
  395. * @testWith
  396. * ["https://example.com/redirect.php", "https://example.com/redirect.php?state=MyOauthState&code=MyAccessCode"]
  397. * ["https://example.com/redirect.php?hello=world", "https://example.com/redirect.php?hello=world&state=MyOauthState&code=MyAccessCode"]
  398. *
  399. */
  400. public function testGeneratePasswordWithPasswordForOauthClient($redirectUri, $redirectUrl) {
  401. $this->session
  402. ->method('get')
  403. ->withConsecutive(
  404. ['client.flow.state.token'],
  405. ['oauth.state']
  406. )
  407. ->willReturnMap([
  408. ['client.flow.state.token', 'MyStateToken'],
  409. ['oauth.state', 'MyOauthState'],
  410. ]);
  411. $this->session
  412. ->method('remove')
  413. ->withConsecutive(
  414. ['client.flow.state.token'],
  415. ['oauth.state']
  416. );
  417. $this->session
  418. ->expects($this->once())
  419. ->method('getId')
  420. ->willReturn('SessionId');
  421. $myToken = $this->createMock(IToken::class);
  422. $myToken
  423. ->expects($this->once())
  424. ->method('getLoginName')
  425. ->willReturn('MyLoginName');
  426. $this->tokenProvider
  427. ->expects($this->once())
  428. ->method('getToken')
  429. ->with('SessionId')
  430. ->willReturn($myToken);
  431. $this->tokenProvider
  432. ->expects($this->once())
  433. ->method('getPassword')
  434. ->with($myToken, 'SessionId')
  435. ->willReturn('MyPassword');
  436. $this->random
  437. ->method('generate')
  438. ->withConsecutive(
  439. [72],
  440. [128]
  441. )
  442. ->willReturnMap([
  443. [72, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS, 'MyGeneratedToken'],
  444. [128, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS, 'MyAccessCode'],
  445. ]);
  446. $user = $this->createMock(IUser::class);
  447. $user
  448. ->expects($this->once())
  449. ->method('getUID')
  450. ->willReturn('MyUid');
  451. $this->userSession
  452. ->expects($this->once())
  453. ->method('getUser')
  454. ->willReturn($user);
  455. $token = $this->createMock(IToken::class);
  456. $this->tokenProvider
  457. ->expects($this->once())
  458. ->method('generateToken')
  459. ->with(
  460. 'MyGeneratedToken',
  461. 'MyUid',
  462. 'MyLoginName',
  463. 'MyPassword',
  464. 'My OAuth client',
  465. IToken::PERMANENT_TOKEN,
  466. IToken::DO_NOT_REMEMBER
  467. )
  468. ->willReturn($token);
  469. $client = new Client();
  470. $client->setName('My OAuth client');
  471. $client->setRedirectUri($redirectUri);
  472. $this->clientMapper
  473. ->expects($this->once())
  474. ->method('getByIdentifier')
  475. ->with('MyClientIdentifier')
  476. ->willReturn($client);
  477. $this->eventDispatcher->expects($this->once())
  478. ->method('dispatchTyped');
  479. $expected = new Http\RedirectResponse($redirectUrl);
  480. $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken', 'MyClientIdentifier'));
  481. }
  482. public function testGeneratePasswordWithoutPassword() {
  483. $this->session
  484. ->expects($this->once())
  485. ->method('get')
  486. ->with('client.flow.state.token')
  487. ->willReturn('MyStateToken');
  488. $this->session
  489. ->expects($this->once())
  490. ->method('remove')
  491. ->with('client.flow.state.token');
  492. $this->session
  493. ->expects($this->once())
  494. ->method('getId')
  495. ->willReturn('SessionId');
  496. $myToken = $this->createMock(IToken::class);
  497. $myToken
  498. ->expects($this->once())
  499. ->method('getLoginName')
  500. ->willReturn('MyLoginName');
  501. $this->tokenProvider
  502. ->expects($this->once())
  503. ->method('getToken')
  504. ->with('SessionId')
  505. ->willReturn($myToken);
  506. $this->tokenProvider
  507. ->expects($this->once())
  508. ->method('getPassword')
  509. ->with($myToken, 'SessionId')
  510. ->willThrowException(new PasswordlessTokenException());
  511. $this->random
  512. ->expects($this->once())
  513. ->method('generate')
  514. ->with(72)
  515. ->willReturn('MyGeneratedToken');
  516. $user = $this->createMock(IUser::class);
  517. $user
  518. ->expects($this->once())
  519. ->method('getUID')
  520. ->willReturn('MyUid');
  521. $this->userSession
  522. ->expects($this->once())
  523. ->method('getUser')
  524. ->willReturn($user);
  525. $this->tokenProvider
  526. ->expects($this->once())
  527. ->method('generateToken')
  528. ->with(
  529. 'MyGeneratedToken',
  530. 'MyUid',
  531. 'MyLoginName',
  532. null,
  533. 'unknown',
  534. IToken::PERMANENT_TOKEN,
  535. IToken::DO_NOT_REMEMBER
  536. );
  537. $this->request
  538. ->expects($this->once())
  539. ->method('getServerProtocol')
  540. ->willReturn('http');
  541. $this->request
  542. ->expects($this->once())
  543. ->method('getServerHost')
  544. ->willReturn('example.com');
  545. $this->request
  546. ->expects($this->any())
  547. ->method('getHeader')
  548. ->willReturn('');
  549. $this->eventDispatcher->expects($this->once())
  550. ->method('dispatchTyped');
  551. $expected = new Http\RedirectResponse('nc://login/server:http://example.com&user:MyLoginName&password:MyGeneratedToken');
  552. $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken'));
  553. }
  554. public function dataGeneratePasswordWithHttpsProxy() {
  555. return [
  556. [
  557. [
  558. ['X-Forwarded-Proto', 'http'],
  559. ['X-Forwarded-Ssl', 'off'],
  560. ['USER_AGENT', ''],
  561. ],
  562. 'http',
  563. 'http',
  564. ],
  565. [
  566. [
  567. ['X-Forwarded-Proto', 'http'],
  568. ['X-Forwarded-Ssl', 'off'],
  569. ['USER_AGENT', ''],
  570. ],
  571. 'https',
  572. 'https',
  573. ],
  574. [
  575. [
  576. ['X-Forwarded-Proto', 'https'],
  577. ['X-Forwarded-Ssl', 'off'],
  578. ['USER_AGENT', ''],
  579. ],
  580. 'http',
  581. 'https',
  582. ],
  583. [
  584. [
  585. ['X-Forwarded-Proto', 'https'],
  586. ['X-Forwarded-Ssl', 'on'],
  587. ['USER_AGENT', ''],
  588. ],
  589. 'http',
  590. 'https',
  591. ],
  592. [
  593. [
  594. ['X-Forwarded-Proto', 'http'],
  595. ['X-Forwarded-Ssl', 'on'],
  596. ['USER_AGENT', ''],
  597. ],
  598. 'http',
  599. 'https',
  600. ],
  601. ];
  602. }
  603. /**
  604. * @dataProvider dataGeneratePasswordWithHttpsProxy
  605. * @param array $headers
  606. * @param string $protocol
  607. * @param string $expected
  608. */
  609. public function testGeneratePasswordWithHttpsProxy(array $headers, $protocol, $expected) {
  610. $this->session
  611. ->expects($this->once())
  612. ->method('get')
  613. ->with('client.flow.state.token')
  614. ->willReturn('MyStateToken');
  615. $this->session
  616. ->expects($this->once())
  617. ->method('remove')
  618. ->with('client.flow.state.token');
  619. $this->session
  620. ->expects($this->once())
  621. ->method('getId')
  622. ->willReturn('SessionId');
  623. $myToken = $this->createMock(IToken::class);
  624. $myToken
  625. ->expects($this->once())
  626. ->method('getLoginName')
  627. ->willReturn('MyLoginName');
  628. $this->tokenProvider
  629. ->expects($this->once())
  630. ->method('getToken')
  631. ->with('SessionId')
  632. ->willReturn($myToken);
  633. $this->tokenProvider
  634. ->expects($this->once())
  635. ->method('getPassword')
  636. ->with($myToken, 'SessionId')
  637. ->willReturn('MyPassword');
  638. $this->random
  639. ->expects($this->once())
  640. ->method('generate')
  641. ->with(72)
  642. ->willReturn('MyGeneratedToken');
  643. $user = $this->createMock(IUser::class);
  644. $user
  645. ->expects($this->once())
  646. ->method('getUID')
  647. ->willReturn('MyUid');
  648. $this->userSession
  649. ->expects($this->once())
  650. ->method('getUser')
  651. ->willReturn($user);
  652. $this->tokenProvider
  653. ->expects($this->once())
  654. ->method('generateToken')
  655. ->with(
  656. 'MyGeneratedToken',
  657. 'MyUid',
  658. 'MyLoginName',
  659. 'MyPassword',
  660. 'unknown',
  661. IToken::PERMANENT_TOKEN,
  662. IToken::DO_NOT_REMEMBER
  663. );
  664. $this->request
  665. ->expects($this->once())
  666. ->method('getServerProtocol')
  667. ->willReturn($protocol);
  668. $this->request
  669. ->expects($this->once())
  670. ->method('getServerHost')
  671. ->willReturn('example.com');
  672. $this->request
  673. ->expects($this->atLeastOnce())
  674. ->method('getHeader')
  675. ->willReturnMap($headers);
  676. $this->eventDispatcher->expects($this->once())
  677. ->method('dispatchTyped');
  678. $expected = new Http\RedirectResponse('nc://login/server:' . $expected . '://example.com&user:MyLoginName&password:MyGeneratedToken');
  679. $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken'));
  680. }
  681. }