SecurityMiddlewareTest.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. <?php
  2. /**
  3. * @author Bernhard Posselt <dev@bernhard-posselt.com>
  4. * @author Lukas Reschke <lukas@owncloud.com>
  5. *
  6. * @copyright Copyright (c) 2015, ownCloud, Inc.
  7. * @license AGPL-3.0
  8. *
  9. * This code is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU Affero General Public License, version 3,
  11. * as published by the Free Software Foundation.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Affero General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License, version 3,
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>
  20. *
  21. */
  22. namespace Test\AppFramework\Middleware\Security;
  23. use OC\AppFramework\Http;
  24. use OC\AppFramework\Http\Request;
  25. use OC\AppFramework\Middleware\Security\Exceptions\AppNotEnabledException;
  26. use OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException;
  27. use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException;
  28. use OC\AppFramework\Middleware\Security\Exceptions\NotLoggedInException;
  29. use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
  30. use OC\Appframework\Middleware\Security\Exceptions\StrictCookieMissingException;
  31. use OC\AppFramework\Middleware\Security\SecurityMiddleware;
  32. use OC\AppFramework\Utility\ControllerMethodReflector;
  33. use OC\Security\CSP\ContentSecurityPolicy;
  34. use OC\Security\CSP\ContentSecurityPolicyManager;
  35. use OC\Security\CSP\ContentSecurityPolicyNonceManager;
  36. use OC\Security\CSRF\CsrfToken;
  37. use OC\Security\CSRF\CsrfTokenManager;
  38. use OCP\App\IAppManager;
  39. use OCP\AppFramework\Controller;
  40. use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
  41. use OCP\AppFramework\Http\RedirectResponse;
  42. use OCP\AppFramework\Http\JSONResponse;
  43. use OCP\AppFramework\Http\Response;
  44. use OCP\AppFramework\Http\TemplateResponse;
  45. use OCP\IConfig;
  46. use OCP\IL10N;
  47. use OCP\ILogger;
  48. use OCP\INavigationManager;
  49. use OCP\IRequest;
  50. use OCP\IURLGenerator;
  51. use OCP\Security\ISecureRandom;
  52. class SecurityMiddlewareTest extends \Test\TestCase {
  53. /** @var SecurityMiddleware|\PHPUnit_Framework_MockObject_MockObject */
  54. private $middleware;
  55. /** @var Controller|\PHPUnit_Framework_MockObject_MockObject */
  56. private $controller;
  57. /** @var SecurityException */
  58. private $secException;
  59. /** @var SecurityException */
  60. private $secAjaxException;
  61. /** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */
  62. private $request;
  63. /** @var ControllerMethodReflector */
  64. private $reader;
  65. /** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */
  66. private $logger;
  67. /** @var INavigationManager|\PHPUnit_Framework_MockObject_MockObject */
  68. private $navigationManager;
  69. /** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */
  70. private $urlGenerator;
  71. /** @var ContentSecurityPolicyManager|\PHPUnit_Framework_MockObject_MockObject */
  72. private $contentSecurityPolicyManager;
  73. /** @var CsrfTokenManager|\PHPUnit_Framework_MockObject_MockObject */
  74. private $csrfTokenManager;
  75. /** @var ContentSecurityPolicyNonceManager|\PHPUnit_Framework_MockObject_MockObject */
  76. private $cspNonceManager;
  77. /** @var IAppManager|\PHPUnit_Framework_MockObject_MockObject */
  78. private $appManager;
  79. /** @var IL10N|\PHPUnit_Framework_MockObject_MockObject */
  80. private $l10n;
  81. protected function setUp() {
  82. parent::setUp();
  83. $this->controller = $this->createMock(Controller::class);
  84. $this->reader = new ControllerMethodReflector();
  85. $this->logger = $this->createMock(ILogger::class);
  86. $this->navigationManager = $this->createMock(INavigationManager::class);
  87. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  88. $this->request = $this->createMock(IRequest::class);
  89. $this->contentSecurityPolicyManager = $this->createMock(ContentSecurityPolicyManager::class);
  90. $this->csrfTokenManager = $this->createMock(CsrfTokenManager::class);
  91. $this->cspNonceManager = $this->createMock(ContentSecurityPolicyNonceManager::class);
  92. $this->l10n = $this->createMock(IL10N::class);
  93. $this->middleware = $this->getMiddleware(true, true);
  94. $this->secException = new SecurityException('hey', false);
  95. $this->secAjaxException = new SecurityException('hey', true);
  96. }
  97. private function getMiddleware(bool $isLoggedIn, bool $isAdminUser, bool $isAppEnabledForUser = true): SecurityMiddleware {
  98. $this->appManager = $this->createMock(IAppManager::class);
  99. $this->appManager->expects($this->any())
  100. ->method('isEnabledForUser')
  101. ->willReturn($isAppEnabledForUser);
  102. return new SecurityMiddleware(
  103. $this->request,
  104. $this->reader,
  105. $this->navigationManager,
  106. $this->urlGenerator,
  107. $this->logger,
  108. 'files',
  109. $isLoggedIn,
  110. $isAdminUser,
  111. $this->contentSecurityPolicyManager,
  112. $this->csrfTokenManager,
  113. $this->cspNonceManager,
  114. $this->appManager,
  115. $this->l10n
  116. );
  117. }
  118. /**
  119. * @PublicPage
  120. * @NoCSRFRequired
  121. */
  122. public function testSetNavigationEntry(){
  123. $this->navigationManager->expects($this->once())
  124. ->method('setActiveEntry')
  125. ->with($this->equalTo('files'));
  126. $this->reader->reflect(__CLASS__, __FUNCTION__);
  127. $this->middleware->beforeController($this->controller, __FUNCTION__);
  128. }
  129. /**
  130. * @param string $method
  131. * @param string $test
  132. */
  133. private function ajaxExceptionStatus($method, $test, $status) {
  134. $isLoggedIn = false;
  135. $isAdminUser = false;
  136. // isAdminUser requires isLoggedIn call to return true
  137. if ($test === 'isAdminUser') {
  138. $isLoggedIn = true;
  139. }
  140. $sec = $this->getMiddleware($isLoggedIn, $isAdminUser);
  141. try {
  142. $this->reader->reflect(__CLASS__, $method);
  143. $sec->beforeController($this->controller, $method);
  144. } catch (SecurityException $ex){
  145. $this->assertEquals($status, $ex->getCode());
  146. }
  147. // add assertion if everything should work fine otherwise phpunit will
  148. // complain
  149. if ($status === 0) {
  150. $this->addToAssertionCount(1);
  151. }
  152. }
  153. public function testAjaxStatusLoggedInCheck() {
  154. $this->ajaxExceptionStatus(
  155. __FUNCTION__,
  156. 'isLoggedIn',
  157. Http::STATUS_UNAUTHORIZED
  158. );
  159. }
  160. /**
  161. * @NoCSRFRequired
  162. */
  163. public function testAjaxNotAdminCheck() {
  164. $this->ajaxExceptionStatus(
  165. __FUNCTION__,
  166. 'isAdminUser',
  167. Http::STATUS_FORBIDDEN
  168. );
  169. }
  170. /**
  171. * @PublicPage
  172. */
  173. public function testAjaxStatusCSRFCheck() {
  174. $this->ajaxExceptionStatus(
  175. __FUNCTION__,
  176. 'passesCSRFCheck',
  177. Http::STATUS_PRECONDITION_FAILED
  178. );
  179. }
  180. /**
  181. * @PublicPage
  182. * @NoCSRFRequired
  183. */
  184. public function testAjaxStatusAllGood() {
  185. $this->ajaxExceptionStatus(
  186. __FUNCTION__,
  187. 'isLoggedIn',
  188. 0
  189. );
  190. $this->ajaxExceptionStatus(
  191. __FUNCTION__,
  192. 'isAdminUser',
  193. 0
  194. );
  195. $this->ajaxExceptionStatus(
  196. __FUNCTION__,
  197. 'isSubAdminUser',
  198. 0
  199. );
  200. $this->ajaxExceptionStatus(
  201. __FUNCTION__,
  202. 'passesCSRFCheck',
  203. 0
  204. );
  205. }
  206. /**
  207. * @PublicPage
  208. * @NoCSRFRequired
  209. */
  210. public function testNoChecks(){
  211. $this->request->expects($this->never())
  212. ->method('passesCSRFCheck')
  213. ->will($this->returnValue(false));
  214. $sec = $this->getMiddleware(false, false);
  215. $this->reader->reflect(__CLASS__, __FUNCTION__);
  216. $sec->beforeController($this->controller, __FUNCTION__);
  217. }
  218. /**
  219. * @param string $method
  220. * @param string $expects
  221. */
  222. private function securityCheck($method, $expects, $shouldFail=false){
  223. // admin check requires login
  224. if ($expects === 'isAdminUser') {
  225. $isLoggedIn = true;
  226. $isAdminUser = !$shouldFail;
  227. } else {
  228. $isLoggedIn = !$shouldFail;
  229. $isAdminUser = false;
  230. }
  231. $sec = $this->getMiddleware($isLoggedIn, $isAdminUser);
  232. if($shouldFail) {
  233. $this->expectException(SecurityException::class);
  234. } else {
  235. $this->addToAssertionCount(1);
  236. }
  237. $this->reader->reflect(__CLASS__, $method);
  238. $sec->beforeController($this->controller, $method);
  239. }
  240. /**
  241. * @PublicPage
  242. * @expectedException \OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException
  243. */
  244. public function testCsrfCheck(){
  245. $this->request->expects($this->once())
  246. ->method('passesCSRFCheck')
  247. ->will($this->returnValue(false));
  248. $this->request->expects($this->once())
  249. ->method('passesStrictCookieCheck')
  250. ->will($this->returnValue(true));
  251. $this->reader->reflect(__CLASS__, __FUNCTION__);
  252. $this->middleware->beforeController($this->controller, __FUNCTION__);
  253. }
  254. /**
  255. * @PublicPage
  256. * @NoCSRFRequired
  257. */
  258. public function testNoCsrfCheck(){
  259. $this->request->expects($this->never())
  260. ->method('passesCSRFCheck')
  261. ->will($this->returnValue(false));
  262. $this->reader->reflect(__CLASS__, __FUNCTION__);
  263. $this->middleware->beforeController($this->controller, __FUNCTION__);
  264. }
  265. /**
  266. * @PublicPage
  267. */
  268. public function testPassesCsrfCheck(){
  269. $this->request->expects($this->once())
  270. ->method('passesCSRFCheck')
  271. ->will($this->returnValue(true));
  272. $this->request->expects($this->once())
  273. ->method('passesStrictCookieCheck')
  274. ->will($this->returnValue(true));
  275. $this->reader->reflect(__CLASS__, __FUNCTION__);
  276. $this->middleware->beforeController($this->controller, __FUNCTION__);
  277. }
  278. /**
  279. * @PublicPage
  280. * @expectedException \OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException
  281. */
  282. public function testFailCsrfCheck(){
  283. $this->request->expects($this->once())
  284. ->method('passesCSRFCheck')
  285. ->will($this->returnValue(false));
  286. $this->request->expects($this->once())
  287. ->method('passesStrictCookieCheck')
  288. ->will($this->returnValue(true));
  289. $this->reader->reflect(__CLASS__, __FUNCTION__);
  290. $this->middleware->beforeController($this->controller, __FUNCTION__);
  291. }
  292. /**
  293. * @PublicPage
  294. * @StrictCookieRequired
  295. * @expectedException \OC\Appframework\Middleware\Security\Exceptions\StrictCookieMissingException
  296. */
  297. public function testStrictCookieRequiredCheck() {
  298. $this->request->expects($this->never())
  299. ->method('passesCSRFCheck');
  300. $this->request->expects($this->once())
  301. ->method('passesStrictCookieCheck')
  302. ->will($this->returnValue(false));
  303. $this->reader->reflect(__CLASS__, __FUNCTION__);
  304. $this->middleware->beforeController($this->controller, __FUNCTION__);
  305. }
  306. /**
  307. * @PublicPage
  308. * @NoCSRFRequired
  309. */
  310. public function testNoStrictCookieRequiredCheck() {
  311. $this->request->expects($this->never())
  312. ->method('passesStrictCookieCheck')
  313. ->will($this->returnValue(false));
  314. $this->reader->reflect(__CLASS__, __FUNCTION__);
  315. $this->middleware->beforeController($this->controller, __FUNCTION__);
  316. }
  317. /**
  318. * @PublicPage
  319. * @NoCSRFRequired
  320. * @StrictCookieRequired
  321. */
  322. public function testPassesStrictCookieRequiredCheck() {
  323. $this->request
  324. ->expects($this->once())
  325. ->method('passesStrictCookieCheck')
  326. ->willReturn(true);
  327. $this->reader->reflect(__CLASS__, __FUNCTION__);
  328. $this->middleware->beforeController($this->controller, __FUNCTION__);
  329. }
  330. public function dataCsrfOcsController() {
  331. $controller = $this->getMockBuilder('OCP\AppFramework\Controller')
  332. ->disableOriginalConstructor()
  333. ->getMock();
  334. $ocsController = $this->getMockBuilder('OCP\AppFramework\OCSController')
  335. ->disableOriginalConstructor()
  336. ->getMock();
  337. return [
  338. [$controller, false, false, true],
  339. [$controller, false, true, true],
  340. [$controller, true, false, true],
  341. [$controller, true, true, true],
  342. [$ocsController, false, false, true],
  343. [$ocsController, false, true, false],
  344. [$ocsController, true, false, false],
  345. [$ocsController, true, true, false],
  346. ];
  347. }
  348. /**
  349. * @dataProvider dataCsrfOcsController
  350. * @param Controller $controller
  351. * @param bool $hasOcsApiHeader
  352. * @param bool $hasBearerAuth
  353. * @param bool $exception
  354. */
  355. public function testCsrfOcsController(Controller $controller, bool $hasOcsApiHeader, bool $hasBearerAuth, bool $exception) {
  356. $this->request
  357. ->method('getHeader')
  358. ->will(self::returnCallback(function ($header) use ($hasOcsApiHeader, $hasBearerAuth) {
  359. if ($header === 'OCS-APIREQUEST' && $hasOcsApiHeader) {
  360. return 'true';
  361. }
  362. if ($header === 'Authorization' && $hasBearerAuth) {
  363. return 'Bearer TOKEN!';
  364. }
  365. return '';
  366. }));
  367. $this->request->expects($this->once())
  368. ->method('passesStrictCookieCheck')
  369. ->willReturn(true);
  370. try {
  371. $this->middleware->beforeController($controller, 'foo');
  372. $this->assertFalse($exception);
  373. } catch (CrossSiteRequestForgeryException $e) {
  374. $this->assertTrue($exception);
  375. }
  376. }
  377. /**
  378. * @NoCSRFRequired
  379. * @NoAdminRequired
  380. */
  381. public function testLoggedInCheck(){
  382. $this->securityCheck(__FUNCTION__, 'isLoggedIn');
  383. }
  384. /**
  385. * @NoCSRFRequired
  386. * @NoAdminRequired
  387. */
  388. public function testFailLoggedInCheck(){
  389. $this->securityCheck(__FUNCTION__, 'isLoggedIn', true);
  390. }
  391. /**
  392. * @NoCSRFRequired
  393. */
  394. public function testIsAdminCheck(){
  395. $this->securityCheck(__FUNCTION__, 'isAdminUser');
  396. }
  397. /**
  398. * @NoCSRFRequired
  399. */
  400. public function testFailIsAdminCheck(){
  401. $this->securityCheck(__FUNCTION__, 'isAdminUser', true);
  402. }
  403. public function testAfterExceptionNotCaughtThrowsItAgain(){
  404. $ex = new \Exception();
  405. $this->expectException(\Exception::class);
  406. $this->middleware->afterException($this->controller, 'test', $ex);
  407. }
  408. public function testAfterExceptionReturnsRedirectForNotLoggedInUser() {
  409. $this->request = new Request(
  410. [
  411. 'server' =>
  412. [
  413. 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  414. 'REQUEST_URI' => 'nextcloud/index.php/apps/specialapp'
  415. ]
  416. ],
  417. $this->createMock(ISecureRandom::class),
  418. $this->createMock(IConfig::class)
  419. );
  420. $this->middleware = $this->getMiddleware(false, false);
  421. $this->urlGenerator
  422. ->expects($this->once())
  423. ->method('linkToRoute')
  424. ->with(
  425. 'core.login.showLoginForm',
  426. [
  427. 'redirect_url' => 'nextcloud/index.php/apps/specialapp',
  428. ]
  429. )
  430. ->will($this->returnValue('http://localhost/nextcloud/index.php/login?redirect_url=nextcloud/index.php/apps/specialapp'));
  431. $this->logger
  432. ->expects($this->once())
  433. ->method('logException');
  434. $response = $this->middleware->afterException(
  435. $this->controller,
  436. 'test',
  437. new NotLoggedInException()
  438. );
  439. $expected = new RedirectResponse('http://localhost/nextcloud/index.php/login?redirect_url=nextcloud/index.php/apps/specialapp');
  440. $this->assertEquals($expected , $response);
  441. }
  442. public function testAfterExceptionRedirectsToWebRootAfterStrictCookieFail() {
  443. $this->request = new Request(
  444. [
  445. 'server' => [
  446. 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  447. 'REQUEST_URI' => 'nextcloud/index.php/apps/specialapp',
  448. ],
  449. ],
  450. $this->createMock(ISecureRandom::class),
  451. $this->createMock(IConfig::class)
  452. );
  453. $this->middleware = $this->getMiddleware(false, false);
  454. $response = $this->middleware->afterException(
  455. $this->controller,
  456. 'test',
  457. new StrictCookieMissingException()
  458. );
  459. $expected = new RedirectResponse(\OC::$WEBROOT);
  460. $this->assertEquals($expected , $response);
  461. }
  462. /**
  463. * @return array
  464. */
  465. public function exceptionProvider() {
  466. return [
  467. [
  468. new AppNotEnabledException(),
  469. ],
  470. [
  471. new CrossSiteRequestForgeryException(),
  472. ],
  473. [
  474. new NotAdminException(''),
  475. ],
  476. ];
  477. }
  478. /**
  479. * @dataProvider exceptionProvider
  480. * @param SecurityException $exception
  481. */
  482. public function testAfterExceptionReturnsTemplateResponse(SecurityException $exception) {
  483. $this->request = new Request(
  484. [
  485. 'server' =>
  486. [
  487. 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  488. 'REQUEST_URI' => 'nextcloud/index.php/apps/specialapp'
  489. ]
  490. ],
  491. $this->createMock(ISecureRandom::class),
  492. $this->createMock(IConfig::class)
  493. );
  494. $this->middleware = $this->getMiddleware(false, false);
  495. $this->logger
  496. ->expects($this->once())
  497. ->method('logException');
  498. $response = $this->middleware->afterException(
  499. $this->controller,
  500. 'test',
  501. $exception
  502. );
  503. $expected = new TemplateResponse('core', '403', ['message' => $exception->getMessage()], 'guest');
  504. $expected->setStatus($exception->getCode());
  505. $this->assertEquals($expected , $response);
  506. }
  507. public function testAfterAjaxExceptionReturnsJSONError(){
  508. $response = $this->middleware->afterException($this->controller, 'test',
  509. $this->secAjaxException);
  510. $this->assertTrue($response instanceof JSONResponse);
  511. }
  512. public function testAfterController() {
  513. $this->cspNonceManager
  514. ->expects($this->once())
  515. ->method('browserSupportsCspV3')
  516. ->willReturn(false);
  517. $response = $this->createMock(Response::class);
  518. $defaultPolicy = new ContentSecurityPolicy();
  519. $defaultPolicy->addAllowedImageDomain('defaultpolicy');
  520. $currentPolicy = new ContentSecurityPolicy();
  521. $currentPolicy->addAllowedConnectDomain('currentPolicy');
  522. $mergedPolicy = new ContentSecurityPolicy();
  523. $mergedPolicy->addAllowedMediaDomain('mergedPolicy');
  524. $response
  525. ->expects($this->exactly(2))
  526. ->method('getContentSecurityPolicy')
  527. ->willReturn($currentPolicy);
  528. $this->contentSecurityPolicyManager
  529. ->expects($this->once())
  530. ->method('getDefaultPolicy')
  531. ->willReturn($defaultPolicy);
  532. $this->contentSecurityPolicyManager
  533. ->expects($this->once())
  534. ->method('mergePolicies')
  535. ->with($defaultPolicy, $currentPolicy)
  536. ->willReturn($mergedPolicy);
  537. $response->expects($this->once())
  538. ->method('setContentSecurityPolicy')
  539. ->with($mergedPolicy);
  540. $this->middleware->afterController($this->controller, 'test', $response);
  541. }
  542. public function testAfterControllerEmptyCSP() {
  543. $response = $this->createMock(Response::class);
  544. $emptyPolicy = new EmptyContentSecurityPolicy();
  545. $response->expects($this->any())
  546. ->method('getContentSecurityPolicy')
  547. ->willReturn($emptyPolicy);
  548. $response->expects($this->never())
  549. ->method('setContentSecurityPolicy');
  550. $this->middleware->afterController($this->controller, 'test', $response);
  551. }
  552. public function testAfterControllerWithContentSecurityPolicy3Support() {
  553. $this->cspNonceManager
  554. ->expects($this->once())
  555. ->method('browserSupportsCspV3')
  556. ->willReturn(true);
  557. $token = $this->createMock(CsrfToken::class);
  558. $token
  559. ->expects($this->once())
  560. ->method('getEncryptedValue')
  561. ->willReturn('MyEncryptedToken');
  562. $this->csrfTokenManager
  563. ->expects($this->once())
  564. ->method('getToken')
  565. ->willReturn($token);
  566. $response = $this->createMock(Response::class);
  567. $defaultPolicy = new ContentSecurityPolicy();
  568. $defaultPolicy->addAllowedImageDomain('defaultpolicy');
  569. $currentPolicy = new ContentSecurityPolicy();
  570. $currentPolicy->addAllowedConnectDomain('currentPolicy');
  571. $mergedPolicy = new ContentSecurityPolicy();
  572. $mergedPolicy->addAllowedMediaDomain('mergedPolicy');
  573. $response
  574. ->expects($this->exactly(2))
  575. ->method('getContentSecurityPolicy')
  576. ->willReturn($currentPolicy);
  577. $this->contentSecurityPolicyManager
  578. ->expects($this->once())
  579. ->method('getDefaultPolicy')
  580. ->willReturn($defaultPolicy);
  581. $this->contentSecurityPolicyManager
  582. ->expects($this->once())
  583. ->method('mergePolicies')
  584. ->with($defaultPolicy, $currentPolicy)
  585. ->willReturn($mergedPolicy);
  586. $response->expects($this->once())
  587. ->method('setContentSecurityPolicy')
  588. ->with($mergedPolicy);
  589. $this->assertEquals($response, $this->middleware->afterController($this->controller, 'test', $response));
  590. }
  591. public function dataRestrictedApp() {
  592. return [
  593. [false, false, false,],
  594. [false, false, true,],
  595. [false, true, false,],
  596. [false, true, true,],
  597. [ true, false, false,],
  598. [ true, false, true,],
  599. [ true, true, false,],
  600. [ true, true, true,],
  601. ];
  602. }
  603. /**
  604. * @PublicPage
  605. * @NoAdminRequired
  606. * @NoCSRFRequired
  607. */
  608. public function testRestrictedAppLoggedInPublicPage() {
  609. $middleware = $this->getMiddleware(true, false);
  610. $this->reader->reflect(__CLASS__,__FUNCTION__);
  611. $this->appManager->method('getAppPath')
  612. ->with('files')
  613. ->willReturn('foo');
  614. $this->appManager->method('isEnabledForUser')
  615. ->with('files')
  616. ->willReturn(false);
  617. $middleware->beforeController($this->controller, __FUNCTION__);
  618. $this->addToAssertionCount(1);
  619. }
  620. /**
  621. * @PublicPage
  622. * @NoAdminRequired
  623. * @NoCSRFRequired
  624. */
  625. public function testRestrictedAppNotLoggedInPublicPage() {
  626. $middleware = $this->getMiddleware(false, false);
  627. $this->reader->reflect(__CLASS__,__FUNCTION__);
  628. $this->appManager->method('getAppPath')
  629. ->with('files')
  630. ->willReturn('foo');
  631. $this->appManager->method('isEnabledForUser')
  632. ->with('files')
  633. ->willReturn(false);
  634. $middleware->beforeController($this->controller, __FUNCTION__);
  635. $this->addToAssertionCount(1);
  636. }
  637. /**
  638. * @NoAdminRequired
  639. * @NoCSRFRequired
  640. */
  641. public function testRestrictedAppLoggedIn() {
  642. $middleware = $this->getMiddleware(true, false, false);
  643. $this->reader->reflect(__CLASS__,__FUNCTION__);
  644. $this->appManager->method('getAppPath')
  645. ->with('files')
  646. ->willReturn('foo');
  647. $this->expectException(AppNotEnabledException::class);
  648. $middleware->beforeController($this->controller, __FUNCTION__);
  649. }
  650. }