You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SecurityMiddlewareTest.php 18KB

hace 7 años
hace 7 años
hace 7 años
hace 7 años
Add public API to give developers the possibility to adjust the global CSP defaults Allows to inject something into the default content policy. This is for example useful when you're injecting Javascript code into a view belonging to another controller and cannot modify its Content-Security-Policy itself. Note that the adjustment is only applied to applications that use AppFramework controllers. To use this from your `app.php` use `\OC::$server->getContentSecurityPolicyManager()->addDefaultPolicy($policy)`, $policy has to be of type `\OCP\AppFramework\Http\ContentSecurityPolicy`. To test this add something like the following into an `app.php` of any enabled app: ``` $manager = \OC::$server->getContentSecurityPolicyManager(); $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy(false); $policy->addAllowedFrameDomain('asdf'); $policy->addAllowedScriptDomain('yolo.com'); $policy->allowInlineScript(false); $manager->addDefaultPolicy($policy); $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy(false); $policy->addAllowedFontDomain('yolo.com'); $manager->addDefaultPolicy($policy); $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy(false); $policy->addAllowedFrameDomain('banana.com'); $manager->addDefaultPolicy($policy); ``` If you now open the files app the policy should be: ``` Content-Security-Policy:default-src 'none';script-src yolo.com 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src yolo.com 'self';connect-src 'self';media-src 'self';frame-src asdf banana.com 'self' ```
hace 8 años
hace 10 años
hace 10 años
hace 10 años
hace 10 años
hace 10 años
hace 10 años
hace 10 años
hace 10 años
hace 7 años
hace 7 años
hace 7 años
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  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\Settings\AuthorizedGroupMapper;
  34. use OCP\App\IAppManager;
  35. use OCP\AppFramework\Controller;
  36. use OCP\AppFramework\Http\JSONResponse;
  37. use OCP\AppFramework\Http\RedirectResponse;
  38. use OCP\AppFramework\Http\TemplateResponse;
  39. use OCP\IConfig;
  40. use OCP\IL10N;
  41. use OCP\INavigationManager;
  42. use OCP\IRequest;
  43. use OCP\IURLGenerator;
  44. use OCP\IUserSession;
  45. use OCP\Security\ISecureRandom;
  46. use Psr\Log\LoggerInterface;
  47. class SecurityMiddlewareTest extends \Test\TestCase {
  48. /** @var SecurityMiddleware|\PHPUnit\Framework\MockObject\MockObject */
  49. private $middleware;
  50. /** @var Controller|\PHPUnit\Framework\MockObject\MockObject */
  51. private $controller;
  52. /** @var SecurityException */
  53. private $secException;
  54. /** @var SecurityException */
  55. private $secAjaxException;
  56. /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */
  57. private $request;
  58. /** @var ControllerMethodReflector */
  59. private $reader;
  60. /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */
  61. private $logger;
  62. /** @var INavigationManager|\PHPUnit\Framework\MockObject\MockObject */
  63. private $navigationManager;
  64. /** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */
  65. private $urlGenerator;
  66. /** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject */
  67. private $appManager;
  68. /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */
  69. private $l10n;
  70. /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
  71. private $userSession;
  72. /** @var AuthorizedGroupMapper|\PHPUnit\Framework\MockObject\MockObject */
  73. private $authorizedGroupMapper;
  74. protected function setUp(): void {
  75. parent::setUp();
  76. $this->authorizedGroupMapper = $this->createMock(AuthorizedGroupMapper::class);
  77. $this->userSession = $this->createMock(IUserSession::class);
  78. $this->controller = $this->createMock(Controller::class);
  79. $this->reader = new ControllerMethodReflector();
  80. $this->logger = $this->createMock(LoggerInterface::class);
  81. $this->navigationManager = $this->createMock(INavigationManager::class);
  82. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  83. $this->request = $this->createMock(IRequest::class);
  84. $this->l10n = $this->createMock(IL10N::class);
  85. $this->middleware = $this->getMiddleware(true, true, false);
  86. $this->secException = new SecurityException('hey', false);
  87. $this->secAjaxException = new SecurityException('hey', true);
  88. }
  89. private function getMiddleware(bool $isLoggedIn, bool $isAdminUser, bool $isSubAdmin, bool $isAppEnabledForUser = true): SecurityMiddleware {
  90. $this->appManager = $this->createMock(IAppManager::class);
  91. $this->appManager->expects($this->any())
  92. ->method('isEnabledForUser')
  93. ->willReturn($isAppEnabledForUser);
  94. return new SecurityMiddleware(
  95. $this->request,
  96. $this->reader,
  97. $this->navigationManager,
  98. $this->urlGenerator,
  99. $this->logger,
  100. 'files',
  101. $isLoggedIn,
  102. $isAdminUser,
  103. $isSubAdmin,
  104. $this->appManager,
  105. $this->l10n,
  106. $this->authorizedGroupMapper,
  107. $this->userSession
  108. );
  109. }
  110. /**
  111. * @PublicPage
  112. * @NoCSRFRequired
  113. */
  114. public function testSetNavigationEntry() {
  115. $this->navigationManager->expects($this->once())
  116. ->method('setActiveEntry')
  117. ->with($this->equalTo('files'));
  118. $this->reader->reflect(__CLASS__, __FUNCTION__);
  119. $this->middleware->beforeController($this->controller, __FUNCTION__);
  120. }
  121. /**
  122. * @param string $method
  123. * @param string $test
  124. */
  125. private function ajaxExceptionStatus($method, $test, $status) {
  126. $isLoggedIn = false;
  127. $isAdminUser = false;
  128. // isAdminUser requires isLoggedIn call to return true
  129. if ($test === 'isAdminUser') {
  130. $isLoggedIn = true;
  131. }
  132. $sec = $this->getMiddleware($isLoggedIn, $isAdminUser, false);
  133. try {
  134. $this->reader->reflect(__CLASS__, $method);
  135. $sec->beforeController($this->controller, $method);
  136. } catch (SecurityException $ex) {
  137. $this->assertEquals($status, $ex->getCode());
  138. }
  139. // add assertion if everything should work fine otherwise phpunit will
  140. // complain
  141. if ($status === 0) {
  142. $this->addToAssertionCount(1);
  143. }
  144. }
  145. public function testAjaxStatusLoggedInCheck() {
  146. $this->ajaxExceptionStatus(
  147. __FUNCTION__,
  148. 'isLoggedIn',
  149. Http::STATUS_UNAUTHORIZED
  150. );
  151. }
  152. /**
  153. * @NoCSRFRequired
  154. */
  155. public function testAjaxNotAdminCheck() {
  156. $this->ajaxExceptionStatus(
  157. __FUNCTION__,
  158. 'isAdminUser',
  159. Http::STATUS_FORBIDDEN
  160. );
  161. }
  162. /**
  163. * @PublicPage
  164. */
  165. public function testAjaxStatusCSRFCheck() {
  166. $this->ajaxExceptionStatus(
  167. __FUNCTION__,
  168. 'passesCSRFCheck',
  169. Http::STATUS_PRECONDITION_FAILED
  170. );
  171. }
  172. /**
  173. * @PublicPage
  174. * @NoCSRFRequired
  175. */
  176. public function testAjaxStatusAllGood() {
  177. $this->ajaxExceptionStatus(
  178. __FUNCTION__,
  179. 'isLoggedIn',
  180. 0
  181. );
  182. $this->ajaxExceptionStatus(
  183. __FUNCTION__,
  184. 'isAdminUser',
  185. 0
  186. );
  187. $this->ajaxExceptionStatus(
  188. __FUNCTION__,
  189. 'passesCSRFCheck',
  190. 0
  191. );
  192. }
  193. /**
  194. * @PublicPage
  195. * @NoCSRFRequired
  196. */
  197. public function testNoChecks() {
  198. $this->request->expects($this->never())
  199. ->method('passesCSRFCheck')
  200. ->willReturn(false);
  201. $sec = $this->getMiddleware(false, false, false);
  202. $this->reader->reflect(__CLASS__, __FUNCTION__);
  203. $sec->beforeController($this->controller, __FUNCTION__);
  204. }
  205. /**
  206. * @param string $method
  207. * @param string $expects
  208. */
  209. private function securityCheck($method, $expects, $shouldFail = false) {
  210. // admin check requires login
  211. if ($expects === 'isAdminUser') {
  212. $isLoggedIn = true;
  213. $isAdminUser = !$shouldFail;
  214. } else {
  215. $isLoggedIn = !$shouldFail;
  216. $isAdminUser = false;
  217. }
  218. $sec = $this->getMiddleware($isLoggedIn, $isAdminUser, false);
  219. if ($shouldFail) {
  220. $this->expectException(SecurityException::class);
  221. } else {
  222. $this->addToAssertionCount(1);
  223. }
  224. $this->reader->reflect(__CLASS__, $method);
  225. $sec->beforeController($this->controller, $method);
  226. }
  227. /**
  228. * @PublicPage
  229. */
  230. public function testCsrfCheck() {
  231. $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException::class);
  232. $this->request->expects($this->once())
  233. ->method('passesCSRFCheck')
  234. ->willReturn(false);
  235. $this->request->expects($this->once())
  236. ->method('passesStrictCookieCheck')
  237. ->willReturn(true);
  238. $this->reader->reflect(__CLASS__, __FUNCTION__);
  239. $this->middleware->beforeController($this->controller, __FUNCTION__);
  240. }
  241. /**
  242. * @PublicPage
  243. * @NoCSRFRequired
  244. */
  245. public function testNoCsrfCheck() {
  246. $this->request->expects($this->never())
  247. ->method('passesCSRFCheck')
  248. ->willReturn(false);
  249. $this->reader->reflect(__CLASS__, __FUNCTION__);
  250. $this->middleware->beforeController($this->controller, __FUNCTION__);
  251. }
  252. /**
  253. * @PublicPage
  254. */
  255. public function testPassesCsrfCheck() {
  256. $this->request->expects($this->once())
  257. ->method('passesCSRFCheck')
  258. ->willReturn(true);
  259. $this->request->expects($this->once())
  260. ->method('passesStrictCookieCheck')
  261. ->willReturn(true);
  262. $this->reader->reflect(__CLASS__, __FUNCTION__);
  263. $this->middleware->beforeController($this->controller, __FUNCTION__);
  264. }
  265. /**
  266. * @PublicPage
  267. */
  268. public function testFailCsrfCheck() {
  269. $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException::class);
  270. $this->request->expects($this->once())
  271. ->method('passesCSRFCheck')
  272. ->willReturn(false);
  273. $this->request->expects($this->once())
  274. ->method('passesStrictCookieCheck')
  275. ->willReturn(true);
  276. $this->reader->reflect(__CLASS__, __FUNCTION__);
  277. $this->middleware->beforeController($this->controller, __FUNCTION__);
  278. }
  279. /**
  280. * @PublicPage
  281. * @StrictCookieRequired
  282. */
  283. public function testStrictCookieRequiredCheck() {
  284. $this->expectException(\OC\Appframework\Middleware\Security\Exceptions\StrictCookieMissingException::class);
  285. $this->request->expects($this->never())
  286. ->method('passesCSRFCheck');
  287. $this->request->expects($this->once())
  288. ->method('passesStrictCookieCheck')
  289. ->willReturn(false);
  290. $this->reader->reflect(__CLASS__, __FUNCTION__);
  291. $this->middleware->beforeController($this->controller, __FUNCTION__);
  292. }
  293. /**
  294. * @PublicPage
  295. * @NoCSRFRequired
  296. */
  297. public function testNoStrictCookieRequiredCheck() {
  298. $this->request->expects($this->never())
  299. ->method('passesStrictCookieCheck')
  300. ->willReturn(false);
  301. $this->reader->reflect(__CLASS__, __FUNCTION__);
  302. $this->middleware->beforeController($this->controller, __FUNCTION__);
  303. }
  304. /**
  305. * @PublicPage
  306. * @NoCSRFRequired
  307. * @StrictCookieRequired
  308. */
  309. public function testPassesStrictCookieRequiredCheck() {
  310. $this->request
  311. ->expects($this->once())
  312. ->method('passesStrictCookieCheck')
  313. ->willReturn(true);
  314. $this->reader->reflect(__CLASS__, __FUNCTION__);
  315. $this->middleware->beforeController($this->controller, __FUNCTION__);
  316. }
  317. public function dataCsrfOcsController() {
  318. $controller = $this->getMockBuilder('OCP\AppFramework\Controller')
  319. ->disableOriginalConstructor()
  320. ->getMock();
  321. $ocsController = $this->getMockBuilder('OCP\AppFramework\OCSController')
  322. ->disableOriginalConstructor()
  323. ->getMock();
  324. return [
  325. [$controller, false, false, true],
  326. [$controller, false, true, true],
  327. [$controller, true, false, true],
  328. [$controller, true, true, true],
  329. [$ocsController, false, false, true],
  330. [$ocsController, false, true, false],
  331. [$ocsController, true, false, false],
  332. [$ocsController, true, true, false],
  333. ];
  334. }
  335. /**
  336. * @dataProvider dataCsrfOcsController
  337. * @param Controller $controller
  338. * @param bool $hasOcsApiHeader
  339. * @param bool $hasBearerAuth
  340. * @param bool $exception
  341. */
  342. public function testCsrfOcsController(Controller $controller, bool $hasOcsApiHeader, bool $hasBearerAuth, bool $exception) {
  343. $this->request
  344. ->method('getHeader')
  345. ->willReturnCallback(function ($header) use ($hasOcsApiHeader, $hasBearerAuth) {
  346. if ($header === 'OCS-APIREQUEST' && $hasOcsApiHeader) {
  347. return 'true';
  348. }
  349. if ($header === 'Authorization' && $hasBearerAuth) {
  350. return 'Bearer TOKEN!';
  351. }
  352. return '';
  353. });
  354. $this->request->expects($this->once())
  355. ->method('passesStrictCookieCheck')
  356. ->willReturn(true);
  357. try {
  358. $this->middleware->beforeController($controller, 'foo');
  359. $this->assertFalse($exception);
  360. } catch (CrossSiteRequestForgeryException $e) {
  361. $this->assertTrue($exception);
  362. }
  363. }
  364. /**
  365. * @NoCSRFRequired
  366. * @NoAdminRequired
  367. */
  368. public function testLoggedInCheck() {
  369. $this->securityCheck(__FUNCTION__, 'isLoggedIn');
  370. }
  371. /**
  372. * @NoCSRFRequired
  373. * @NoAdminRequired
  374. */
  375. public function testFailLoggedInCheck() {
  376. $this->securityCheck(__FUNCTION__, 'isLoggedIn', true);
  377. }
  378. /**
  379. * @NoCSRFRequired
  380. */
  381. public function testIsAdminCheck() {
  382. $this->securityCheck(__FUNCTION__, 'isAdminUser');
  383. }
  384. /**
  385. * @NoCSRFRequired
  386. * @SubAdminRequired
  387. */
  388. public function testIsNotSubAdminCheck() {
  389. $this->reader->reflect(__CLASS__, __FUNCTION__);
  390. $sec = $this->getMiddleware(true, false, false);
  391. $this->expectException(SecurityException::class);
  392. $sec->beforeController($this, __METHOD__);
  393. }
  394. /**
  395. * @NoCSRFRequired
  396. * @SubAdminRequired
  397. */
  398. public function testIsSubAdminCheck() {
  399. $this->reader->reflect(__CLASS__, __FUNCTION__);
  400. $sec = $this->getMiddleware(true, false, true);
  401. $sec->beforeController($this, __METHOD__);
  402. $this->addToAssertionCount(1);
  403. }
  404. /**
  405. * @NoCSRFRequired
  406. * @SubAdminRequired
  407. */
  408. public function testIsSubAdminAndAdminCheck() {
  409. $this->reader->reflect(__CLASS__, __FUNCTION__);
  410. $sec = $this->getMiddleware(true, true, true);
  411. $sec->beforeController($this, __METHOD__);
  412. $this->addToAssertionCount(1);
  413. }
  414. /**
  415. * @NoCSRFRequired
  416. */
  417. public function testFailIsAdminCheck() {
  418. $this->securityCheck(__FUNCTION__, 'isAdminUser', true);
  419. }
  420. public function testAfterExceptionNotCaughtThrowsItAgain() {
  421. $ex = new \Exception();
  422. $this->expectException(\Exception::class);
  423. $this->middleware->afterException($this->controller, 'test', $ex);
  424. }
  425. public function testAfterExceptionReturnsRedirectForNotLoggedInUser() {
  426. $this->request = new Request(
  427. [
  428. 'server' =>
  429. [
  430. 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  431. 'REQUEST_URI' => 'nextcloud/index.php/apps/specialapp'
  432. ]
  433. ],
  434. $this->createMock(ISecureRandom::class),
  435. $this->createMock(IConfig::class)
  436. );
  437. $this->middleware = $this->getMiddleware(false, false, false);
  438. $this->urlGenerator
  439. ->expects($this->once())
  440. ->method('linkToRoute')
  441. ->with(
  442. 'core.login.showLoginForm',
  443. [
  444. 'redirect_url' => 'nextcloud/index.php/apps/specialapp',
  445. ]
  446. )
  447. ->willReturn('http://localhost/nextcloud/index.php/login?redirect_url=nextcloud/index.php/apps/specialapp');
  448. $this->logger
  449. ->expects($this->once())
  450. ->method('debug');
  451. $response = $this->middleware->afterException(
  452. $this->controller,
  453. 'test',
  454. new NotLoggedInException()
  455. );
  456. $expected = new RedirectResponse('http://localhost/nextcloud/index.php/login?redirect_url=nextcloud/index.php/apps/specialapp');
  457. $this->assertEquals($expected, $response);
  458. }
  459. public function testAfterExceptionRedirectsToWebRootAfterStrictCookieFail() {
  460. $this->request = new Request(
  461. [
  462. 'server' => [
  463. 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  464. 'REQUEST_URI' => 'nextcloud/index.php/apps/specialapp',
  465. ],
  466. ],
  467. $this->createMock(ISecureRandom::class),
  468. $this->createMock(IConfig::class)
  469. );
  470. $this->middleware = $this->getMiddleware(false, false, false);
  471. $response = $this->middleware->afterException(
  472. $this->controller,
  473. 'test',
  474. new StrictCookieMissingException()
  475. );
  476. $expected = new RedirectResponse(\OC::$WEBROOT . '/');
  477. $this->assertEquals($expected, $response);
  478. }
  479. /**
  480. * @return array
  481. */
  482. public function exceptionProvider() {
  483. return [
  484. [
  485. new AppNotEnabledException(),
  486. ],
  487. [
  488. new CrossSiteRequestForgeryException(),
  489. ],
  490. [
  491. new NotAdminException(''),
  492. ],
  493. ];
  494. }
  495. /**
  496. * @dataProvider exceptionProvider
  497. * @param SecurityException $exception
  498. */
  499. public function testAfterExceptionReturnsTemplateResponse(SecurityException $exception) {
  500. $this->request = new Request(
  501. [
  502. 'server' =>
  503. [
  504. 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  505. 'REQUEST_URI' => 'nextcloud/index.php/apps/specialapp'
  506. ]
  507. ],
  508. $this->createMock(ISecureRandom::class),
  509. $this->createMock(IConfig::class)
  510. );
  511. $this->middleware = $this->getMiddleware(false, false, false);
  512. $this->logger
  513. ->expects($this->once())
  514. ->method('debug');
  515. $response = $this->middleware->afterException(
  516. $this->controller,
  517. 'test',
  518. $exception
  519. );
  520. $expected = new TemplateResponse('core', '403', ['message' => $exception->getMessage()], 'guest');
  521. $expected->setStatus($exception->getCode());
  522. $this->assertEquals($expected, $response);
  523. }
  524. public function testAfterAjaxExceptionReturnsJSONError() {
  525. $response = $this->middleware->afterException($this->controller, 'test',
  526. $this->secAjaxException);
  527. $this->assertTrue($response instanceof JSONResponse);
  528. }
  529. public function dataRestrictedApp() {
  530. return [
  531. [false, false, false,],
  532. [false, false, true,],
  533. [false, true, false,],
  534. [false, true, true,],
  535. [ true, false, false,],
  536. [ true, false, true,],
  537. [ true, true, false,],
  538. [ true, true, true,],
  539. ];
  540. }
  541. /**
  542. * @PublicPage
  543. * @NoAdminRequired
  544. * @NoCSRFRequired
  545. */
  546. public function testRestrictedAppLoggedInPublicPage() {
  547. $middleware = $this->getMiddleware(true, false, false);
  548. $this->reader->reflect(__CLASS__, __FUNCTION__);
  549. $this->appManager->method('getAppPath')
  550. ->with('files')
  551. ->willReturn('foo');
  552. $this->appManager->method('isEnabledForUser')
  553. ->with('files')
  554. ->willReturn(false);
  555. $middleware->beforeController($this->controller, __FUNCTION__);
  556. $this->addToAssertionCount(1);
  557. }
  558. /**
  559. * @PublicPage
  560. * @NoAdminRequired
  561. * @NoCSRFRequired
  562. */
  563. public function testRestrictedAppNotLoggedInPublicPage() {
  564. $middleware = $this->getMiddleware(false, false, false);
  565. $this->reader->reflect(__CLASS__, __FUNCTION__);
  566. $this->appManager->method('getAppPath')
  567. ->with('files')
  568. ->willReturn('foo');
  569. $this->appManager->method('isEnabledForUser')
  570. ->with('files')
  571. ->willReturn(false);
  572. $middleware->beforeController($this->controller, __FUNCTION__);
  573. $this->addToAssertionCount(1);
  574. }
  575. /**
  576. * @NoAdminRequired
  577. * @NoCSRFRequired
  578. */
  579. public function testRestrictedAppLoggedIn() {
  580. $middleware = $this->getMiddleware(true, false, false, false);
  581. $this->reader->reflect(__CLASS__, __FUNCTION__);
  582. $this->appManager->method('getAppPath')
  583. ->with('files')
  584. ->willReturn('foo');
  585. $this->expectException(AppNotEnabledException::class);
  586. $middleware->beforeController($this->controller, __FUNCTION__);
  587. }
  588. }