ClientFlowLoginControllerTest.php 19 KB

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