TwoFactorChallengeControllerTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. <?php
  2. /**
  3. * @author Christoph Wurst <christoph@owncloud.com>
  4. *
  5. * @copyright Copyright (c) 2016, ownCloud, Inc.
  6. * @license AGPL-3.0
  7. *
  8. * This code is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License, version 3,
  10. * as published by the Free Software Foundation.
  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, version 3,
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>
  19. *
  20. */
  21. namespace Test\Core\Controller;
  22. use OC\Authentication\TwoFactorAuth\Manager;
  23. use OC\Authentication\TwoFactorAuth\ProviderSet;
  24. use OC\Core\Controller\TwoFactorChallengeController;
  25. use OC_Util;
  26. use OCP\AppFramework\Http\RedirectResponse;
  27. use OCP\AppFramework\Http\TemplateResponse;
  28. use OCP\Authentication\TwoFactorAuth\IProvider;
  29. use OCP\Authentication\TwoFactorAuth\TwoFactorException;
  30. use OCP\IRequest;
  31. use OCP\ISession;
  32. use OCP\IURLGenerator;
  33. use OCP\IUser;
  34. use OCP\IUserSession;
  35. use OCP\Template;
  36. use PHPUnit_Framework_MockObject_MockObject;
  37. use Test\TestCase;
  38. class TwoFactorChallengeControllerTest extends TestCase {
  39. /** @var IRequest|PHPUnit_Framework_MockObject_MockObject */
  40. private $request;
  41. /** @var Manager|PHPUnit_Framework_MockObject_MockObject */
  42. private $twoFactorManager;
  43. /** @var IUserSession|PHPUnit_Framework_MockObject_MockObject */
  44. private $userSession;
  45. /** @var ISession|PHPUnit_Framework_MockObject_MockObject */
  46. private $session;
  47. /** @var IURLGenerator|PHPUnit_Framework_MockObject_MockObject */
  48. private $urlGenerator;
  49. /** @var TwoFactorChallengeController|PHPUnit_Framework_MockObject_MockObject */
  50. private $controller;
  51. protected function setUp() {
  52. parent::setUp();
  53. $this->request = $this->createMock(IRequest::class);
  54. $this->twoFactorManager = $this->createMock(Manager::class);
  55. $this->userSession = $this->createMock(IUserSession::class);
  56. $this->session = $this->createMock(ISession::class);
  57. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  58. $this->controller = $this->getMockBuilder(TwoFactorChallengeController::class)
  59. ->setConstructorArgs([
  60. 'core',
  61. $this->request,
  62. $this->twoFactorManager,
  63. $this->userSession,
  64. $this->session,
  65. $this->urlGenerator,
  66. ])
  67. ->setMethods(['getLogoutUrl'])
  68. ->getMock();
  69. $this->controller->expects($this->any())
  70. ->method('getLogoutUrl')
  71. ->willReturn('logoutAttribute');
  72. }
  73. public function testSelectChallenge() {
  74. $user = $this->getMockBuilder(IUser::class)->getMock();
  75. $p1 = $this->createMock(IProvider::class);
  76. $p1->method('getId')->willReturn('p1');
  77. $backupProvider = $this->createMock(IProvider::class);
  78. $backupProvider->method('getId')->willReturn('backup_codes');
  79. $providerSet = new ProviderSet([$p1, $backupProvider], true);
  80. $this->userSession->expects($this->once())
  81. ->method('getUser')
  82. ->will($this->returnValue($user));
  83. $this->twoFactorManager->expects($this->once())
  84. ->method('getProviderSet')
  85. ->with($user)
  86. ->will($this->returnValue($providerSet));
  87. $expected = new TemplateResponse('core', 'twofactorselectchallenge', [
  88. 'providers' => [
  89. $p1,
  90. ],
  91. 'providerMissing' => true,
  92. 'backupProvider' => $backupProvider,
  93. 'redirect_url' => '/some/url',
  94. 'logout_url' => 'logoutAttribute',
  95. ], 'guest');
  96. $this->assertEquals($expected, $this->controller->selectChallenge('/some/url'));
  97. }
  98. public function testShowChallenge() {
  99. $user = $this->createMock(IUser::class);
  100. $provider = $this->createMock(IProvider::class);
  101. $provider->method('getId')->willReturn('myprovider');
  102. $backupProvider = $this->createMock(IProvider::class);
  103. $backupProvider->method('getId')->willReturn('backup_codes');
  104. $tmpl = $this->createMock(Template::class);
  105. $providerSet = new ProviderSet([$provider, $backupProvider], true);
  106. $this->userSession->expects($this->once())
  107. ->method('getUser')
  108. ->will($this->returnValue($user));
  109. $this->twoFactorManager->expects($this->once())
  110. ->method('getProviderSet')
  111. ->with($user)
  112. ->will($this->returnValue($providerSet));
  113. $provider->expects($this->once())
  114. ->method('getId')
  115. ->will($this->returnValue('u2f'));
  116. $backupProvider->expects($this->once())
  117. ->method('getId')
  118. ->will($this->returnValue('backup_codes'));
  119. $this->session->expects($this->once())
  120. ->method('exists')
  121. ->with('two_factor_auth_error')
  122. ->will($this->returnValue(true));
  123. $this->session->expects($this->exactly(2))
  124. ->method('remove')
  125. ->with($this->logicalOr($this->equalTo('two_factor_auth_error'), $this->equalTo('two_factor_auth_error_message')));
  126. $provider->expects($this->once())
  127. ->method('getTemplate')
  128. ->with($user)
  129. ->will($this->returnValue($tmpl));
  130. $tmpl->expects($this->once())
  131. ->method('fetchPage')
  132. ->will($this->returnValue('<html/>'));
  133. $expected = new TemplateResponse('core', 'twofactorshowchallenge', [
  134. 'error' => true,
  135. 'provider' => $provider,
  136. 'backupProvider' => $backupProvider,
  137. 'logout_url' => 'logoutAttribute',
  138. 'template' => '<html/>',
  139. 'redirect_url' => '/re/dir/ect/url',
  140. 'error_message' => null,
  141. ], 'guest');
  142. $this->assertEquals($expected, $this->controller->showChallenge('myprovider', '/re/dir/ect/url'));
  143. }
  144. public function testShowInvalidChallenge() {
  145. $user = $this->createMock(IUser::class);
  146. $providerSet = new ProviderSet([], false);
  147. $this->userSession->expects($this->once())
  148. ->method('getUser')
  149. ->will($this->returnValue($user));
  150. $this->twoFactorManager->expects($this->once())
  151. ->method('getProviderSet')
  152. ->with($user)
  153. ->will($this->returnValue($providerSet));
  154. $this->urlGenerator->expects($this->once())
  155. ->method('linkToRoute')
  156. ->with('core.TwoFactorChallenge.selectChallenge')
  157. ->will($this->returnValue('select/challenge/url'));
  158. $expected = new RedirectResponse('select/challenge/url');
  159. $this->assertEquals($expected, $this->controller->showChallenge('myprovider', 'redirect/url'));
  160. }
  161. public function testSolveChallenge() {
  162. $user = $this->createMock(IUser::class);
  163. $provider = $this->createMock(IProvider::class);
  164. $this->userSession->expects($this->once())
  165. ->method('getUser')
  166. ->will($this->returnValue($user));
  167. $this->twoFactorManager->expects($this->once())
  168. ->method('getProvider')
  169. ->with($user, 'myprovider')
  170. ->will($this->returnValue($provider));
  171. $this->twoFactorManager->expects($this->once())
  172. ->method('verifyChallenge')
  173. ->with('myprovider', $user, 'token')
  174. ->will($this->returnValue(true));
  175. $expected = new RedirectResponse(OC_Util::getDefaultPageUrl());
  176. $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token'));
  177. }
  178. public function testSolveValidChallengeAndRedirect() {
  179. $user = $this->createMock(IUser::class);
  180. $provider = $this->createMock(IProvider::class);
  181. $this->userSession->expects($this->once())
  182. ->method('getUser')
  183. ->will($this->returnValue($user));
  184. $this->twoFactorManager->expects($this->once())
  185. ->method('getProvider')
  186. ->with($user, 'myprovider')
  187. ->will($this->returnValue($provider));
  188. $this->twoFactorManager->expects($this->once())
  189. ->method('verifyChallenge')
  190. ->with('myprovider', $user, 'token')
  191. ->willReturn(true);
  192. $this->urlGenerator->expects($this->once())
  193. ->method('getAbsoluteURL')
  194. ->with('redirect url')
  195. ->willReturn('redirect/url');
  196. $expected = new RedirectResponse('redirect/url');
  197. $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token', 'redirect%20url'));
  198. }
  199. public function testSolveChallengeInvalidProvider() {
  200. $user = $this->getMockBuilder(IUser::class)->getMock();
  201. $this->userSession->expects($this->once())
  202. ->method('getUser')
  203. ->will($this->returnValue($user));
  204. $this->twoFactorManager->expects($this->once())
  205. ->method('getProvider')
  206. ->with($user, 'myprovider')
  207. ->will($this->returnValue(null));
  208. $this->urlGenerator->expects($this->once())
  209. ->method('linkToRoute')
  210. ->with('core.TwoFactorChallenge.selectChallenge')
  211. ->will($this->returnValue('select/challenge/url'));
  212. $expected = new RedirectResponse('select/challenge/url');
  213. $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token'));
  214. }
  215. public function testSolveInvalidChallenge() {
  216. $user = $this->createMock(IUser::class);
  217. $provider = $this->createMock(IProvider::class);
  218. $this->userSession->expects($this->once())
  219. ->method('getUser')
  220. ->will($this->returnValue($user));
  221. $this->twoFactorManager->expects($this->once())
  222. ->method('getProvider')
  223. ->with($user, 'myprovider')
  224. ->will($this->returnValue($provider));
  225. $this->twoFactorManager->expects($this->once())
  226. ->method('verifyChallenge')
  227. ->with('myprovider', $user, 'token')
  228. ->will($this->returnValue(false));
  229. $this->session->expects($this->once())
  230. ->method('set')
  231. ->with('two_factor_auth_error', true);
  232. $this->urlGenerator->expects($this->once())
  233. ->method('linkToRoute')
  234. ->with('core.TwoFactorChallenge.showChallenge', [
  235. 'challengeProviderId' => 'myprovider',
  236. 'redirect_url' => '/url',
  237. ])
  238. ->will($this->returnValue('files/index/url'));
  239. $provider->expects($this->once())
  240. ->method('getId')
  241. ->will($this->returnValue('myprovider'));
  242. $expected = new RedirectResponse('files/index/url');
  243. $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token', '/url'));
  244. }
  245. public function testSolveChallengeTwoFactorException() {
  246. $user = $this->createMock(IUser::class);
  247. $provider = $this->createMock(IProvider::class);
  248. $exception = new TwoFactorException("2FA failed");
  249. $this->userSession->expects($this->once())
  250. ->method('getUser')
  251. ->will($this->returnValue($user));
  252. $this->twoFactorManager->expects($this->once())
  253. ->method('getProvider')
  254. ->with($user, 'myprovider')
  255. ->will($this->returnValue($provider));
  256. $this->twoFactorManager->expects($this->once())
  257. ->method('verifyChallenge')
  258. ->with('myprovider', $user, 'token')
  259. ->will($this->throwException($exception));
  260. $this->session->expects($this->at(0))
  261. ->method('set')
  262. ->with('two_factor_auth_error_message', "2FA failed");
  263. $this->session->expects($this->at(1))
  264. ->method('set')
  265. ->with('two_factor_auth_error', true);
  266. $this->urlGenerator->expects($this->once())
  267. ->method('linkToRoute')
  268. ->with('core.TwoFactorChallenge.showChallenge', [
  269. 'challengeProviderId' => 'myprovider',
  270. 'redirect_url' => '/url',
  271. ])
  272. ->will($this->returnValue('files/index/url'));
  273. $provider->expects($this->once())
  274. ->method('getId')
  275. ->will($this->returnValue('myprovider'));
  276. $expected = new RedirectResponse('files/index/url');
  277. $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token', '/url'));
  278. }
  279. }