aboutsummaryrefslogtreecommitdiffstats
path: root/tests/lib/AppFramework/Middleware
diff options
context:
space:
mode:
Diffstat (limited to 'tests/lib/AppFramework/Middleware')
-rw-r--r--tests/lib/AppFramework/Middleware/AdditionalScriptsMiddlewareTest.php79
-rw-r--r--tests/lib/AppFramework/Middleware/CompressionMiddlewareTest.php32
-rw-r--r--tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php79
-rw-r--r--tests/lib/AppFramework/Middleware/MiddlewareTest.php47
-rw-r--r--tests/lib/AppFramework/Middleware/NotModifiedMiddlewareTest.php39
-rw-r--r--tests/lib/AppFramework/Middleware/OCSMiddlewareTest.php165
-rw-r--r--tests/lib/AppFramework/Middleware/PublicShare/PublicShareMiddlewareTest.php66
-rw-r--r--tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php313
-rw-r--r--tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php233
-rw-r--r--tests/lib/AppFramework/Middleware/Security/CSPMiddlewareTest.php52
-rw-r--r--tests/lib/AppFramework/Middleware/Security/FeaturePolicyMiddlewareTest.php26
-rw-r--r--tests/lib/AppFramework/Middleware/Security/Mock/CORSMiddlewareController.php145
-rw-r--r--tests/lib/AppFramework/Middleware/Security/Mock/NormalController.php17
-rw-r--r--tests/lib/AppFramework/Middleware/Security/Mock/OCSController.php15
-rw-r--r--tests/lib/AppFramework/Middleware/Security/Mock/PasswordConfirmationMiddlewareController.php38
-rw-r--r--tests/lib/AppFramework/Middleware/Security/Mock/SecurityMiddlewareController.php171
-rw-r--r--tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php169
-rw-r--r--tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php323
-rw-r--r--tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.php37
-rw-r--r--tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php530
-rw-r--r--tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php158
21 files changed, 1634 insertions, 1100 deletions
diff --git a/tests/lib/AppFramework/Middleware/AdditionalScriptsMiddlewareTest.php b/tests/lib/AppFramework/Middleware/AdditionalScriptsMiddlewareTest.php
index 5127248215b..4fa5de62b0b 100644
--- a/tests/lib/AppFramework/Middleware/AdditionalScriptsMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/AdditionalScriptsMiddlewareTest.php
@@ -2,25 +2,8 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware;
@@ -35,12 +18,8 @@ use OCP\AppFramework\PublicShareController;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IUserSession;
use PHPUnit\Framework\MockObject\MockObject;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class AdditionalScriptsMiddlewareTest extends \Test\TestCase {
-
- /** @var EventDispatcherInterface|MockObject */
- private $legacyDispatcher;
/** @var IUserSession|MockObject */
private $userSession;
@@ -55,11 +34,9 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase {
protected function setUp(): void {
parent::setUp();
- $this->legacyDispatcher = $this->createMock(EventDispatcherInterface::class);
$this->userSession = $this->createMock(IUserSession::class);
$this->dispatcher = $this->createMock(IEventDispatcher::class);
$this->middleWare = new AdditionalScriptsMiddleware(
- $this->legacyDispatcher,
$this->userSession,
$this->dispatcher
);
@@ -67,9 +44,7 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase {
$this->controller = $this->createMock(Controller::class);
}
- public function testNoTemplateResponse() {
- $this->legacyDispatcher->expects($this->never())
- ->method($this->anything());
+ public function testNoTemplateResponse(): void {
$this->userSession->expects($this->never())
->method($this->anything());
$this->dispatcher->expects($this->never())
@@ -78,9 +53,7 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase {
$this->middleWare->afterController($this->controller, 'myMethod', $this->createMock(Response::class));
}
- public function testPublicShareController() {
- $this->legacyDispatcher->expects($this->never())
- ->method($this->anything());
+ public function testPublicShareController(): void {
$this->userSession->expects($this->never())
->method($this->anything());
$this->dispatcher->expects($this->never())
@@ -89,21 +62,12 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase {
$this->middleWare->afterController($this->createMock(PublicShareController::class), 'myMethod', $this->createMock(Response::class));
}
- public function testStandaloneTemplateResponse() {
- $this->legacyDispatcher->expects($this->once())
- ->method('dispatch')
- ->willReturnCallback(function ($eventName) {
- if ($eventName === TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS) {
- return;
- }
-
- $this->fail('Wrong event dispatched');
- });
+ public function testStandaloneTemplateResponse(): void {
$this->userSession->expects($this->never())
->method($this->anything());
$this->dispatcher->expects($this->once())
->method('dispatchTyped')
- ->willReturnCallback(function ($event) {
+ ->willReturnCallback(function ($event): void {
if ($event instanceof BeforeTemplateRenderedEvent && $event->isLoggedIn() === false) {
return;
}
@@ -114,21 +78,12 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase {
$this->middleWare->afterController($this->controller, 'myMethod', $this->createMock(StandaloneTemplateResponse::class));
}
- public function testTemplateResponseNotLoggedIn() {
- $this->legacyDispatcher->expects($this->once())
- ->method('dispatch')
- ->willReturnCallback(function ($eventName) {
- if ($eventName === TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS) {
- return;
- }
-
- $this->fail('Wrong event dispatched');
- });
+ public function testTemplateResponseNotLoggedIn(): void {
$this->userSession->method('isLoggedIn')
->willReturn(false);
$this->dispatcher->expects($this->once())
->method('dispatchTyped')
- ->willReturnCallback(function ($event) {
+ ->willReturnCallback(function ($event): void {
if ($event instanceof BeforeTemplateRenderedEvent && $event->isLoggedIn() === false) {
return;
}
@@ -139,25 +94,14 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase {
$this->middleWare->afterController($this->controller, 'myMethod', $this->createMock(TemplateResponse::class));
}
- public function testTemplateResponseLoggedIn() {
+ public function testTemplateResponseLoggedIn(): void {
$events = [];
- $this->legacyDispatcher->expects($this->exactly(2))
- ->method('dispatch')
- ->willReturnCallback(function ($eventName) use (&$events) {
- if ($eventName === TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS ||
- $eventName === TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS_LOGGEDIN) {
- $events[] = $eventName;
- return;
- }
-
- $this->fail('Wrong event dispatched');
- });
$this->userSession->method('isLoggedIn')
->willReturn(true);
$this->dispatcher->expects($this->once())
->method('dispatchTyped')
- ->willReturnCallback(function ($event) {
+ ->willReturnCallback(function ($event): void {
if ($event instanceof BeforeTemplateRenderedEvent && $event->isLoggedIn() === true) {
return;
}
@@ -166,8 +110,5 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase {
});
$this->middleWare->afterController($this->controller, 'myMethod', $this->createMock(TemplateResponse::class));
-
- $this->assertContains(TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS, $events);
- $this->assertContains(TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS_LOGGEDIN, $events);
}
}
diff --git a/tests/lib/AppFramework/Middleware/CompressionMiddlewareTest.php b/tests/lib/AppFramework/Middleware/CompressionMiddlewareTest.php
index 5dd13942097..010ce3fff6d 100644
--- a/tests/lib/AppFramework/Middleware/CompressionMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/CompressionMiddlewareTest.php
@@ -2,25 +2,8 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware;
@@ -35,7 +18,6 @@ use OCP\AppFramework\Http\JSONResponse;
use OCP\IRequest;
class CompressionMiddlewareTest extends \Test\TestCase {
-
/** @var IRequest */
private $request;
/** @var Controller */
@@ -54,7 +36,7 @@ class CompressionMiddlewareTest extends \Test\TestCase {
$this->controller = $this->createMock(Controller::class);
}
- public function testGzipOCSV1() {
+ public function testGzipOCSV1(): void {
$this->request->method('getHeader')
->with('Accept-Encoding')
->willReturn('gzip');
@@ -76,7 +58,7 @@ class CompressionMiddlewareTest extends \Test\TestCase {
$this->assertSame($output, gzdecode($result));
}
- public function testGzipOCSV2() {
+ public function testGzipOCSV2(): void {
$this->request->method('getHeader')
->with('Accept-Encoding')
->willReturn('gzip');
@@ -98,7 +80,7 @@ class CompressionMiddlewareTest extends \Test\TestCase {
$this->assertSame($output, gzdecode($result));
}
- public function testGzipJSONResponse() {
+ public function testGzipJSONResponse(): void {
$this->request->method('getHeader')
->with('Accept-Encoding')
->willReturn('gzip');
@@ -120,7 +102,7 @@ class CompressionMiddlewareTest extends \Test\TestCase {
$this->assertSame($output, gzdecode($result));
}
- public function testNoGzipDataResponse() {
+ public function testNoGzipDataResponse(): void {
$this->request->method('getHeader')
->with('Accept-Encoding')
->willReturn('gzip');
@@ -140,7 +122,7 @@ class CompressionMiddlewareTest extends \Test\TestCase {
$this->assertSame($output, $result);
}
- public function testNoGzipNo200() {
+ public function testNoGzipNo200(): void {
$this->request->method('getHeader')
->with('Accept-Encoding')
->willReturn('gzip');
diff --git a/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php b/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php
index f408320971d..aae1c53456b 100644
--- a/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php
+++ b/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php
@@ -1,30 +1,16 @@
<?php
/**
- * ownCloud - App Framework
- *
- * @author Bernhard Posselt
- * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware;
use OC\AppFramework\Http\Request;
use OC\AppFramework\Middleware\MiddlewareDispatcher;
+use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Middleware;
use OCP\IConfig;
@@ -48,17 +34,16 @@ class TestMiddleware extends Middleware {
public $response;
public $output;
- private $beforeControllerThrowsEx;
-
/**
* @param boolean $beforeControllerThrowsEx
*/
- public function __construct($beforeControllerThrowsEx) {
+ public function __construct(
+ private $beforeControllerThrowsEx,
+ ) {
self::$beforeControllerCalled = 0;
self::$afterControllerCalled = 0;
self::$afterExceptionCalled = 0;
self::$beforeOutputCalled = 0;
- $this->beforeControllerThrowsEx = $beforeControllerThrowsEx;
}
public function beforeController($controller, $methodName) {
@@ -99,6 +84,10 @@ class TestMiddleware extends Middleware {
}
}
+class TestController extends Controller {
+ public function method(): void {
+ }
+}
class MiddlewareDispatcherTest extends \Test\TestCase {
public $exception;
@@ -125,8 +114,8 @@ class MiddlewareDispatcherTest extends \Test\TestCase {
private function getControllerMock() {
- return $this->getMockBuilder('OCP\AppFramework\Controller')
- ->setMethods(['method'])
+ return $this->getMockBuilder(TestController::class)
+ ->onlyMethods(['method'])
->setConstructorArgs(['app',
new Request(
['method' => 'GET'],
@@ -144,20 +133,20 @@ class MiddlewareDispatcherTest extends \Test\TestCase {
}
- public function testAfterExceptionShouldReturnResponseOfMiddleware() {
+ public function testAfterExceptionShouldReturnResponseOfMiddleware(): void {
$response = new Response();
- $m1 = $this->getMockBuilder('\OCP\AppFramework\Middleware')
- ->setMethods(['afterException', 'beforeController'])
+ $m1 = $this->getMockBuilder(Middleware::class)
+ ->onlyMethods(['afterException', 'beforeController'])
->getMock();
$m1->expects($this->never())
- ->method('afterException');
+ ->method('afterException');
- $m2 = $this->getMockBuilder('OCP\AppFramework\Middleware')
- ->setMethods(['afterException', 'beforeController'])
+ $m2 = $this->getMockBuilder(Middleware::class)
+ ->onlyMethods(['afterException', 'beforeController'])
->getMock();
$m2->expects($this->once())
- ->method('afterException')
- ->willReturn($response);
+ ->method('afterException')
+ ->willReturn($response);
$this->dispatcher->registerMiddleware($m1);
$this->dispatcher->registerMiddleware($m2);
@@ -167,7 +156,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase {
}
- public function testAfterExceptionShouldThrowAgainWhenNotHandled() {
+ public function testAfterExceptionShouldThrowAgainWhenNotHandled(): void {
$m1 = new TestMiddleware(false);
$m2 = new TestMiddleware(true);
@@ -180,7 +169,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase {
}
- public function testBeforeControllerCorrectArguments() {
+ public function testBeforeControllerCorrectArguments(): void {
$m1 = $this->getMiddleware();
$this->dispatcher->beforeController($this->controller, $this->method);
@@ -189,7 +178,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase {
}
- public function testAfterControllerCorrectArguments() {
+ public function testAfterControllerCorrectArguments(): void {
$m1 = $this->getMiddleware();
$this->dispatcher->afterController($this->controller, $this->method, $this->response);
@@ -200,7 +189,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase {
}
- public function testAfterExceptionCorrectArguments() {
+ public function testAfterExceptionCorrectArguments(): void {
$m1 = $this->getMiddleware();
$this->expectException(\Exception::class);
@@ -214,7 +203,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase {
}
- public function testBeforeOutputCorrectArguments() {
+ public function testBeforeOutputCorrectArguments(): void {
$m1 = $this->getMiddleware();
$this->dispatcher->beforeOutput($this->controller, $this->method, $this->out);
@@ -225,7 +214,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase {
}
- public function testBeforeControllerOrder() {
+ public function testBeforeControllerOrder(): void {
$m1 = $this->getMiddleware();
$m2 = $this->getMiddleware();
@@ -235,7 +224,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase {
$this->assertEquals(2, $m2->beforeControllerOrder);
}
- public function testAfterControllerOrder() {
+ public function testAfterControllerOrder(): void {
$m1 = $this->getMiddleware();
$m2 = $this->getMiddleware();
@@ -246,7 +235,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase {
}
- public function testAfterExceptionOrder() {
+ public function testAfterExceptionOrder(): void {
$m1 = $this->getMiddleware();
$m2 = $this->getMiddleware();
@@ -259,7 +248,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase {
}
- public function testBeforeOutputOrder() {
+ public function testBeforeOutputOrder(): void {
$m1 = $this->getMiddleware();
$m2 = $this->getMiddleware();
@@ -270,16 +259,16 @@ class MiddlewareDispatcherTest extends \Test\TestCase {
}
- public function testExceptionShouldRunAfterExceptionOfOnlyPreviouslyExecutedMiddlewares() {
+ public function testExceptionShouldRunAfterExceptionOfOnlyPreviouslyExecutedMiddlewares(): void {
$m1 = $this->getMiddleware();
$m2 = $this->getMiddleware(true);
$m3 = $this->createMock(Middleware::class);
$m3->expects($this->never())
- ->method('afterException');
+ ->method('afterException');
$m3->expects($this->never())
- ->method('beforeController');
+ ->method('beforeController');
$m3->expects($this->never())
- ->method('afterController');
+ ->method('afterController');
$m3->method('beforeOutput')
->willReturnArgument(2);
diff --git a/tests/lib/AppFramework/Middleware/MiddlewareTest.php b/tests/lib/AppFramework/Middleware/MiddlewareTest.php
index bd61aab4673..addd9683122 100644
--- a/tests/lib/AppFramework/Middleware/MiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/MiddlewareTest.php
@@ -1,42 +1,26 @@
<?php
/**
- * ownCloud - App Framework
- *
- * @author Bernhard Posselt
- * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware;
+use OC\AppFramework\DependencyInjection\DIContainer;
use OC\AppFramework\Http\Request;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Middleware;
use OCP\IConfig;
use OCP\IRequestId;
-use OC\AppFramework\DependencyInjection\DIContainer;
class ChildMiddleware extends Middleware {
};
class MiddlewareTest extends \Test\TestCase {
-
/**
* @var Middleware
*/
@@ -52,12 +36,9 @@ class MiddlewareTest extends \Test\TestCase {
$this->middleware = new ChildMiddleware();
- $this->api = $this->getMockBuilder(DIContainer::class)
- ->disableOriginalConstructor()
- ->getMock();
+ $this->api = $this->createMock(DIContainer::class);
$this->controller = $this->getMockBuilder(Controller::class)
- ->setMethods([])
->setConstructorArgs([
$this->api,
new Request(
@@ -67,31 +48,31 @@ class MiddlewareTest extends \Test\TestCase {
)
])->getMock();
$this->exception = new \Exception();
- $this->response = $this->getMockBuilder(Response::class)->getMock();
+ $this->response = $this->createMock(Response::class);
}
- public function testBeforeController() {
- $this->middleware->beforeController($this->controller, null);
+ public function testBeforeController(): void {
+ $this->middleware->beforeController($this->controller, '');
$this->assertNull(null);
}
- public function testAfterExceptionRaiseAgainWhenUnhandled() {
+ public function testAfterExceptionRaiseAgainWhenUnhandled(): void {
$this->expectException(\Exception::class);
- $this->middleware->afterException($this->controller, null, $this->exception);
+ $this->middleware->afterException($this->controller, '', $this->exception);
}
- public function testAfterControllerReturnResponseWhenUnhandled() {
- $response = $this->middleware->afterController($this->controller, null, $this->response);
+ public function testAfterControllerReturnResponseWhenUnhandled(): void {
+ $response = $this->middleware->afterController($this->controller, '', $this->response);
$this->assertEquals($this->response, $response);
}
- public function testBeforeOutputReturnOutputhenUnhandled() {
- $output = $this->middleware->beforeOutput($this->controller, null, 'test');
+ public function testBeforeOutputReturnOutputhenUnhandled(): void {
+ $output = $this->middleware->beforeOutput($this->controller, '', 'test');
$this->assertEquals('test', $output);
}
diff --git a/tests/lib/AppFramework/Middleware/NotModifiedMiddlewareTest.php b/tests/lib/AppFramework/Middleware/NotModifiedMiddlewareTest.php
index c62384302fb..7dcb28a2af4 100644
--- a/tests/lib/AppFramework/Middleware/NotModifiedMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/NotModifiedMiddlewareTest.php
@@ -2,25 +2,8 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware;
@@ -28,10 +11,10 @@ namespace Test\AppFramework\Middleware;
use OC\AppFramework\Middleware\NotModifiedMiddleware;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\Response;
use OCP\IRequest;
class NotModifiedMiddlewareTest extends \Test\TestCase {
-
/** @var IRequest */
private $request;
/** @var Controller */
@@ -50,7 +33,7 @@ class NotModifiedMiddlewareTest extends \Test\TestCase {
$this->controller = $this->createMock(Controller::class);
}
- public function dataModified(): array {
+ public static function dataModified(): array {
$now = new \DateTime();
return [
@@ -61,20 +44,18 @@ class NotModifiedMiddlewareTest extends \Test\TestCase {
[null, '"etag"', null, '', false],
['etag', '"etag"', null, '', true],
- [null, '', $now, $now->format(\DateTimeInterface::RFC2822), true],
+ [null, '', $now, $now->format(\DateTimeInterface::RFC7231), true],
[null, '', $now, $now->format(\DateTimeInterface::ATOM), false],
- [null, '', null, $now->format(\DateTimeInterface::RFC2822), false],
+ [null, '', null, $now->format(\DateTimeInterface::RFC7231), false],
[null, '', $now, '', false],
['etag', '"etag"', $now, $now->format(\DateTimeInterface::ATOM), true],
- ['etag', '"etag"', $now, $now->format(\DateTimeInterface::RFC2822), true],
+ ['etag', '"etag"', $now, $now->format(\DateTimeInterface::RFC7231), true],
];
}
- /**
- * @dataProvider dataModified
- */
- public function testMiddleware(?string $etag, string $etagHeader, ?\DateTime $lastModified, string $lastModifiedHeader, bool $notModifiedSet) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataModified')]
+ public function testMiddleware(?string $etag, string $etagHeader, ?\DateTime $lastModified, string $lastModifiedHeader, bool $notModifiedSet): void {
$this->request->method('getHeader')
->willReturnCallback(function (string $name) use ($etagHeader, $lastModifiedHeader) {
if ($name === 'IF_NONE_MATCH') {
@@ -86,7 +67,7 @@ class NotModifiedMiddlewareTest extends \Test\TestCase {
return '';
});
- $response = new Http\Response();
+ $response = new Response();
if ($etag !== null) {
$response->setETag($etag);
}
diff --git a/tests/lib/AppFramework/Middleware/OCSMiddlewareTest.php b/tests/lib/AppFramework/Middleware/OCSMiddlewareTest.php
index 83b764f6c65..e5c6a417a4b 100644
--- a/tests/lib/AppFramework/Middleware/OCSMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/OCSMiddlewareTest.php
@@ -1,23 +1,8 @@
<?php
+
/**
- *
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware;
@@ -28,6 +13,8 @@ use OC\AppFramework\OCS\V1Response;
use OC\AppFramework\OCS\V2Response;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\AppFramework\Http\Response;
use OCP\AppFramework\OCS\OCSBadRequestException;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\OCS\OCSForbiddenException;
@@ -36,7 +23,6 @@ use OCP\AppFramework\OCSController;
use OCP\IRequest;
class OCSMiddlewareTest extends \Test\TestCase {
-
/**
* @var IRequest
*/
@@ -49,49 +35,35 @@ class OCSMiddlewareTest extends \Test\TestCase {
->getMock();
}
- public function dataAfterException() {
- $OCSController = $this->getMockBuilder(OCSController::class)
- ->disableOriginalConstructor()
- ->getMock();
- $controller = $this->getMockBuilder(Controller::class)
- ->disableOriginalConstructor()
- ->getMock();
-
+ public static function dataAfterException(): array {
return [
- [$OCSController, new \Exception(), true],
- [$OCSController, new OCSException(), false, '', Http::STATUS_INTERNAL_SERVER_ERROR],
- [$OCSController, new OCSException('foo'), false, 'foo', Http::STATUS_INTERNAL_SERVER_ERROR],
- [$OCSController, new OCSException('foo', Http::STATUS_IM_A_TEAPOT), false, 'foo', Http::STATUS_IM_A_TEAPOT],
- [$OCSController, new OCSBadRequestException(), false, '', Http::STATUS_BAD_REQUEST],
- [$OCSController, new OCSBadRequestException('foo'), false, 'foo', Http::STATUS_BAD_REQUEST],
- [$OCSController, new OCSForbiddenException(), false, '', Http::STATUS_FORBIDDEN],
- [$OCSController, new OCSForbiddenException('foo'), false, 'foo', Http::STATUS_FORBIDDEN],
- [$OCSController, new OCSNotFoundException(), false, '', Http::STATUS_NOT_FOUND],
- [$OCSController, new OCSNotFoundException('foo'), false, 'foo', Http::STATUS_NOT_FOUND],
-
- [$controller, new \Exception(), true],
- [$controller, new OCSException(), true],
- [$controller, new OCSException('foo'), true],
- [$controller, new OCSException('foo', Http::STATUS_IM_A_TEAPOT), true],
- [$controller, new OCSBadRequestException(), true],
- [$controller, new OCSBadRequestException('foo'), true],
- [$controller, new OCSForbiddenException(), true],
- [$controller, new OCSForbiddenException('foo'), true],
- [$controller, new OCSNotFoundException(), true],
- [$controller, new OCSNotFoundException('foo'), true],
+ [OCSController::class, new \Exception(), true],
+ [OCSController::class, new OCSException(), false, '', Http::STATUS_INTERNAL_SERVER_ERROR],
+ [OCSController::class, new OCSException('foo'), false, 'foo', Http::STATUS_INTERNAL_SERVER_ERROR],
+ [OCSController::class, new OCSException('foo', Http::STATUS_IM_A_TEAPOT), false, 'foo', Http::STATUS_IM_A_TEAPOT],
+ [OCSController::class, new OCSBadRequestException(), false, '', Http::STATUS_BAD_REQUEST],
+ [OCSController::class, new OCSBadRequestException('foo'), false, 'foo', Http::STATUS_BAD_REQUEST],
+ [OCSController::class, new OCSForbiddenException(), false, '', Http::STATUS_FORBIDDEN],
+ [OCSController::class, new OCSForbiddenException('foo'), false, 'foo', Http::STATUS_FORBIDDEN],
+ [OCSController::class, new OCSNotFoundException(), false, '', Http::STATUS_NOT_FOUND],
+ [OCSController::class, new OCSNotFoundException('foo'), false, 'foo', Http::STATUS_NOT_FOUND],
+
+ [Controller::class, new \Exception(), true],
+ [Controller::class, new OCSException(), true],
+ [Controller::class, new OCSException('foo'), true],
+ [Controller::class, new OCSException('foo', Http::STATUS_IM_A_TEAPOT), true],
+ [Controller::class, new OCSBadRequestException(), true],
+ [Controller::class, new OCSBadRequestException('foo'), true],
+ [Controller::class, new OCSForbiddenException(), true],
+ [Controller::class, new OCSForbiddenException('foo'), true],
+ [Controller::class, new OCSNotFoundException(), true],
+ [Controller::class, new OCSNotFoundException('foo'), true],
];
}
- /**
- * @dataProvider dataAfterException
- *
- * @param Controller $controller
- * @param \Exception $exception
- * @param bool $forward
- * @param string $message
- * @param int $code
- */
- public function testAfterExceptionOCSv1($controller, $exception, $forward, $message = '', $code = 0) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataAfterException')]
+ public function testAfterExceptionOCSv1(string $controller, \Exception $exception, bool $forward, string $message = '', int $code = 0): void {
+ $controller = $this->createMock($controller);
$this->request
->method('getScriptName')
->willReturn('/ocs/v1.php');
@@ -110,7 +82,7 @@ class OCSMiddlewareTest extends \Test\TestCase {
$this->assertSame($message, $this->invokePrivate($result, 'statusMessage'));
if ($exception->getCode() === 0) {
- $this->assertSame(\OCP\AppFramework\OCSController::RESPOND_UNKNOWN_ERROR, $result->getOCSStatus());
+ $this->assertSame(OCSController::RESPOND_UNKNOWN_ERROR, $result->getOCSStatus());
} else {
$this->assertSame($code, $result->getOCSStatus());
}
@@ -118,16 +90,9 @@ class OCSMiddlewareTest extends \Test\TestCase {
$this->assertSame(Http::STATUS_OK, $result->getStatus());
}
- /**
- * @dataProvider dataAfterException
- *
- * @param Controller $controller
- * @param \Exception $exception
- * @param bool $forward
- * @param string $message
- * @param int $code
- */
- public function testAfterExceptionOCSv2($controller, $exception, $forward, $message = '', $code = 0) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataAfterException')]
+ public function testAfterExceptionOCSv2(string $controller, \Exception $exception, bool $forward, string $message = '', int $code = 0): void {
+ $controller = $this->createMock($controller);
$this->request
->method('getScriptName')
->willReturn('/ocs/v2.php');
@@ -145,23 +110,16 @@ class OCSMiddlewareTest extends \Test\TestCase {
$this->assertSame($message, $this->invokePrivate($result, 'statusMessage'));
if ($exception->getCode() === 0) {
- $this->assertSame(\OCP\AppFramework\OCSController::RESPOND_UNKNOWN_ERROR, $result->getOCSStatus());
+ $this->assertSame(OCSController::RESPOND_UNKNOWN_ERROR, $result->getOCSStatus());
} else {
$this->assertSame($code, $result->getOCSStatus());
}
$this->assertSame($code, $result->getStatus());
}
- /**
- * @dataProvider dataAfterException
- *
- * @param Controller $controller
- * @param \Exception $exception
- * @param bool $forward
- * @param string $message
- * @param int $code
- */
- public function testAfterExceptionOCSv2SubFolder($controller, $exception, $forward, $message = '', $code = 0) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataAfterException')]
+ public function testAfterExceptionOCSv2SubFolder(string $controller, \Exception $exception, bool $forward, string $message = '', int $code = 0): void {
+ $controller = $this->createMock($controller);
$this->request
->method('getScriptName')
->willReturn('/mysubfolder/ocs/v2.php');
@@ -169,7 +127,7 @@ class OCSMiddlewareTest extends \Test\TestCase {
$OCSMiddleware->beforeController($controller, 'method');
if ($forward) {
- $this->expectException(get_class($exception));
+ $this->expectException($exception::class);
$this->expectExceptionMessage($exception->getMessage());
}
@@ -179,46 +137,33 @@ class OCSMiddlewareTest extends \Test\TestCase {
$this->assertSame($message, $this->invokePrivate($result, 'statusMessage'));
if ($exception->getCode() === 0) {
- $this->assertSame(\OCP\AppFramework\OCSController::RESPOND_UNKNOWN_ERROR, $result->getOCSStatus());
+ $this->assertSame(OCSController::RESPOND_UNKNOWN_ERROR, $result->getOCSStatus());
} else {
$this->assertSame($code, $result->getOCSStatus());
}
$this->assertSame($code, $result->getStatus());
}
- public function dataAfterController() {
- $OCSController = $this->getMockBuilder(OCSController::class)
- ->disableOriginalConstructor()
- ->getMock();
- $controller = $this->getMockBuilder(Controller::class)
- ->disableOriginalConstructor()
- ->getMock();
-
+ public static function dataAfterController(): array {
return [
- [$OCSController, new Http\Response(), false],
- [$OCSController, new Http\JSONResponse(), false],
- [$OCSController, new Http\JSONResponse(['message' => 'foo']), false],
- [$OCSController, new Http\JSONResponse(['message' => 'foo'], Http::STATUS_UNAUTHORIZED), true, OCSController::RESPOND_UNAUTHORISED],
- [$OCSController, new Http\JSONResponse(['message' => 'foo'], Http::STATUS_FORBIDDEN), true],
-
- [$controller, new Http\Response(), false],
- [$controller, new Http\JSONResponse(), false],
- [$controller, new Http\JSONResponse(['message' => 'foo']), false],
- [$controller, new Http\JSONResponse(['message' => 'foo'], Http::STATUS_UNAUTHORIZED), false],
- [$controller, new Http\JSONResponse(['message' => 'foo'], Http::STATUS_FORBIDDEN), false],
+ [OCSController::class, new Response(), false],
+ [OCSController::class, new JSONResponse(), false],
+ [OCSController::class, new JSONResponse(['message' => 'foo']), false],
+ [OCSController::class, new JSONResponse(['message' => 'foo'], Http::STATUS_UNAUTHORIZED), true, OCSController::RESPOND_UNAUTHORISED],
+ [OCSController::class, new JSONResponse(['message' => 'foo'], Http::STATUS_FORBIDDEN), true],
+
+ [Controller::class, new Response(), false],
+ [Controller::class, new JSONResponse(), false],
+ [Controller::class, new JSONResponse(['message' => 'foo']), false],
+ [Controller::class, new JSONResponse(['message' => 'foo'], Http::STATUS_UNAUTHORIZED), false],
+ [Controller::class, new JSONResponse(['message' => 'foo'], Http::STATUS_FORBIDDEN), false],
];
}
- /**
- * @dataProvider dataAfterController
- *
- * @param Controller $controller
- * @param Http\Response $response
- * @param bool $converted
- * @param int $convertedOCSStatus
- */
- public function testAfterController($controller, $response, $converted, $convertedOCSStatus = 0) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataAfterController')]
+ public function testAfterController(string $controller, Response $response, bool $converted, int $convertedOCSStatus = 0): void {
+ $controller = $this->createMock($controller);
$OCSMiddleware = new OCSMiddleware($this->request);
$newResponse = $OCSMiddleware->afterController($controller, 'foo', $response);
diff --git a/tests/lib/AppFramework/Middleware/PublicShare/PublicShareMiddlewareTest.php b/tests/lib/AppFramework/Middleware/PublicShare/PublicShareMiddlewareTest.php
index 7e7140971e4..e87ee7fd565 100644
--- a/tests/lib/AppFramework/Middleware/PublicShare/PublicShareMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/PublicShare/PublicShareMiddlewareTest.php
@@ -1,24 +1,8 @@
<?php
+
/**
- * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware\PublicShare;
@@ -27,23 +11,26 @@ use OC\AppFramework\Middleware\PublicShare\Exceptions\NeedAuthenticationExceptio
use OC\AppFramework\Middleware\PublicShare\PublicShareMiddleware;
use OCP\AppFramework\AuthPublicShareController;
use OCP\AppFramework\Controller;
-use OCP\AppFramework\Http\NotFoundResponse;
+use OCP\AppFramework\Http;
use OCP\AppFramework\Http\RedirectResponse;
+use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\PublicShareController;
use OCP\Files\NotFoundException;
use OCP\IConfig;
use OCP\IRequest;
use OCP\ISession;
use OCP\IURLGenerator;
+use OCP\Security\Bruteforce\IThrottler;
class PublicShareMiddlewareTest extends \Test\TestCase {
-
/** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */
private $request;
/** @var ISession|\PHPUnit\Framework\MockObject\MockObject */
private $session;
/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
private $config;
+ /** @var IThrottler|\PHPUnit\Framework\MockObject\MockObject */
+ private $throttler;
/** @var PublicShareMiddleware */
private $middleware;
@@ -55,22 +42,24 @@ class PublicShareMiddlewareTest extends \Test\TestCase {
$this->request = $this->createMock(IRequest::class);
$this->session = $this->createMock(ISession::class);
$this->config = $this->createMock(IConfig::class);
+ $this->throttler = $this->createMock(IThrottler::class);
$this->middleware = new PublicShareMiddleware(
$this->request,
$this->session,
- $this->config
+ $this->config,
+ $this->throttler
);
}
- public function testBeforeControllerNoPublicShareController() {
+ public function testBeforeControllerNoPublicShareController(): void {
$controller = $this->createMock(Controller::class);
$this->middleware->beforeController($controller, 'method');
$this->assertTrue(true);
}
- public function dataShareApi() {
+ public static function dataShareApi(): array {
return [
['no', 'no',],
['no', 'yes',],
@@ -78,10 +67,8 @@ class PublicShareMiddlewareTest extends \Test\TestCase {
];
}
- /**
- * @dataProvider dataShareApi
- */
- public function testBeforeControllerShareApiDisabled(string $shareApi, string $shareLinks) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataShareApi')]
+ public function testBeforeControllerShareApiDisabled(string $shareApi, string $shareLinks): void {
$controller = $this->createMock(PublicShareController::class);
$this->config->method('getAppValue')
@@ -94,7 +81,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase {
$this->middleware->beforeController($controller, 'mehod');
}
- public function testBeforeControllerNoTokenParam() {
+ public function testBeforeControllerNoTokenParam(): void {
$controller = $this->createMock(PublicShareController::class);
$this->config->method('getAppValue')
@@ -107,7 +94,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase {
$this->middleware->beforeController($controller, 'mehod');
}
- public function testBeforeControllerInvalidToken() {
+ public function testBeforeControllerInvalidToken(): void {
$controller = $this->createMock(PublicShareController::class);
$this->config->method('getAppValue')
@@ -129,7 +116,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase {
$this->middleware->beforeController($controller, 'mehod');
}
- public function testBeforeControllerValidTokenNotAuthenticated() {
+ public function testBeforeControllerValidTokenNotAuthenticated(): void {
$controller = $this->getMockBuilder(PublicShareController::class)
->setConstructorArgs(['app', $this->request, $this->session])
->getMock();
@@ -154,7 +141,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase {
$this->middleware->beforeController($controller, 'mehod');
}
- public function testBeforeControllerValidTokenAuthenticateMethod() {
+ public function testBeforeControllerValidTokenAuthenticateMethod(): void {
$controller = $this->getMockBuilder(PublicShareController::class)
->setConstructorArgs(['app', $this->request, $this->session])
->getMock();
@@ -179,7 +166,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase {
$this->assertTrue(true);
}
- public function testBeforeControllerValidTokenShowAuthenticateMethod() {
+ public function testBeforeControllerValidTokenShowAuthenticateMethod(): void {
$controller = $this->getMockBuilder(PublicShareController::class)
->setConstructorArgs(['app', $this->request, $this->session])
->getMock();
@@ -204,7 +191,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase {
$this->assertTrue(true);
}
- public function testBeforeControllerAuthPublicShareController() {
+ public function testBeforeControllerAuthPublicShareController(): void {
$controller = $this->getMockBuilder(AuthPublicShareController::class)
->setConstructorArgs(['app', $this->request, $this->session, $this->createMock(IURLGenerator::class)])
->getMock();
@@ -233,7 +220,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase {
$this->middleware->beforeController($controller, 'method');
}
- public function testAfterExceptionNoPublicShareController() {
+ public function testAfterExceptionNoPublicShareController(): void {
$controller = $this->createMock(Controller::class);
$exception = new \Exception();
@@ -244,15 +231,16 @@ class PublicShareMiddlewareTest extends \Test\TestCase {
}
}
- public function testAfterExceptionPublicShareControllerNotFoundException() {
+ public function testAfterExceptionPublicShareControllerNotFoundException(): void {
$controller = $this->createMock(PublicShareController::class);
$exception = new NotFoundException();
$result = $this->middleware->afterException($controller, 'method', $exception);
- $this->assertInstanceOf(NotFoundResponse::class, $result);
+ $this->assertInstanceOf(TemplateResponse::class, $result);
+ $this->assertEquals($result->getStatus(), Http::STATUS_NOT_FOUND);
}
- public function testAfterExceptionPublicShareController() {
+ public function testAfterExceptionPublicShareController(): void {
$controller = $this->createMock(PublicShareController::class);
$exception = new \Exception();
@@ -263,7 +251,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase {
}
}
- public function testAfterExceptionAuthPublicShareController() {
+ public function testAfterExceptionAuthPublicShareController(): void {
$controller = $this->getMockBuilder(AuthPublicShareController::class)
->setConstructorArgs([
'app',
diff --git a/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php
index cc04992ae18..3fd2cb38a33 100644
--- a/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php
@@ -1,69 +1,70 @@
<?php
+
/**
- * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware\Security;
use OC\AppFramework\Middleware\Security\BruteForceMiddleware;
use OC\AppFramework\Utility\ControllerMethodReflector;
-use OC\Security\Bruteforce\Throttler;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\BruteForceProtection;
use OCP\AppFramework\Http\Response;
use OCP\IRequest;
+use OCP\Security\Bruteforce\IThrottler;
+use Psr\Log\LoggerInterface;
use Test\TestCase;
+class TestController extends Controller {
+ /**
+ * @BruteForceProtection(action=login)
+ */
+ public function testMethodWithAnnotation() {
+ }
+
+ public function testMethodWithoutAnnotation() {
+ }
+
+ #[BruteForceProtection(action: 'single')]
+ public function singleAttribute(): void {
+ }
+
+ #[BruteForceProtection(action: 'first')]
+ #[BruteForceProtection(action: 'second')]
+ public function multipleAttributes(): void {
+ }
+}
+
class BruteForceMiddlewareTest extends TestCase {
- /** @var ControllerMethodReflector|\PHPUnit\Framework\MockObject\MockObject */
+ /** @var ControllerMethodReflector */
private $reflector;
- /** @var Throttler|\PHPUnit\Framework\MockObject\MockObject */
+ /** @var IThrottler|\PHPUnit\Framework\MockObject\MockObject */
private $throttler;
/** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */
private $request;
- /** @var BruteForceMiddleware */
- private $bruteForceMiddleware;
+ /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */
+ private $logger;
+ private BruteForceMiddleware $bruteForceMiddleware;
protected function setUp(): void {
parent::setUp();
- $this->reflector = $this->createMock(ControllerMethodReflector::class);
- $this->throttler = $this->createMock(Throttler::class);
+ $this->reflector = new ControllerMethodReflector();
+ $this->throttler = $this->createMock(IThrottler::class);
$this->request = $this->createMock(IRequest::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
$this->bruteForceMiddleware = new BruteForceMiddleware(
$this->reflector,
$this->throttler,
- $this->request
+ $this->request,
+ $this->logger,
);
}
- public function testBeforeControllerWithAnnotation() {
- $this->reflector
- ->expects($this->once())
- ->method('hasAnnotation')
- ->with('BruteForceProtection')
- ->willReturn(true);
- $this->reflector
- ->expects($this->once())
- ->method('getAnnotationParameter')
- ->with('BruteForceProtection', 'action')
- ->willReturn('login');
+ public function testBeforeControllerWithAnnotation(): void {
$this->request
->expects($this->once())
->method('getRemoteAddress')
@@ -73,20 +74,51 @@ class BruteForceMiddlewareTest extends TestCase {
->method('sleepDelayOrThrowOnMax')
->with('127.0.0.1', 'login');
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
- $controller = $this->createMock(Controller::class);
- $this->bruteForceMiddleware->beforeController($controller, 'testMethod');
+ $controller = new TestController('test', $this->request);
+ $this->reflector->reflect($controller, 'testMethodWithAnnotation');
+ $this->bruteForceMiddleware->beforeController($controller, 'testMethodWithAnnotation');
}
- public function testBeforeControllerWithoutAnnotation() {
- $this->reflector
+ public function testBeforeControllerWithSingleAttribute(): void {
+ $this->request
->expects($this->once())
- ->method('hasAnnotation')
- ->with('BruteForceProtection')
- ->willReturn(false);
- $this->reflector
- ->expects($this->never())
- ->method('getAnnotationParameter');
+ ->method('getRemoteAddress')
+ ->willReturn('::1');
+ $this->throttler
+ ->expects($this->once())
+ ->method('sleepDelayOrThrowOnMax')
+ ->with('::1', 'single');
+
+ $controller = new TestController('test', $this->request);
+ $this->reflector->reflect($controller, 'singleAttribute');
+ $this->bruteForceMiddleware->beforeController($controller, 'singleAttribute');
+ }
+
+ public function testBeforeControllerWithMultipleAttributes(): void {
+ $this->request
+ ->expects($this->once())
+ ->method('getRemoteAddress')
+ ->willReturn('::1');
+
+ $calls = [
+ ['::1', 'first'],
+ ['::1', 'second'],
+ ];
+ $this->throttler
+ ->expects($this->exactly(2))
+ ->method('sleepDelayOrThrowOnMax')
+ ->willReturnCallback(function () use (&$calls) {
+ $expected = array_shift($calls);
+ $this->assertEquals($expected, func_get_args());
+ return 0;
+ });
+
+ $controller = new TestController('test', $this->request);
+ $this->reflector->reflect($controller, 'multipleAttributes');
+ $this->bruteForceMiddleware->beforeController($controller, 'multipleAttributes');
+ }
+
+ public function testBeforeControllerWithoutAnnotation(): void {
$this->request
->expects($this->never())
->method('getRemoteAddress');
@@ -94,19 +126,14 @@ class BruteForceMiddlewareTest extends TestCase {
->expects($this->never())
->method('sleepDelayOrThrowOnMax');
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
- $controller = $this->createMock(Controller::class);
- $this->bruteForceMiddleware->beforeController($controller, 'testMethod');
+ $controller = new TestController('test', $this->request);
+ $this->reflector->reflect($controller, 'testMethodWithoutAnnotation');
+ $this->bruteForceMiddleware->beforeController($controller, 'testMethodWithoutAnnotation');
}
- public function testAfterControllerWithAnnotationAndThrottledRequest() {
+ public function testAfterControllerWithAnnotationAndThrottledRequest(): void {
/** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */
$response = $this->createMock(Response::class);
- $this->reflector
- ->expects($this->once())
- ->method('hasAnnotation')
- ->with('BruteForceProtection')
- ->willReturn(true);
$response
->expects($this->once())
->method('isThrottled')
@@ -115,79 +142,187 @@ class BruteForceMiddlewareTest extends TestCase {
->expects($this->once())
->method('getThrottleMetadata')
->willReturn([]);
- $this->reflector
- ->expects($this->once())
- ->method('getAnnotationParameter')
- ->with('BruteForceProtection', 'action')
- ->willReturn('login');
$this->request
->expects($this->once())
->method('getRemoteAddress')
->willReturn('127.0.0.1');
$this->throttler
->expects($this->once())
- ->method('sleepDelay')
+ ->method('sleepDelayOrThrowOnMax')
->with('127.0.0.1', 'login');
$this->throttler
->expects($this->once())
->method('registerAttempt')
->with('login', '127.0.0.1');
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
- $controller = $this->createMock(Controller::class);
- $this->bruteForceMiddleware->afterController($controller, 'testMethod', $response);
+ $controller = new TestController('test', $this->request);
+ $this->reflector->reflect($controller, 'testMethodWithAnnotation');
+ $this->bruteForceMiddleware->afterController($controller, 'testMethodWithAnnotation', $response);
}
- public function testAfterControllerWithAnnotationAndNotThrottledRequest() {
+ public function testAfterControllerWithAnnotationAndNotThrottledRequest(): void {
/** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */
$response = $this->createMock(Response::class);
- $this->reflector
- ->expects($this->once())
- ->method('hasAnnotation')
- ->with('BruteForceProtection')
- ->willReturn(true);
$response
->expects($this->once())
->method('isThrottled')
->willReturn(false);
- $this->reflector
- ->expects($this->never())
- ->method('getAnnotationParameter');
$this->request
->expects($this->never())
->method('getRemoteAddress');
$this->throttler
->expects($this->never())
- ->method('sleepDelay');
+ ->method('sleepDelayOrThrowOnMax');
$this->throttler
->expects($this->never())
->method('registerAttempt');
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
- $controller = $this->createMock(Controller::class);
- $this->bruteForceMiddleware->afterController($controller, 'testMethod', $response);
+ $controller = new TestController('test', $this->request);
+ $this->reflector->reflect($controller, 'testMethodWithAnnotation');
+ $this->bruteForceMiddleware->afterController($controller, 'testMethodWithAnnotation', $response);
}
- public function testAfterControllerWithoutAnnotation() {
- $this->reflector
+ public function testAfterControllerWithSingleAttribute(): void {
+ /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */
+ $response = $this->createMock(Response::class);
+ $response
->expects($this->once())
- ->method('hasAnnotation')
- ->with('BruteForceProtection')
- ->willReturn(false);
- $this->reflector
+ ->method('isThrottled')
+ ->willReturn(true);
+ $response
+ ->expects($this->once())
+ ->method('getThrottleMetadata')
+ ->willReturn([]);
+
+ $this->request
+ ->expects($this->once())
+ ->method('getRemoteAddress')
+ ->willReturn('::1');
+ $this->throttler
+ ->expects($this->once())
+ ->method('sleepDelayOrThrowOnMax')
+ ->with('::1', 'single');
+ $this->throttler
+ ->expects($this->once())
+ ->method('registerAttempt')
+ ->with('single', '::1');
+
+ $controller = new TestController('test', $this->request);
+ $this->reflector->reflect($controller, 'singleAttribute');
+ $this->bruteForceMiddleware->afterController($controller, 'singleAttribute', $response);
+ }
+
+ public function testAfterControllerWithMultipleAttributesGeneralMatch(): void {
+ /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */
+ $response = $this->createMock(Response::class);
+ $response
+ ->expects($this->once())
+ ->method('isThrottled')
+ ->willReturn(true);
+ $response
+ ->expects($this->once())
+ ->method('getThrottleMetadata')
+ ->willReturn([]);
+
+ $this->request
+ ->expects($this->once())
+ ->method('getRemoteAddress')
+ ->willReturn('::1');
+
+ $sleepCalls = [
+ ['::1', 'first'],
+ ['::1', 'second'],
+ ];
+ $this->throttler
+ ->expects($this->exactly(2))
+ ->method('sleepDelayOrThrowOnMax')
+ ->willReturnCallback(function () use (&$sleepCalls) {
+ $expected = array_shift($sleepCalls);
+ $this->assertEquals($expected, func_get_args());
+ return 0;
+ });
+
+ $attemptCalls = [
+ ['first', '::1', []],
+ ['second', '::1', []],
+ ];
+ $this->throttler
+ ->expects($this->exactly(2))
+ ->method('registerAttempt')
+ ->willReturnCallback(function () use (&$attemptCalls): void {
+ $expected = array_shift($attemptCalls);
+ $this->assertEquals($expected, func_get_args());
+ });
+
+ $controller = new TestController('test', $this->request);
+ $this->reflector->reflect($controller, 'multipleAttributes');
+ $this->bruteForceMiddleware->afterController($controller, 'multipleAttributes', $response);
+ }
+
+ public function testAfterControllerWithMultipleAttributesSpecificMatch(): void {
+ /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */
+ $response = $this->createMock(Response::class);
+ $response
+ ->expects($this->once())
+ ->method('isThrottled')
+ ->willReturn(true);
+ $response
+ ->expects($this->once())
+ ->method('getThrottleMetadata')
+ ->willReturn(['action' => 'second']);
+
+ $this->request
+ ->expects($this->once())
+ ->method('getRemoteAddress')
+ ->willReturn('::1');
+ $this->throttler
+ ->expects($this->once())
+ ->method('sleepDelayOrThrowOnMax')
+ ->with('::1', 'second');
+ $this->throttler
+ ->expects($this->once())
+ ->method('registerAttempt')
+ ->with('second', '::1');
+
+ $controller = new TestController('test', $this->request);
+ $this->reflector->reflect($controller, 'multipleAttributes');
+ $this->bruteForceMiddleware->afterController($controller, 'multipleAttributes', $response);
+ }
+
+ public function testAfterControllerWithoutAnnotation(): void {
+ $this->request
+ ->expects($this->never())
+ ->method('getRemoteAddress');
+ $this->throttler
->expects($this->never())
- ->method('getAnnotationParameter');
+ ->method('sleepDelayOrThrowOnMax');
+
+ $controller = new TestController('test', $this->request);
+ $this->reflector->reflect($controller, 'testMethodWithoutAnnotation');
+ /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */
+ $response = $this->createMock(Response::class);
+ $this->bruteForceMiddleware->afterController($controller, 'testMethodWithoutAnnotation', $response);
+ }
+
+ public function testAfterControllerWithThrottledResponseButUnhandled(): void {
$this->request
->expects($this->never())
->method('getRemoteAddress');
$this->throttler
->expects($this->never())
- ->method('sleepDelay');
+ ->method('sleepDelayOrThrowOnMax');
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
- $controller = $this->createMock(Controller::class);
+ $controller = new TestController('test', $this->request);
+ $this->reflector->reflect($controller, 'testMethodWithoutAnnotation');
/** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */
$response = $this->createMock(Response::class);
- $this->bruteForceMiddleware->afterController($controller, 'testMethod', $response);
+ $response->method('isThrottled')
+ ->willReturn(true);
+
+ $this->logger->expects($this->once())
+ ->method('debug')
+ ->with('Response for Test\AppFramework\Middleware\Security\TestController::testMethodWithoutAnnotation got bruteforce throttled but has no annotation nor attribute defined.');
+
+ $this->bruteForceMiddleware->afterController($controller, 'testMethodWithoutAnnotation', $response);
}
}
diff --git a/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php
index cc6c74c16c4..c325ae638fb 100644
--- a/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php
@@ -1,51 +1,60 @@
<?php
+
/**
- * ownCloud - App Framework
- *
- * This file is licensed under the Affero General Public License version 3 or
- * later. See the COPYING file.
- *
- * @author Bernhard Posselt <dev@bernhard-posselt.com>
- * @copyright Bernhard Posselt 2014
+ * SPDX-FileCopyrightText: 2016-2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2014-2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace Test\AppFramework\Middleware\Security;
use OC\AppFramework\Http\Request;
use OC\AppFramework\Middleware\Security\CORSMiddleware;
use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
use OC\AppFramework\Utility\ControllerMethodReflector;
-use OC\Security\Bruteforce\Throttler;
+use OC\Authentication\Exceptions\PasswordLoginForbiddenException;
use OC\User\Session;
-use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\IConfig;
+use OCP\IRequest;
use OCP\IRequestId;
+use OCP\Security\Bruteforce\IThrottler;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
+use Test\AppFramework\Middleware\Security\Mock\CORSMiddlewareController;
class CORSMiddlewareTest extends \Test\TestCase {
-
/** @var ControllerMethodReflector */
private $reflector;
- /** @var Session|\PHPUnit\Framework\MockObject\MockObject */
+ /** @var Session|MockObject */
private $session;
- /** @var Throttler */
+ /** @var IThrottler|MockObject */
private $throttler;
- /** @var Controller */
+ /** @var CORSMiddlewareController */
private $controller;
+ private LoggerInterface $logger;
protected function setUp(): void {
parent::setUp();
$this->reflector = new ControllerMethodReflector();
$this->session = $this->createMock(Session::class);
- $this->throttler = $this->createMock(Throttler::class);
- $this->controller = $this->createMock(Controller::class);
+ $this->throttler = $this->createMock(IThrottler::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
+ $this->controller = new CORSMiddlewareController(
+ 'test',
+ $this->createMock(IRequest::class)
+ );
+ }
+
+ public static function dataSetCORSAPIHeader(): array {
+ return [
+ ['testSetCORSAPIHeader'],
+ ['testSetCORSAPIHeaderAttribute'],
+ ];
}
- /**
- * @CORS
- */
- public function testSetCORSAPIHeader() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataSetCORSAPIHeader')]
+ public function testSetCORSAPIHeader(string $method): void {
$request = new Request(
[
'server' => [
@@ -55,16 +64,15 @@ class CORSMiddlewareTest extends \Test\TestCase {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
- $this->reflector->reflect($this, __FUNCTION__);
- $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler);
+ $this->reflector->reflect($this->controller, $method);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger);
- $response = $middleware->afterController($this->controller, __FUNCTION__, new Response());
+ $response = $middleware->afterController($this->controller, $method, new Response());
$headers = $response->getHeaders();
$this->assertEquals('test', $headers['Access-Control-Allow-Origin']);
}
-
- public function testNoAnnotationNoCORSHEADER() {
+ public function testNoAnnotationNoCORSHEADER(): void {
$request = new Request(
[
'server' => [
@@ -74,37 +82,45 @@ class CORSMiddlewareTest extends \Test\TestCase {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
- $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger);
$response = $middleware->afterController($this->controller, __FUNCTION__, new Response());
$headers = $response->getHeaders();
$this->assertFalse(array_key_exists('Access-Control-Allow-Origin', $headers));
}
+ public static function dataNoOriginHeaderNoCORSHEADER(): array {
+ return [
+ ['testNoOriginHeaderNoCORSHEADER'],
+ ['testNoOriginHeaderNoCORSHEADERAttribute'],
+ ];
+ }
- /**
- * @CORS
- */
- public function testNoOriginHeaderNoCORSHEADER() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoOriginHeaderNoCORSHEADER')]
+ public function testNoOriginHeaderNoCORSHEADER(string $method): void {
$request = new Request(
[],
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
- $this->reflector->reflect($this, __FUNCTION__);
- $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler);
+ $this->reflector->reflect($this->controller, $method);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger);
- $response = $middleware->afterController($this->controller, __FUNCTION__, new Response());
+ $response = $middleware->afterController($this->controller, $method, new Response());
$headers = $response->getHeaders();
$this->assertFalse(array_key_exists('Access-Control-Allow-Origin', $headers));
}
+ public static function dataCorsIgnoredIfWithCredentialsHeaderPresent(): array {
+ return [
+ ['testCorsIgnoredIfWithCredentialsHeaderPresent'],
+ ['testCorsAttributeIgnoredIfWithCredentialsHeaderPresent'],
+ ];
+ }
- /**
- * @CORS
- */
- public function testCorsIgnoredIfWithCredentialsHeaderPresent() {
- $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\SecurityException::class);
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataCorsIgnoredIfWithCredentialsHeaderPresent')]
+ public function testCorsIgnoredIfWithCredentialsHeaderPresent(string $method): void {
+ $this->expectException(SecurityException::class);
$request = new Request(
[
@@ -115,41 +131,87 @@ class CORSMiddlewareTest extends \Test\TestCase {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
- $this->reflector->reflect($this, __FUNCTION__);
- $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler);
+ $this->reflector->reflect($this->controller, $method);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger);
$response = new Response();
$response->addHeader('AcCess-control-Allow-Credentials ', 'TRUE');
- $middleware->afterController($this->controller, __FUNCTION__, $response);
+ $middleware->afterController($this->controller, $method, $response);
+ }
+
+ public static function dataNoCORSOnAnonymousPublicPage(): array {
+ return [
+ ['testNoCORSOnAnonymousPublicPage'],
+ ['testNoCORSOnAnonymousPublicPageAttribute'],
+ ['testNoCORSAttributeOnAnonymousPublicPage'],
+ ['testNoCORSAttributeOnAnonymousPublicPageAttribute'],
+ ];
}
- /**
- * @CORS
- * @PublicPage
- */
- public function testNoCORSShouldAllowCookieAuth() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCORSOnAnonymousPublicPage')]
+ public function testNoCORSOnAnonymousPublicPage(string $method): void {
$request = new Request(
[],
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
- $this->reflector->reflect($this, __FUNCTION__);
- $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler);
+ $this->reflector->reflect($this->controller, $method);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger);
+ $this->session->expects($this->once())
+ ->method('isLoggedIn')
+ ->willReturn(false);
$this->session->expects($this->never())
->method('logout');
$this->session->expects($this->never())
->method('logClientIn')
->with($this->equalTo('user'), $this->equalTo('pass'))
->willReturn(true);
- $this->reflector->reflect($this, __FUNCTION__);
+ $this->reflector->reflect($this->controller, $method);
+
+ $middleware->beforeController($this->controller, $method);
+ }
+
+ public static function dataCORSShouldNeverAllowCookieAuth(): array {
+ return [
+ ['testCORSShouldNeverAllowCookieAuth'],
+ ['testCORSShouldNeverAllowCookieAuthAttribute'],
+ ['testCORSAttributeShouldNeverAllowCookieAuth'],
+ ['testCORSAttributeShouldNeverAllowCookieAuthAttribute'],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataCORSShouldNeverAllowCookieAuth')]
+ public function testCORSShouldNeverAllowCookieAuth(string $method): void {
+ $request = new Request(
+ [],
+ $this->createMock(IRequestId::class),
+ $this->createMock(IConfig::class)
+ );
+ $this->reflector->reflect($this->controller, $method);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger);
+ $this->session->expects($this->once())
+ ->method('isLoggedIn')
+ ->willReturn(true);
+ $this->session->expects($this->once())
+ ->method('logout');
+ $this->session->expects($this->never())
+ ->method('logClientIn')
+ ->with($this->equalTo('user'), $this->equalTo('pass'))
+ ->willReturn(true);
+
+ $this->expectException(SecurityException::class);
+ $middleware->beforeController($this->controller, $method);
+ }
- $middleware->beforeController($this->controller, __FUNCTION__);
+ public static function dataCORSShouldRelogin(): array {
+ return [
+ ['testCORSShouldRelogin'],
+ ['testCORSAttributeShouldRelogin'],
+ ];
}
- /**
- * @CORS
- */
- public function testCORSShouldRelogin() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataCORSShouldRelogin')]
+ public function testCORSShouldRelogin(string $method): void {
$request = new Request(
['server' => [
'PHP_AUTH_USER' => 'user',
@@ -164,17 +226,22 @@ class CORSMiddlewareTest extends \Test\TestCase {
->method('logClientIn')
->with($this->equalTo('user'), $this->equalTo('pass'))
->willReturn(true);
- $this->reflector->reflect($this, __FUNCTION__);
- $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler);
+ $this->reflector->reflect($this->controller, $method);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger);
- $middleware->beforeController($this->controller, __FUNCTION__);
+ $middleware->beforeController($this->controller, $method);
}
- /**
- * @CORS
- */
- public function testCORSShouldFailIfPasswordLoginIsForbidden() {
- $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\SecurityException::class);
+ public static function dataCORSShouldFailIfPasswordLoginIsForbidden(): array {
+ return [
+ ['testCORSShouldFailIfPasswordLoginIsForbidden'],
+ ['testCORSAttributeShouldFailIfPasswordLoginIsForbidden'],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataCORSShouldFailIfPasswordLoginIsForbidden')]
+ public function testCORSShouldFailIfPasswordLoginIsForbidden(string $method): void {
+ $this->expectException(SecurityException::class);
$request = new Request(
['server' => [
@@ -189,18 +256,23 @@ class CORSMiddlewareTest extends \Test\TestCase {
$this->session->expects($this->once())
->method('logClientIn')
->with($this->equalTo('user'), $this->equalTo('pass'))
- ->will($this->throwException(new \OC\Authentication\Exceptions\PasswordLoginForbiddenException));
- $this->reflector->reflect($this, __FUNCTION__);
- $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler);
+ ->willThrowException(new PasswordLoginForbiddenException);
+ $this->reflector->reflect($this->controller, $method);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger);
- $middleware->beforeController($this->controller, __FUNCTION__);
+ $middleware->beforeController($this->controller, $method);
}
- /**
- * @CORS
- */
- public function testCORSShouldNotAllowCookieAuth() {
- $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\SecurityException::class);
+ public static function dataCORSShouldNotAllowCookieAuth(): array {
+ return [
+ ['testCORSShouldNotAllowCookieAuth'],
+ ['testCORSAttributeShouldNotAllowCookieAuth'],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataCORSShouldNotAllowCookieAuth')]
+ public function testCORSShouldNotAllowCookieAuth(string $method): void {
+ $this->expectException(SecurityException::class);
$request = new Request(
['server' => [
@@ -216,13 +288,13 @@ class CORSMiddlewareTest extends \Test\TestCase {
->method('logClientIn')
->with($this->equalTo('user'), $this->equalTo('pass'))
->willReturn(false);
- $this->reflector->reflect($this, __FUNCTION__);
- $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler);
+ $this->reflector->reflect($this->controller, $method);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger);
- $middleware->beforeController($this->controller, __FUNCTION__);
+ $middleware->beforeController($this->controller, $method);
}
- public function testAfterExceptionWithSecurityExceptionNoStatus() {
+ public function testAfterExceptionWithSecurityExceptionNoStatus(): void {
$request = new Request(
['server' => [
'PHP_AUTH_USER' => 'user',
@@ -231,14 +303,14 @@ class CORSMiddlewareTest extends \Test\TestCase {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
- $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger);
$response = $middleware->afterException($this->controller, __FUNCTION__, new SecurityException('A security exception'));
$expected = new JSONResponse(['message' => 'A security exception'], 500);
$this->assertEquals($expected, $response);
}
- public function testAfterExceptionWithSecurityExceptionWithStatus() {
+ public function testAfterExceptionWithSecurityExceptionWithStatus(): void {
$request = new Request(
['server' => [
'PHP_AUTH_USER' => 'user',
@@ -247,15 +319,14 @@ class CORSMiddlewareTest extends \Test\TestCase {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
- $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger);
$response = $middleware->afterException($this->controller, __FUNCTION__, new SecurityException('A security exception', 501));
$expected = new JSONResponse(['message' => 'A security exception'], 501);
$this->assertEquals($expected, $response);
}
-
- public function testAfterExceptionWithRegularException() {
+ public function testAfterExceptionWithRegularException(): void {
$this->expectException(\Exception::class);
$this->expectExceptionMessage('A regular exception');
@@ -267,7 +338,7 @@ class CORSMiddlewareTest extends \Test\TestCase {
$this->createMock(IRequestId::class),
$this->createMock(IConfig::class)
);
- $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger);
$middleware->afterException($this->controller, __FUNCTION__, new \Exception('A regular exception'));
}
}
diff --git a/tests/lib/AppFramework/Middleware/Security/CSPMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/CSPMiddlewareTest.php
index 2dfb04e138e..b0b41b27cb9 100644
--- a/tests/lib/AppFramework/Middleware/Security/CSPMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/CSPMiddlewareTest.php
@@ -2,25 +2,8 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware\Security;
@@ -29,24 +12,19 @@ use OC\AppFramework\Middleware\Security\CSPMiddleware;
use OC\Security\CSP\ContentSecurityPolicy;
use OC\Security\CSP\ContentSecurityPolicyManager;
use OC\Security\CSP\ContentSecurityPolicyNonceManager;
-use OC\Security\CSRF\CsrfToken;
-use OC\Security\CSRF\CsrfTokenManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
use OCP\AppFramework\Http\Response;
use PHPUnit\Framework\MockObject\MockObject;
class CSPMiddlewareTest extends \Test\TestCase {
-
- /** @var CSPMiddleware|MockObject */
+ /** @var CSPMiddleware&MockObject */
private $middleware;
- /** @var Controller|MockObject */
+ /** @var Controller&MockObject */
private $controller;
- /** @var ContentSecurityPolicyManager|MockObject */
+ /** @var ContentSecurityPolicyManager&MockObject */
private $contentSecurityPolicyManager;
- /** @var CsrfTokenManager|MockObject */
- private $csrfTokenManager;
- /** @var ContentSecurityPolicyNonceManager|MockObject */
+ /** @var ContentSecurityPolicyNonceManager&MockObject */
private $cspNonceManager;
protected function setUp(): void {
@@ -54,16 +32,14 @@ class CSPMiddlewareTest extends \Test\TestCase {
$this->controller = $this->createMock(Controller::class);
$this->contentSecurityPolicyManager = $this->createMock(ContentSecurityPolicyManager::class);
- $this->csrfTokenManager = $this->createMock(CsrfTokenManager::class);
$this->cspNonceManager = $this->createMock(ContentSecurityPolicyNonceManager::class);
$this->middleware = new CSPMiddleware(
$this->contentSecurityPolicyManager,
$this->cspNonceManager,
- $this->csrfTokenManager
);
}
- public function testAfterController() {
+ public function testAfterController(): void {
$this->cspNonceManager
->expects($this->once())
->method('browserSupportsCspV3')
@@ -95,7 +71,7 @@ class CSPMiddlewareTest extends \Test\TestCase {
$this->middleware->afterController($this->controller, 'test', $response);
}
- public function testAfterControllerEmptyCSP() {
+ public function testAfterControllerEmptyCSP(): void {
$response = $this->createMock(Response::class);
$emptyPolicy = new EmptyContentSecurityPolicy();
$response->expects($this->any())
@@ -107,19 +83,15 @@ class CSPMiddlewareTest extends \Test\TestCase {
$this->middleware->afterController($this->controller, 'test', $response);
}
- public function testAfterControllerWithContentSecurityPolicy3Support() {
+ public function testAfterControllerWithContentSecurityPolicy3Support(): void {
$this->cspNonceManager
->expects($this->once())
->method('browserSupportsCspV3')
->willReturn(true);
- $token = $this->createMock(CsrfToken::class);
- $token
- ->expects($this->once())
- ->method('getEncryptedValue')
- ->willReturn('MyEncryptedToken');
- $this->csrfTokenManager
+ $token = base64_encode('the-nonce');
+ $this->cspNonceManager
->expects($this->once())
- ->method('getToken')
+ ->method('getNonce')
->willReturn($token);
$response = $this->createMock(Response::class);
$defaultPolicy = new ContentSecurityPolicy();
diff --git a/tests/lib/AppFramework/Middleware/Security/FeaturePolicyMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/FeaturePolicyMiddlewareTest.php
index 0a4b3c4f34c..55a70d4c040 100644
--- a/tests/lib/AppFramework/Middleware/Security/FeaturePolicyMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/FeaturePolicyMiddlewareTest.php
@@ -2,25 +2,8 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware\Security;
@@ -34,7 +17,6 @@ use OCP\AppFramework\Http\Response;
use PHPUnit\Framework\MockObject\MockObject;
class FeaturePolicyMiddlewareTest extends \Test\TestCase {
-
/** @var FeaturePolicyMiddleware|MockObject */
private $middleware;
/** @var Controller|MockObject */
@@ -52,7 +34,7 @@ class FeaturePolicyMiddlewareTest extends \Test\TestCase {
);
}
- public function testAfterController() {
+ public function testAfterController(): void {
$response = $this->createMock(Response::class);
$defaultPolicy = new FeaturePolicy();
$defaultPolicy->addAllowedCameraDomain('defaultpolicy');
@@ -74,7 +56,7 @@ class FeaturePolicyMiddlewareTest extends \Test\TestCase {
$this->middleware->afterController($this->controller, 'test', $response);
}
- public function testAfterControllerEmptyCSP() {
+ public function testAfterControllerEmptyCSP(): void {
$response = $this->createMock(Response::class);
$emptyPolicy = new EmptyFeaturePolicy();
$response->method('getFeaturePolicy')
diff --git a/tests/lib/AppFramework/Middleware/Security/Mock/CORSMiddlewareController.php b/tests/lib/AppFramework/Middleware/Security/Mock/CORSMiddlewareController.php
new file mode 100644
index 00000000000..8ab3a48b62e
--- /dev/null
+++ b/tests/lib/AppFramework/Middleware/Security/Mock/CORSMiddlewareController.php
@@ -0,0 +1,145 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace Test\AppFramework\Middleware\Security\Mock;
+
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\CORS;
+use OCP\AppFramework\Http\Attribute\PublicPage;
+
+class CORSMiddlewareController extends Controller {
+ /**
+ * @CORS
+ */
+ public function testSetCORSAPIHeader() {
+ }
+
+ #[CORS]
+ public function testSetCORSAPIHeaderAttribute() {
+ }
+
+ public function testNoAnnotationNoCORSHEADER() {
+ }
+
+ /**
+ * @CORS
+ */
+ public function testNoOriginHeaderNoCORSHEADER() {
+ }
+
+ #[CORS]
+ public function testNoOriginHeaderNoCORSHEADERAttribute() {
+ }
+
+ /**
+ * @CORS
+ */
+ public function testCorsIgnoredIfWithCredentialsHeaderPresent() {
+ }
+
+ #[CORS]
+ public function testCorsAttributeIgnoredIfWithCredentialsHeaderPresent() {
+ }
+
+ /**
+ * CORS must not be enforced for anonymous users on public pages
+ *
+ * @CORS
+ * @PublicPage
+ */
+ public function testNoCORSOnAnonymousPublicPage() {
+ }
+
+ /**
+ * CORS must not be enforced for anonymous users on public pages
+ *
+ * @CORS
+ */
+ #[PublicPage]
+ public function testNoCORSOnAnonymousPublicPageAttribute() {
+ }
+
+ /**
+ * @PublicPage
+ */
+ #[CORS]
+ public function testNoCORSAttributeOnAnonymousPublicPage() {
+ }
+
+ #[CORS]
+ #[PublicPage]
+ public function testNoCORSAttributeOnAnonymousPublicPageAttribute() {
+ }
+
+ /**
+ * @CORS
+ * @PublicPage
+ */
+ public function testCORSShouldNeverAllowCookieAuth() {
+ }
+
+ /**
+ * @CORS
+ */
+ #[PublicPage]
+ public function testCORSShouldNeverAllowCookieAuthAttribute() {
+ }
+
+ /**
+ * @PublicPage
+ */
+ #[CORS]
+ public function testCORSAttributeShouldNeverAllowCookieAuth() {
+ }
+
+ #[CORS]
+ #[PublicPage]
+ public function testCORSAttributeShouldNeverAllowCookieAuthAttribute() {
+ }
+
+ /**
+ * @CORS
+ */
+ public function testCORSShouldRelogin() {
+ }
+
+ #[CORS]
+ public function testCORSAttributeShouldRelogin() {
+ }
+
+ /**
+ * @CORS
+ */
+ public function testCORSShouldFailIfPasswordLoginIsForbidden() {
+ }
+
+ #[CORS]
+ public function testCORSAttributeShouldFailIfPasswordLoginIsForbidden() {
+ }
+
+ /**
+ * @CORS
+ */
+ public function testCORSShouldNotAllowCookieAuth() {
+ }
+
+ #[CORS]
+ public function testCORSAttributeShouldNotAllowCookieAuth() {
+ }
+
+ public function testAfterExceptionWithSecurityExceptionNoStatus() {
+ }
+
+ public function testAfterExceptionWithSecurityExceptionWithStatus() {
+ }
+
+
+ public function testAfterExceptionWithRegularException() {
+ }
+}
diff --git a/tests/lib/AppFramework/Middleware/Security/Mock/NormalController.php b/tests/lib/AppFramework/Middleware/Security/Mock/NormalController.php
new file mode 100644
index 00000000000..4d6778e98b9
--- /dev/null
+++ b/tests/lib/AppFramework/Middleware/Security/Mock/NormalController.php
@@ -0,0 +1,17 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace Test\AppFramework\Middleware\Security\Mock;
+
+use OCP\AppFramework\Controller;
+
+class NormalController extends Controller {
+ public function foo() {
+ }
+}
diff --git a/tests/lib/AppFramework/Middleware/Security/Mock/OCSController.php b/tests/lib/AppFramework/Middleware/Security/Mock/OCSController.php
new file mode 100644
index 00000000000..93e793ecca9
--- /dev/null
+++ b/tests/lib/AppFramework/Middleware/Security/Mock/OCSController.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace Test\AppFramework\Middleware\Security\Mock;
+
+class OCSController extends \OCP\AppFramework\OCSController {
+ public function foo() {
+ }
+}
diff --git a/tests/lib/AppFramework/Middleware/Security/Mock/PasswordConfirmationMiddlewareController.php b/tests/lib/AppFramework/Middleware/Security/Mock/PasswordConfirmationMiddlewareController.php
new file mode 100644
index 00000000000..cd1cdaa49ca
--- /dev/null
+++ b/tests/lib/AppFramework/Middleware/Security/Mock/PasswordConfirmationMiddlewareController.php
@@ -0,0 +1,38 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace Test\AppFramework\Middleware\Security\Mock;
+
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
+
+class PasswordConfirmationMiddlewareController extends Controller {
+ public function testNoAnnotationNorAttribute() {
+ }
+
+ /**
+ * @TestAnnotation
+ */
+ public function testDifferentAnnotation() {
+ }
+
+ /**
+ * @PasswordConfirmationRequired
+ */
+ public function testAnnotation() {
+ }
+
+ #[PasswordConfirmationRequired]
+ public function testAttribute() {
+ }
+
+ #[PasswordConfirmationRequired]
+ public function testSSO() {
+ }
+}
diff --git a/tests/lib/AppFramework/Middleware/Security/Mock/SecurityMiddlewareController.php b/tests/lib/AppFramework/Middleware/Security/Mock/SecurityMiddlewareController.php
new file mode 100644
index 00000000000..c8f9878b0c1
--- /dev/null
+++ b/tests/lib/AppFramework/Middleware/Security/Mock/SecurityMiddlewareController.php
@@ -0,0 +1,171 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace Test\AppFramework\Middleware\Security\Mock;
+
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\ExAppRequired;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
+use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
+use OCP\AppFramework\Http\Attribute\PublicPage;
+use OCP\AppFramework\Http\Attribute\StrictCookiesRequired;
+use OCP\AppFramework\Http\Attribute\SubAdminRequired;
+
+class SecurityMiddlewareController extends Controller {
+ /**
+ * @PublicPage
+ * @NoCSRFRequired
+ */
+ public function testAnnotationNoCSRFRequiredPublicPage() {
+ }
+
+ /**
+ * @NoCSRFRequired
+ */
+ #[PublicPage]
+ public function testAnnotationNoCSRFRequiredAttributePublicPage() {
+ }
+
+ /**
+ * @PublicPage
+ */
+ #[NoCSRFRequired]
+ public function testAnnotationPublicPageAttributeNoCSRFRequired() {
+ }
+
+ #[NoCSRFRequired]
+ #[PublicPage]
+ public function testAttributeNoCSRFRequiredPublicPage() {
+ }
+
+ public function testNoAnnotationNorAttribute() {
+ }
+
+ /**
+ * @NoCSRFRequired
+ */
+ public function testAnnotationNoCSRFRequired() {
+ }
+
+ #[NoCSRFRequired]
+ public function testAttributeNoCSRFRequired() {
+ }
+
+ /**
+ * @PublicPage
+ */
+ public function testAnnotationPublicPage() {
+ }
+
+ #[PublicPage]
+ public function testAttributePublicPage() {
+ }
+
+ /**
+ * @PublicPage
+ * @StrictCookieRequired
+ */
+ public function testAnnotationPublicPageStrictCookieRequired() {
+ }
+
+ /**
+ * @StrictCookieRequired
+ */
+ #[PublicPage]
+ public function testAnnotationStrictCookieRequiredAttributePublicPage() {
+ }
+
+ /**
+ * @PublicPage
+ */
+ #[StrictCookiesRequired]
+ public function testAnnotationPublicPageAttributeStrictCookiesRequired() {
+ }
+
+ #[PublicPage]
+ #[StrictCookiesRequired]
+ public function testAttributePublicPageStrictCookiesRequired() {
+ }
+
+ /**
+ * @PublicPage
+ * @NoCSRFRequired
+ * @StrictCookieRequired
+ */
+ public function testAnnotationNoCSRFRequiredPublicPageStrictCookieRequired() {
+ }
+
+ #[NoCSRFRequired]
+ #[PublicPage]
+ #[StrictCookiesRequired]
+ public function testAttributeNoCSRFRequiredPublicPageStrictCookiesRequired() {
+ }
+
+ /**
+ * @NoCSRFRequired
+ * @NoAdminRequired
+ */
+ public function testAnnotationNoAdminRequiredNoCSRFRequired() {
+ }
+
+ #[NoAdminRequired]
+ #[NoCSRFRequired]
+ public function testAttributeNoAdminRequiredNoCSRFRequired() {
+ }
+
+ /**
+ * @NoCSRFRequired
+ * @SubAdminRequired
+ */
+ public function testAnnotationNoCSRFRequiredSubAdminRequired() {
+ }
+
+ /**
+ * @SubAdminRequired
+ */
+ #[NoCSRFRequired]
+ public function testAnnotationNoCSRFRequiredAttributeSubAdminRequired() {
+ }
+
+ /**
+ * @NoCSRFRequired
+ */
+ #[SubAdminRequired]
+ public function testAnnotationSubAdminRequiredAttributeNoCSRFRequired() {
+ }
+
+ #[NoCSRFRequired]
+ #[SubAdminRequired]
+ public function testAttributeNoCSRFRequiredSubAdminRequired() {
+ }
+
+ /**
+ * @PublicPage
+ * @NoAdminRequired
+ * @NoCSRFRequired
+ */
+ public function testAnnotationNoAdminRequiredNoCSRFRequiredPublicPage() {
+ }
+
+ #[NoAdminRequired]
+ #[NoCSRFRequired]
+ #[PublicPage]
+ public function testAttributeNoAdminRequiredNoCSRFRequiredPublicPage() {
+ }
+
+ /**
+ * @ExAppRequired
+ */
+ public function testAnnotationExAppRequired() {
+ }
+
+ #[ExAppRequired]
+ public function testAttributeExAppRequired() {
+ }
+}
diff --git a/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php
index 3153d7f0b08..90e801ca471 100644
--- a/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php
@@ -1,24 +1,8 @@
<?php
+
/**
- * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware\Security;
@@ -26,74 +10,90 @@ namespace Test\AppFramework\Middleware\Security;
use OC\AppFramework\Middleware\Security\Exceptions\NotConfirmedException;
use OC\AppFramework\Middleware\Security\PasswordConfirmationMiddleware;
use OC\AppFramework\Utility\ControllerMethodReflector;
-use OCP\AppFramework\Controller;
+use OC\Authentication\Token\IProvider;
+use OC\User\Manager;
use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Authentication\Token\IToken;
+use OCP\IRequest;
use OCP\ISession;
use OCP\IUser;
use OCP\IUserSession;
+use Psr\Log\LoggerInterface;
+use Test\AppFramework\Middleware\Security\Mock\PasswordConfirmationMiddlewareController;
use Test\TestCase;
class PasswordConfirmationMiddlewareTest extends TestCase {
/** @var ControllerMethodReflector */
private $reflector;
- /** @var ISession|\PHPUnit\Framework\MockObject\MockObject */
+ /** @var ISession&\PHPUnit\Framework\MockObject\MockObject */
private $session;
- /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
+ /** @var IUserSession&\PHPUnit\Framework\MockObject\MockObject */
private $userSession;
- /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
+ /** @var IUser&\PHPUnit\Framework\MockObject\MockObject */
private $user;
/** @var PasswordConfirmationMiddleware */
private $middleware;
- /** @var Controller */
- private $contoller;
- /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */
+ /** @var PasswordConfirmationMiddlewareController */
+ private $controller;
+ /** @var ITimeFactory&\PHPUnit\Framework\MockObject\MockObject */
private $timeFactory;
+ private IProvider&\PHPUnit\Framework\MockObject\MockObject $tokenProvider;
+ private LoggerInterface $logger;
+ /** @var IRequest&\PHPUnit\Framework\MockObject\MockObject */
+ private IRequest $request;
+ /** @var Manager&\PHPUnit\Framework\MockObject\MockObject */
+ private Manager $userManager;
protected function setUp(): void {
$this->reflector = new ControllerMethodReflector();
$this->session = $this->createMock(ISession::class);
$this->userSession = $this->createMock(IUserSession::class);
$this->user = $this->createMock(IUser::class);
- $this->contoller = $this->createMock(Controller::class);
$this->timeFactory = $this->createMock(ITimeFactory::class);
+ $this->tokenProvider = $this->createMock(IProvider::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
+ $this->request = $this->createMock(IRequest::class);
+ $this->userManager = $this->createMock(Manager::class);
+ $this->controller = new PasswordConfirmationMiddlewareController(
+ 'test',
+ $this->createMock(IRequest::class)
+ );
$this->middleware = new PasswordConfirmationMiddleware(
$this->reflector,
$this->session,
$this->userSession,
- $this->timeFactory
+ $this->timeFactory,
+ $this->tokenProvider,
+ $this->logger,
+ $this->request,
+ $this->userManager,
);
}
- public function testNoAnnotation() {
- $this->reflector->reflect(__CLASS__, __FUNCTION__);
+ public function testNoAnnotationNorAttribute(): void {
+ $this->reflector->reflect($this->controller, __FUNCTION__);
$this->session->expects($this->never())
->method($this->anything());
$this->userSession->expects($this->never())
->method($this->anything());
- $this->middleware->beforeController($this->contoller, __FUNCTION__);
+ $this->middleware->beforeController($this->controller, __FUNCTION__);
}
- /**
- * @TestAnnotation
- */
- public function testDifferentAnnotation() {
- $this->reflector->reflect(__CLASS__, __FUNCTION__);
+ public function testDifferentAnnotation(): void {
+ $this->reflector->reflect($this->controller, __FUNCTION__);
$this->session->expects($this->never())
->method($this->anything());
$this->userSession->expects($this->never())
->method($this->anything());
- $this->middleware->beforeController($this->contoller, __FUNCTION__);
+ $this->middleware->beforeController($this->controller, __FUNCTION__);
}
- /**
- * @PasswordConfirmationRequired
- * @dataProvider dataProvider
- */
- public function testAnnotation($backend, $lastConfirm, $currentTime, $exception) {
- $this->reflector->reflect(__CLASS__, __FUNCTION__);
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataProvider')]
+ public function testAnnotation($backend, $lastConfirm, $currentTime, $exception): void {
+ $this->reflector->reflect($this->controller, __FUNCTION__);
$this->user->method('getBackendClassName')
->willReturn($backend);
@@ -107,9 +107,16 @@ class PasswordConfirmationMiddlewareTest extends TestCase {
$this->timeFactory->method('getTime')
->willReturn($currentTime);
+ $token = $this->createMock(IToken::class);
+ $token->method('getScopeAsArray')
+ ->willReturn([]);
+ $this->tokenProvider->expects($this->once())
+ ->method('getToken')
+ ->willReturn($token);
+
$thrown = false;
try {
- $this->middleware->beforeController($this->contoller, __FUNCTION__);
+ $this->middleware->beforeController($this->controller, __FUNCTION__);
} catch (NotConfirmedException $e) {
$thrown = true;
}
@@ -117,7 +124,42 @@ class PasswordConfirmationMiddlewareTest extends TestCase {
$this->assertSame($exception, $thrown);
}
- public function dataProvider() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataProvider')]
+ public function testAttribute($backend, $lastConfirm, $currentTime, $exception): void {
+ $this->reflector->reflect($this->controller, __FUNCTION__);
+
+ $this->user->method('getBackendClassName')
+ ->willReturn($backend);
+ $this->userSession->method('getUser')
+ ->willReturn($this->user);
+
+ $this->session->method('get')
+ ->with('last-password-confirm')
+ ->willReturn($lastConfirm);
+
+ $this->timeFactory->method('getTime')
+ ->willReturn($currentTime);
+
+ $token = $this->createMock(IToken::class);
+ $token->method('getScopeAsArray')
+ ->willReturn([]);
+ $this->tokenProvider->expects($this->once())
+ ->method('getToken')
+ ->willReturn($token);
+
+ $thrown = false;
+ try {
+ $this->middleware->beforeController($this->controller, __FUNCTION__);
+ } catch (NotConfirmedException $e) {
+ $thrown = true;
+ }
+
+ $this->assertSame($exception, $thrown);
+ }
+
+
+
+ public static function dataProvider(): array {
return [
['foo', 2000, 4000, true],
['foo', 2000, 3000, false],
@@ -127,4 +169,41 @@ class PasswordConfirmationMiddlewareTest extends TestCase {
['foo', 2000, 3816, true],
];
}
+
+ public function testSSO(): void {
+ static $sessionId = 'mySession1d';
+
+ $this->reflector->reflect($this->controller, __FUNCTION__);
+
+ $this->user->method('getBackendClassName')
+ ->willReturn('fictional_backend');
+ $this->userSession->method('getUser')
+ ->willReturn($this->user);
+
+ $this->session->method('get')
+ ->with('last-password-confirm')
+ ->willReturn(0);
+ $this->session->method('getId')
+ ->willReturn($sessionId);
+
+ $this->timeFactory->method('getTime')
+ ->willReturn(9876);
+
+ $token = $this->createMock(IToken::class);
+ $token->method('getScopeAsArray')
+ ->willReturn([IToken::SCOPE_SKIP_PASSWORD_VALIDATION => true]);
+ $this->tokenProvider->expects($this->once())
+ ->method('getToken')
+ ->with($sessionId)
+ ->willReturn($token);
+
+ $thrown = false;
+ try {
+ $this->middleware->beforeController($this->controller, __FUNCTION__);
+ } catch (NotConfirmedException) {
+ $thrown = true;
+ }
+
+ $this->assertSame(false, $thrown);
+ }
}
diff --git a/tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php
index aa713b99156..c42baadcb1c 100644
--- a/tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php
@@ -1,91 +1,113 @@
<?php
+
+declare(strict_types=1);
+
/**
- * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware\Security;
use OC\AppFramework\Middleware\Security\RateLimitingMiddleware;
use OC\AppFramework\Utility\ControllerMethodReflector;
+use OC\Security\Ip\BruteforceAllowList;
use OC\Security\RateLimiting\Exception\RateLimitExceededException;
use OC\Security\RateLimiting\Limiter;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\AnonRateLimit;
+use OCP\AppFramework\Http\Attribute\UserRateLimit;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\TemplateResponse;
+use OCP\IAppConfig;
use OCP\IRequest;
+use OCP\ISession;
use OCP\IUser;
use OCP\IUserSession;
+use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
+class TestRateLimitController extends Controller {
+ /**
+ * @UserRateThrottle(limit=20, period=200)
+ * @AnonRateThrottle(limit=10, period=100)
+ */
+ public function testMethodWithAnnotation() {
+ }
+
+ /**
+ * @AnonRateThrottle(limit=10, period=100)
+ */
+ public function testMethodWithAnnotationFallback() {
+ }
+
+ public function testMethodWithoutAnnotation() {
+ }
+
+ #[UserRateLimit(limit: 20, period: 200)]
+ #[AnonRateLimit(limit: 10, period: 100)]
+ public function testMethodWithAttributes() {
+ }
+
+ #[AnonRateLimit(limit: 10, period: 100)]
+ public function testMethodWithAttributesFallback() {
+ }
+}
+
/**
* @group DB
*/
class RateLimitingMiddlewareTest extends TestCase {
- /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */
- private $request;
- /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
- private $userSession;
- /** @var ControllerMethodReflector|\PHPUnit\Framework\MockObject\MockObject */
- private $reflector;
- /** @var Limiter|\PHPUnit\Framework\MockObject\MockObject */
- private $limiter;
- /** @var RateLimitingMiddleware */
- private $rateLimitingMiddleware;
+ private IRequest|MockObject $request;
+ private IUserSession|MockObject $userSession;
+ private ControllerMethodReflector $reflector;
+ private Limiter|MockObject $limiter;
+ private ISession|MockObject $session;
+ private IAppConfig|MockObject $appConfig;
+ private BruteforceAllowList|MockObject $bruteForceAllowList;
+ private RateLimitingMiddleware $rateLimitingMiddleware;
protected function setUp(): void {
parent::setUp();
$this->request = $this->createMock(IRequest::class);
$this->userSession = $this->createMock(IUserSession::class);
- $this->reflector = $this->createMock(ControllerMethodReflector::class);
+ $this->reflector = new ControllerMethodReflector();
$this->limiter = $this->createMock(Limiter::class);
+ $this->session = $this->createMock(ISession::class);
+ $this->appConfig = $this->createMock(IAppConfig::class);
+ $this->bruteForceAllowList = $this->createMock(BruteforceAllowList::class);
$this->rateLimitingMiddleware = new RateLimitingMiddleware(
$this->request,
$this->userSession,
$this->reflector,
- $this->limiter
+ $this->limiter,
+ $this->session,
+ $this->appConfig,
+ $this->bruteForceAllowList,
);
}
- public function testBeforeControllerWithoutAnnotation() {
- $this->reflector
- ->expects($this->at(0))
- ->method('getAnnotationParameter')
- ->with('AnonRateThrottle', 'limit')
- ->willReturn('');
- $this->reflector
- ->expects($this->at(1))
- ->method('getAnnotationParameter')
- ->with('AnonRateThrottle', 'period')
- ->willReturn('');
- $this->reflector
- ->expects($this->at(2))
- ->method('getAnnotationParameter')
- ->with('UserRateThrottle', 'limit')
- ->willReturn('');
- $this->reflector
- ->expects($this->at(3))
- ->method('getAnnotationParameter')
- ->with('UserRateThrottle', 'period')
- ->willReturn('');
+ public function testBeforeControllerWithoutAnnotationForAnon(): void {
+ $this->limiter
+ ->expects($this->never())
+ ->method('registerUserRequest');
+ $this->limiter
+ ->expects($this->never())
+ ->method('registerAnonRequest');
+
+ $this->userSession->expects($this->once())
+ ->method('isLoggedIn')
+ ->willReturn(false);
+
+ /** @var TestRateLimitController|MockObject $controller */
+ $controller = $this->createMock(TestRateLimitController::class);
+ $this->reflector->reflect($controller, 'testMethodWithoutAnnotation');
+ $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithoutAnnotation');
+ }
+ public function testBeforeControllerWithoutAnnotationForLoggedIn(): void {
$this->limiter
->expects($this->never())
->method('registerUserRequest');
@@ -93,39 +115,79 @@ class RateLimitingMiddlewareTest extends TestCase {
->expects($this->never())
->method('registerAnonRequest');
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
- $controller = $this->createMock(Controller::class);
- $this->rateLimitingMiddleware->beforeController($controller, 'testMethod');
+ $this->userSession->expects($this->once())
+ ->method('isLoggedIn')
+ ->willReturn(true);
+
+ /** @var TestRateLimitController|MockObject $controller */
+ $controller = $this->createMock(TestRateLimitController::class);
+ $this->reflector->reflect($controller, 'testMethodWithoutAnnotation');
+ $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithoutAnnotation');
+ }
+
+ public function testBeforeControllerForAnon(): void {
+ $controller = new TestRateLimitController('test', $this->request);
+
+ $this->request
+ ->method('getRemoteAddress')
+ ->willReturn('127.0.0.1');
+
+ $this->userSession
+ ->expects($this->once())
+ ->method('isLoggedIn')
+ ->willReturn(false);
+
+ $this->limiter
+ ->expects($this->never())
+ ->method('registerUserRequest');
+ $this->limiter
+ ->expects($this->once())
+ ->method('registerAnonRequest')
+ ->with(get_class($controller) . '::testMethodWithAnnotation', '10', '100', '127.0.0.1');
+
+ $this->reflector->reflect($controller, 'testMethodWithAnnotation');
+ $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithAnnotation');
+ }
+
+ public function testBeforeControllerForLoggedIn(): void {
+ $controller = new TestRateLimitController('test', $this->request);
+ /** @var IUser|MockObject $user */
+ $user = $this->createMock(IUser::class);
+
+ $this->userSession
+ ->expects($this->once())
+ ->method('isLoggedIn')
+ ->willReturn(true);
+ $this->userSession
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($user);
+
+ $this->limiter
+ ->expects($this->never())
+ ->method('registerAnonRequest');
+ $this->limiter
+ ->expects($this->once())
+ ->method('registerUserRequest')
+ ->with(get_class($controller) . '::testMethodWithAnnotation', '20', '200', $user);
+
+
+ $this->reflector->reflect($controller, 'testMethodWithAnnotation');
+ $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithAnnotation');
}
- public function testBeforeControllerForAnon() {
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
- $controller = $this->createMock(Controller::class);
+ public function testBeforeControllerAnonWithFallback(): void {
+ $controller = new TestRateLimitController('test', $this->request);
$this->request
->expects($this->once())
->method('getRemoteAddress')
->willReturn('127.0.0.1');
- $this->reflector
- ->expects($this->at(0))
- ->method('getAnnotationParameter')
- ->with('AnonRateThrottle', 'limit')
- ->willReturn('100');
- $this->reflector
- ->expects($this->at(1))
- ->method('getAnnotationParameter')
- ->with('AnonRateThrottle', 'period')
- ->willReturn('10');
- $this->reflector
- ->expects($this->at(2))
- ->method('getAnnotationParameter')
- ->with('UserRateThrottle', 'limit')
- ->willReturn('');
- $this->reflector
- ->expects($this->at(3))
- ->method('getAnnotationParameter')
- ->with('UserRateThrottle', 'period')
- ->willReturn('');
+ $this->userSession
+ ->expects($this->once())
+ ->method('isLoggedIn')
+ ->willReturn(true);
+
$this->limiter
->expects($this->never())
@@ -133,16 +195,39 @@ class RateLimitingMiddlewareTest extends TestCase {
$this->limiter
->expects($this->once())
->method('registerAnonRequest')
- ->with(get_class($controller) . '::testMethod', '100', '10', '127.0.0.1');
+ ->with(get_class($controller) . '::testMethodWithAnnotationFallback', '10', '100', '127.0.0.1');
+
+ $this->reflector->reflect($controller, 'testMethodWithAnnotationFallback');
+ $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithAnnotationFallback');
+ }
+
+ public function testBeforeControllerAttributesForAnon(): void {
+ $controller = new TestRateLimitController('test', $this->request);
+
+ $this->request
+ ->method('getRemoteAddress')
+ ->willReturn('127.0.0.1');
+ $this->userSession
+ ->expects($this->once())
+ ->method('isLoggedIn')
+ ->willReturn(false);
- $this->rateLimitingMiddleware->beforeController($controller, 'testMethod');
+ $this->limiter
+ ->expects($this->never())
+ ->method('registerUserRequest');
+ $this->limiter
+ ->expects($this->once())
+ ->method('registerAnonRequest')
+ ->with(get_class($controller) . '::testMethodWithAttributes', '10', '100', '127.0.0.1');
+
+ $this->reflector->reflect($controller, 'testMethodWithAttributes');
+ $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithAttributes');
}
- public function testBeforeControllerForLoggedIn() {
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
- $controller = $this->createMock(Controller::class);
- /** @var IUser|\PHPUnit\Framework\MockObject\MockObject $user */
+ public function testBeforeControllerAttributesForLoggedIn(): void {
+ $controller = new TestRateLimitController('test', $this->request);
+ /** @var IUser|MockObject $user */
$user = $this->createMock(IUser::class);
$this->userSession
@@ -154,42 +239,21 @@ class RateLimitingMiddlewareTest extends TestCase {
->method('getUser')
->willReturn($user);
- $this->reflector
- ->expects($this->at(0))
- ->method('getAnnotationParameter')
- ->with('AnonRateThrottle', 'limit')
- ->willReturn('');
- $this->reflector
- ->expects($this->at(1))
- ->method('getAnnotationParameter')
- ->with('AnonRateThrottle', 'period')
- ->willReturn('');
- $this->reflector
- ->expects($this->at(2))
- ->method('getAnnotationParameter')
- ->with('UserRateThrottle', 'limit')
- ->willReturn('100');
- $this->reflector
- ->expects($this->at(3))
- ->method('getAnnotationParameter')
- ->with('UserRateThrottle', 'period')
- ->willReturn('10');
-
$this->limiter
->expects($this->never())
->method('registerAnonRequest');
$this->limiter
->expects($this->once())
->method('registerUserRequest')
- ->with(get_class($controller) . '::testMethod', '100', '10', $user);
+ ->with(get_class($controller) . '::testMethodWithAttributes', '20', '200', $user);
- $this->rateLimitingMiddleware->beforeController($controller, 'testMethod');
+ $this->reflector->reflect($controller, 'testMethodWithAttributes');
+ $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithAttributes');
}
- public function testBeforeControllerAnonWithFallback() {
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
- $controller = $this->createMock(Controller::class);
+ public function testBeforeControllerAttributesAnonWithFallback(): void {
+ $controller = new TestRateLimitController('test', $this->request);
$this->request
->expects($this->once())
->method('getRemoteAddress')
@@ -198,28 +262,8 @@ class RateLimitingMiddlewareTest extends TestCase {
$this->userSession
->expects($this->once())
->method('isLoggedIn')
- ->willReturn(false);
+ ->willReturn(true);
- $this->reflector
- ->expects($this->at(0))
- ->method('getAnnotationParameter')
- ->with('AnonRateThrottle', 'limit')
- ->willReturn('200');
- $this->reflector
- ->expects($this->at(1))
- ->method('getAnnotationParameter')
- ->with('AnonRateThrottle', 'period')
- ->willReturn('20');
- $this->reflector
- ->expects($this->at(2))
- ->method('getAnnotationParameter')
- ->with('UserRateThrottle', 'limit')
- ->willReturn('100');
- $this->reflector
- ->expects($this->at(3))
- ->method('getAnnotationParameter')
- ->with('UserRateThrottle', 'period')
- ->willReturn('10');
$this->limiter
->expects($this->never())
@@ -227,25 +271,23 @@ class RateLimitingMiddlewareTest extends TestCase {
$this->limiter
->expects($this->once())
->method('registerAnonRequest')
- ->with(get_class($controller) . '::testMethod', '200', '20', '127.0.0.1');
+ ->with(get_class($controller) . '::testMethodWithAttributesFallback', '10', '100', '127.0.0.1');
- $this->rateLimitingMiddleware->beforeController($controller, 'testMethod');
+ $this->reflector->reflect($controller, 'testMethodWithAttributesFallback');
+ $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithAttributesFallback');
}
-
- public function testAfterExceptionWithOtherException() {
+ public function testAfterExceptionWithOtherException(): void {
$this->expectException(\Exception::class);
$this->expectExceptionMessage('My test exception');
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
- $controller = $this->createMock(Controller::class);
+ $controller = new TestRateLimitController('test', $this->request);
$this->rateLimitingMiddleware->afterException($controller, 'testMethod', new \Exception('My test exception'));
}
- public function testAfterExceptionWithJsonBody() {
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
- $controller = $this->createMock(Controller::class);
+ public function testAfterExceptionWithJsonBody(): void {
+ $controller = new TestRateLimitController('test', $this->request);
$this->request
->expects($this->once())
->method('getHeader')
@@ -258,9 +300,8 @@ class RateLimitingMiddlewareTest extends TestCase {
$this->assertEquals($expected, $result);
}
- public function testAfterExceptionWithHtmlBody() {
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */
- $controller = $this->createMock(Controller::class);
+ public function testAfterExceptionWithHtmlBody(): void {
+ $controller = new TestRateLimitController('test', $this->request);
$this->request
->expects($this->once())
->method('getHeader')
diff --git a/tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.php
index 61f5eeb5aea..7800371f68f 100644
--- a/tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.php
@@ -1,24 +1,8 @@
<?php
+
/**
- * @copyright 2017, Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test\AppFramework\Middleware\Security;
@@ -33,7 +17,6 @@ use OCP\AppFramework\Http;
use Test\TestCase;
class SameSiteCookieMiddlewareTest extends TestCase {
-
/** @var SameSiteCookieMiddleware */
private $middleware;
@@ -51,7 +34,7 @@ class SameSiteCookieMiddlewareTest extends TestCase {
$this->middleware = new SameSiteCookieMiddleware($this->request, $this->reflector);
}
- public function testBeforeControllerNoIndex() {
+ public function testBeforeControllerNoIndex(): void {
$this->request->method('getScriptName')
->willReturn('/ocs/v2.php');
@@ -59,7 +42,7 @@ class SameSiteCookieMiddlewareTest extends TestCase {
$this->addToAssertionCount(1);
}
- public function testBeforeControllerIndexHasAnnotation() {
+ public function testBeforeControllerIndexHasAnnotation(): void {
$this->request->method('getScriptName')
->willReturn('/index.php');
@@ -71,7 +54,7 @@ class SameSiteCookieMiddlewareTest extends TestCase {
$this->addToAssertionCount(1);
}
- public function testBeforeControllerIndexNoAnnotationPassingCheck() {
+ public function testBeforeControllerIndexNoAnnotationPassingCheck(): void {
$this->request->method('getScriptName')
->willReturn('/index.php');
@@ -86,7 +69,7 @@ class SameSiteCookieMiddlewareTest extends TestCase {
$this->addToAssertionCount(1);
}
- public function testBeforeControllerIndexNoAnnotationFailingCheck() {
+ public function testBeforeControllerIndexNoAnnotationFailingCheck(): void {
$this->expectException(LaxSameSiteCookieFailedException::class);
$this->request->method('getScriptName')
@@ -102,7 +85,7 @@ class SameSiteCookieMiddlewareTest extends TestCase {
$this->middleware->beforeController($this->createMock(Controller::class), 'foo');
}
- public function testAfterExceptionNoLaxCookie() {
+ public function testAfterExceptionNoLaxCookie(): void {
$ex = new SecurityException();
try {
@@ -113,7 +96,7 @@ class SameSiteCookieMiddlewareTest extends TestCase {
}
}
- public function testAfterExceptionLaxCookie() {
+ public function testAfterExceptionLaxCookie(): void {
$ex = new LaxSameSiteCookieFailedException();
$this->request->method('getRequestUri')
@@ -121,7 +104,7 @@ class SameSiteCookieMiddlewareTest extends TestCase {
$middleware = $this->getMockBuilder(SameSiteCookieMiddleware::class)
->setConstructorArgs([$this->request, $this->reflector])
- ->setMethods(['setSameSiteCookie'])
+ ->onlyMethods(['setSameSiteCookie'])
->getMock();
$middleware->expects($this->once())
diff --git a/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php
index 276ebe8f9ac..0c6fc21357d 100644
--- a/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php
@@ -1,23 +1,9 @@
<?php
+
/**
- * @author Bernhard Posselt <dev@bernhard-posselt.com>
- * @author Lukas Reschke <lukas@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace Test\AppFramework\Middleware\Security;
@@ -26,6 +12,7 @@ use OC\AppFramework\Http;
use OC\AppFramework\Http\Request;
use OC\AppFramework\Middleware\Security\Exceptions\AppNotEnabledException;
use OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException;
+use OC\AppFramework\Middleware\Security\Exceptions\ExAppRequiredException;
use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException;
use OC\AppFramework\Middleware\Security\Exceptions\NotLoggedInException;
use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
@@ -33,25 +20,32 @@ use OC\Appframework\Middleware\Security\Exceptions\StrictCookieMissingException;
use OC\AppFramework\Middleware\Security\SecurityMiddleware;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OC\Settings\AuthorizedGroupMapper;
+use OC\User\Session;
use OCP\App\IAppManager;
-use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\TemplateResponse;
+use OCP\Group\ISubAdmin;
use OCP\IConfig;
+use OCP\IGroupManager;
use OCP\IL10N;
use OCP\INavigationManager;
use OCP\IRequest;
use OCP\IRequestId;
+use OCP\ISession;
use OCP\IURLGenerator;
+use OCP\IUser;
use OCP\IUserSession;
+use OCP\Security\Ip\IRemoteAddress;
use Psr\Log\LoggerInterface;
+use Test\AppFramework\Middleware\Security\Mock\NormalController;
+use Test\AppFramework\Middleware\Security\Mock\OCSController;
+use Test\AppFramework\Middleware\Security\Mock\SecurityMiddlewareController;
class SecurityMiddlewareTest extends \Test\TestCase {
-
/** @var SecurityMiddleware|\PHPUnit\Framework\MockObject\MockObject */
private $middleware;
- /** @var Controller|\PHPUnit\Framework\MockObject\MockObject */
+ /** @var SecurityMiddlewareController */
private $controller;
/** @var SecurityException */
private $secException;
@@ -80,13 +74,19 @@ class SecurityMiddlewareTest extends \Test\TestCase {
parent::setUp();
$this->authorizedGroupMapper = $this->createMock(AuthorizedGroupMapper::class);
- $this->userSession = $this->createMock(IUserSession::class);
- $this->controller = $this->createMock(Controller::class);
+ $this->userSession = $this->createMock(Session::class);
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')->willReturn('test');
+ $this->userSession->method('getUser')->willReturn($user);
+ $this->request = $this->createMock(IRequest::class);
+ $this->controller = new SecurityMiddlewareController(
+ 'test',
+ $this->request
+ );
$this->reader = new ControllerMethodReflector();
$this->logger = $this->createMock(LoggerInterface::class);
$this->navigationManager = $this->createMock(INavigationManager::class);
$this->urlGenerator = $this->createMock(IURLGenerator::class);
- $this->request = $this->createMock(IRequest::class);
$this->l10n = $this->createMock(IL10N::class);
$this->middleware = $this->getMiddleware(true, true, false);
$this->secException = new SecurityException('hey', false);
@@ -98,6 +98,15 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$this->appManager->expects($this->any())
->method('isEnabledForUser')
->willReturn($isAppEnabledForUser);
+ $remoteIpAddress = $this->createMock(IRemoteAddress::class);
+ $remoteIpAddress->method('allowsAdminActions')->willReturn(true);
+
+ $groupManager = $this->createMock(IGroupManager::class);
+ $groupManager->method('isAdmin')
+ ->willReturn($isAdminUser);
+ $subAdminManager = $this->createMock(ISubAdmin::class);
+ $subAdminManager->method('isSubAdmin')
+ ->willReturn($isSubAdmin);
return new SecurityMiddleware(
$this->request,
@@ -107,27 +116,93 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$this->logger,
'files',
$isLoggedIn,
- $isAdminUser,
- $isSubAdmin,
+ $groupManager,
+ $subAdminManager,
$this->appManager,
$this->l10n,
$this->authorizedGroupMapper,
- $this->userSession
+ $this->userSession,
+ $remoteIpAddress
);
}
+ public static function dataNoCSRFRequiredPublicPage(): array {
+ return [
+ ['testAnnotationNoCSRFRequiredPublicPage'],
+ ['testAnnotationNoCSRFRequiredAttributePublicPage'],
+ ['testAnnotationPublicPageAttributeNoCSRFRequired'],
+ ['testAttributeNoCSRFRequiredPublicPage'],
+ ];
+ }
- /**
- * @PublicPage
- * @NoCSRFRequired
- */
- public function testSetNavigationEntry() {
+ public static function dataPublicPage(): array {
+ return [
+ ['testAnnotationPublicPage'],
+ ['testAttributePublicPage'],
+ ];
+ }
+
+ public static function dataNoCSRFRequired(): array {
+ return [
+ ['testAnnotationNoCSRFRequired'],
+ ['testAttributeNoCSRFRequired'],
+ ];
+ }
+
+ public static function dataPublicPageStrictCookieRequired(): array {
+ return [
+ ['testAnnotationPublicPageStrictCookieRequired'],
+ ['testAnnotationStrictCookieRequiredAttributePublicPage'],
+ ['testAnnotationPublicPageAttributeStrictCookiesRequired'],
+ ['testAttributePublicPageStrictCookiesRequired'],
+ ];
+ }
+
+ public static function dataNoCSRFRequiredPublicPageStrictCookieRequired(): array {
+ return [
+ ['testAnnotationNoCSRFRequiredPublicPageStrictCookieRequired'],
+ ['testAttributeNoCSRFRequiredPublicPageStrictCookiesRequired'],
+ ];
+ }
+
+ public static function dataNoAdminRequiredNoCSRFRequired(): array {
+ return [
+ ['testAnnotationNoAdminRequiredNoCSRFRequired'],
+ ['testAttributeNoAdminRequiredNoCSRFRequired'],
+ ];
+ }
+
+ public static function dataNoAdminRequiredNoCSRFRequiredPublicPage(): array {
+ return [
+ ['testAnnotationNoAdminRequiredNoCSRFRequiredPublicPage'],
+ ['testAttributeNoAdminRequiredNoCSRFRequiredPublicPage'],
+ ];
+ }
+
+ public static function dataNoCSRFRequiredSubAdminRequired(): array {
+ return [
+ ['testAnnotationNoCSRFRequiredSubAdminRequired'],
+ ['testAnnotationNoCSRFRequiredAttributeSubAdminRequired'],
+ ['testAnnotationSubAdminRequiredAttributeNoCSRFRequired'],
+ ['testAttributeNoCSRFRequiredSubAdminRequired'],
+ ];
+ }
+
+ public static function dataExAppRequired(): array {
+ return [
+ ['testAnnotationExAppRequired'],
+ ['testAttributeExAppRequired'],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredPublicPage')]
+ public function testSetNavigationEntry(string $method): void {
$this->navigationManager->expects($this->once())
->method('setActiveEntry')
->with($this->equalTo('files'));
- $this->reader->reflect(__CLASS__, __FUNCTION__);
- $this->middleware->beforeController($this->controller, __FUNCTION__);
+ $this->reader->reflect($this->controller, $method);
+ $this->middleware->beforeController($this->controller, $method);
}
@@ -147,7 +222,7 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$sec = $this->getMiddleware($isLoggedIn, $isAdminUser, false);
try {
- $this->reader->reflect(__CLASS__, $method);
+ $this->reader->reflect($this->controller, $method);
$sec->beforeController($this->controller, $method);
} catch (SecurityException $ex) {
$this->assertEquals($status, $ex->getCode());
@@ -160,75 +235,63 @@ class SecurityMiddlewareTest extends \Test\TestCase {
}
}
- public function testAjaxStatusLoggedInCheck() {
+ public function testAjaxStatusLoggedInCheck(): void {
$this->ajaxExceptionStatus(
- __FUNCTION__,
+ 'testNoAnnotationNorAttribute',
'isLoggedIn',
Http::STATUS_UNAUTHORIZED
);
}
- /**
- * @NoCSRFRequired
- */
- public function testAjaxNotAdminCheck() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequired')]
+ public function testAjaxNotAdminCheck(string $method): void {
$this->ajaxExceptionStatus(
- __FUNCTION__,
+ $method,
'isAdminUser',
Http::STATUS_FORBIDDEN
);
}
- /**
- * @PublicPage
- */
- public function testAjaxStatusCSRFCheck() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataPublicPage')]
+ public function testAjaxStatusCSRFCheck(string $method): void {
$this->ajaxExceptionStatus(
- __FUNCTION__,
+ $method,
'passesCSRFCheck',
Http::STATUS_PRECONDITION_FAILED
);
}
- /**
- * @PublicPage
- * @NoCSRFRequired
- */
- public function testAjaxStatusAllGood() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredPublicPage')]
+ public function testAjaxStatusAllGood(string $method): void {
$this->ajaxExceptionStatus(
- __FUNCTION__,
+ $method,
'isLoggedIn',
0
);
$this->ajaxExceptionStatus(
- __FUNCTION__,
+ $method,
'isAdminUser',
0
);
$this->ajaxExceptionStatus(
- __FUNCTION__,
+ $method,
'passesCSRFCheck',
0
);
}
-
- /**
- * @PublicPage
- * @NoCSRFRequired
- */
- public function testNoChecks() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredPublicPage')]
+ public function testNoChecks(string $method): void {
$this->request->expects($this->never())
->method('passesCSRFCheck')
->willReturn(false);
$sec = $this->getMiddleware(false, false, false);
- $this->reader->reflect(__CLASS__, __FUNCTION__);
- $sec->beforeController($this->controller, __FUNCTION__);
+ $this->reader->reflect($this->controller, $method);
+ $sec->beforeController($this->controller, $method);
}
-
/**
* @param string $method
* @param string $expects
@@ -251,16 +314,14 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$this->addToAssertionCount(1);
}
- $this->reader->reflect(__CLASS__, $method);
+ $this->reader->reflect($this->controller, $method);
$sec->beforeController($this->controller, $method);
}
- /**
- * @PublicPage
- */
- public function testCsrfCheck() {
- $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException::class);
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataPublicPage')]
+ public function testCsrfCheck(string $method): void {
+ $this->expectException(CrossSiteRequestForgeryException::class);
$this->request->expects($this->once())
->method('passesCSRFCheck')
@@ -268,28 +329,22 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$this->request->expects($this->once())
->method('passesStrictCookieCheck')
->willReturn(true);
- $this->reader->reflect(__CLASS__, __FUNCTION__);
- $this->middleware->beforeController($this->controller, __FUNCTION__);
+ $this->reader->reflect($this->controller, $method);
+ $this->middleware->beforeController($this->controller, $method);
}
-
- /**
- * @PublicPage
- * @NoCSRFRequired
- */
- public function testNoCsrfCheck() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredPublicPage')]
+ public function testNoCsrfCheck(string $method): void {
$this->request->expects($this->never())
->method('passesCSRFCheck')
->willReturn(false);
- $this->reader->reflect(__CLASS__, __FUNCTION__);
- $this->middleware->beforeController($this->controller, __FUNCTION__);
+ $this->reader->reflect($this->controller, $method);
+ $this->middleware->beforeController($this->controller, $method);
}
- /**
- * @PublicPage
- */
- public function testPassesCsrfCheck() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataPublicPage')]
+ public function testPassesCsrfCheck(string $method): void {
$this->request->expects($this->once())
->method('passesCSRFCheck')
->willReturn(true);
@@ -297,15 +352,13 @@ class SecurityMiddlewareTest extends \Test\TestCase {
->method('passesStrictCookieCheck')
->willReturn(true);
- $this->reader->reflect(__CLASS__, __FUNCTION__);
- $this->middleware->beforeController($this->controller, __FUNCTION__);
+ $this->reader->reflect($this->controller, $method);
+ $this->middleware->beforeController($this->controller, $method);
}
- /**
- * @PublicPage
- */
- public function testFailCsrfCheck() {
- $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException::class);
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataPublicPage')]
+ public function testFailCsrfCheck(string $method): void {
+ $this->expectException(CrossSiteRequestForgeryException::class);
$this->request->expects($this->once())
->method('passesCSRFCheck')
@@ -314,16 +367,13 @@ class SecurityMiddlewareTest extends \Test\TestCase {
->method('passesStrictCookieCheck')
->willReturn(true);
- $this->reader->reflect(__CLASS__, __FUNCTION__);
- $this->middleware->beforeController($this->controller, __FUNCTION__);
+ $this->reader->reflect($this->controller, $method);
+ $this->middleware->beforeController($this->controller, $method);
}
- /**
- * @PublicPage
- * @StrictCookieRequired
- */
- public function testStrictCookieRequiredCheck() {
- $this->expectException(\OC\Appframework\Middleware\Security\Exceptions\StrictCookieMissingException::class);
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataPublicPageStrictCookieRequired')]
+ public function testStrictCookieRequiredCheck(string $method): void {
+ $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\StrictCookieMissingException::class);
$this->request->expects($this->never())
->method('passesCSRFCheck');
@@ -331,68 +381,53 @@ class SecurityMiddlewareTest extends \Test\TestCase {
->method('passesStrictCookieCheck')
->willReturn(false);
- $this->reader->reflect(__CLASS__, __FUNCTION__);
- $this->middleware->beforeController($this->controller, __FUNCTION__);
+ $this->reader->reflect($this->controller, $method);
+ $this->middleware->beforeController($this->controller, $method);
}
-
- /**
- * @PublicPage
- * @NoCSRFRequired
- */
- public function testNoStrictCookieRequiredCheck() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredPublicPage')]
+ public function testNoStrictCookieRequiredCheck(string $method): void {
$this->request->expects($this->never())
->method('passesStrictCookieCheck')
->willReturn(false);
- $this->reader->reflect(__CLASS__, __FUNCTION__);
- $this->middleware->beforeController($this->controller, __FUNCTION__);
+ $this->reader->reflect($this->controller, $method);
+ $this->middleware->beforeController($this->controller, $method);
}
- /**
- * @PublicPage
- * @NoCSRFRequired
- * @StrictCookieRequired
- */
- public function testPassesStrictCookieRequiredCheck() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredPublicPageStrictCookieRequired')]
+ public function testPassesStrictCookieRequiredCheck(string $method): void {
$this->request
->expects($this->once())
->method('passesStrictCookieCheck')
->willReturn(true);
- $this->reader->reflect(__CLASS__, __FUNCTION__);
- $this->middleware->beforeController($this->controller, __FUNCTION__);
+ $this->reader->reflect($this->controller, $method);
+ $this->middleware->beforeController($this->controller, $method);
}
- public function dataCsrfOcsController() {
- $controller = $this->getMockBuilder('OCP\AppFramework\Controller')
- ->disableOriginalConstructor()
- ->getMock();
- $ocsController = $this->getMockBuilder('OCP\AppFramework\OCSController')
- ->disableOriginalConstructor()
- ->getMock();
-
+ public static function dataCsrfOcsController(): array {
return [
- [$controller, false, false, true],
- [$controller, false, true, true],
- [$controller, true, false, true],
- [$controller, true, true, true],
-
- [$ocsController, false, false, true],
- [$ocsController, false, true, false],
- [$ocsController, true, false, false],
- [$ocsController, true, true, false],
+ [NormalController::class, false, false, true],
+ [NormalController::class, false, true, true],
+ [NormalController::class, true, false, true],
+ [NormalController::class, true, true, true],
+
+ [OCSController::class, false, false, true],
+ [OCSController::class, false, true, false],
+ [OCSController::class, true, false, false],
+ [OCSController::class, true, true, false],
];
}
/**
- * @dataProvider dataCsrfOcsController
- * @param Controller $controller
+ * @param string $controllerClass
* @param bool $hasOcsApiHeader
* @param bool $hasBearerAuth
* @param bool $exception
*/
- public function testCsrfOcsController(Controller $controller, bool $hasOcsApiHeader, bool $hasBearerAuth, bool $exception) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataCsrfOcsController')]
+ public function testCsrfOcsController(string $controllerClass, bool $hasOcsApiHeader, bool $hasBearerAuth, bool $exception): void {
$this->request
->method('getHeader')
->willReturnCallback(function ($header) use ($hasOcsApiHeader, $hasBearerAuth) {
@@ -408,6 +443,8 @@ class SecurityMiddlewareTest extends \Test\TestCase {
->method('passesStrictCookieCheck')
->willReturn(true);
+ $controller = new $controllerClass('test', $this->request);
+
try {
$this->middleware->beforeController($controller, 'foo');
$this->assertFalse($exception);
@@ -416,86 +453,112 @@ class SecurityMiddlewareTest extends \Test\TestCase {
}
}
- /**
- * @NoCSRFRequired
- * @NoAdminRequired
- */
- public function testLoggedInCheck() {
- $this->securityCheck(__FUNCTION__, 'isLoggedIn');
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoAdminRequiredNoCSRFRequired')]
+ public function testLoggedInCheck(string $method): void {
+ $this->securityCheck($method, 'isLoggedIn');
}
-
- /**
- * @NoCSRFRequired
- * @NoAdminRequired
- */
- public function testFailLoggedInCheck() {
- $this->securityCheck(__FUNCTION__, 'isLoggedIn', true);
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoAdminRequiredNoCSRFRequired')]
+ public function testFailLoggedInCheck(string $method): void {
+ $this->securityCheck($method, 'isLoggedIn', true);
}
-
- /**
- * @NoCSRFRequired
- */
- public function testIsAdminCheck() {
- $this->securityCheck(__FUNCTION__, 'isAdminUser');
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequired')]
+ public function testIsAdminCheck(string $method): void {
+ $this->securityCheck($method, 'isAdminUser');
}
- /**
- * @NoCSRFRequired
- * @SubAdminRequired
- */
- public function testIsNotSubAdminCheck() {
- $this->reader->reflect(__CLASS__, __FUNCTION__);
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredSubAdminRequired')]
+ public function testIsNotSubAdminCheck(string $method): void {
+ $this->reader->reflect($this->controller, $method);
$sec = $this->getMiddleware(true, false, false);
$this->expectException(SecurityException::class);
- $sec->beforeController($this, __METHOD__);
+ $sec->beforeController($this->controller, $method);
}
- /**
- * @NoCSRFRequired
- * @SubAdminRequired
- */
- public function testIsSubAdminCheck() {
- $this->reader->reflect(__CLASS__, __FUNCTION__);
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredSubAdminRequired')]
+ public function testIsSubAdminCheck(string $method): void {
+ $this->reader->reflect($this->controller, $method);
$sec = $this->getMiddleware(true, false, true);
- $sec->beforeController($this, __METHOD__);
+ $sec->beforeController($this->controller, $method);
$this->addToAssertionCount(1);
}
- /**
- * @NoCSRFRequired
- * @SubAdminRequired
- */
- public function testIsSubAdminAndAdminCheck() {
- $this->reader->reflect(__CLASS__, __FUNCTION__);
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredSubAdminRequired')]
+ public function testIsSubAdminAndAdminCheck(string $method): void {
+ $this->reader->reflect($this->controller, $method);
$sec = $this->getMiddleware(true, true, true);
- $sec->beforeController($this, __METHOD__);
+ $sec->beforeController($this->controller, $method);
$this->addToAssertionCount(1);
}
- /**
- * @NoCSRFRequired
- */
- public function testFailIsAdminCheck() {
- $this->securityCheck(__FUNCTION__, 'isAdminUser', true);
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequired')]
+ public function testFailIsAdminCheck(string $method): void {
+ $this->securityCheck($method, 'isAdminUser', true);
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoAdminRequiredNoCSRFRequiredPublicPage')]
+ public function testRestrictedAppLoggedInPublicPage(string $method): void {
+ $middleware = $this->getMiddleware(true, false, false);
+ $this->reader->reflect($this->controller, $method);
+
+ $this->appManager->method('getAppPath')
+ ->with('files')
+ ->willReturn('foo');
+
+ $this->appManager->method('isEnabledForUser')
+ ->with('files')
+ ->willReturn(false);
+
+ $middleware->beforeController($this->controller, $method);
+ $this->addToAssertionCount(1);
}
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoAdminRequiredNoCSRFRequiredPublicPage')]
+ public function testRestrictedAppNotLoggedInPublicPage(string $method): void {
+ $middleware = $this->getMiddleware(false, false, false);
+ $this->reader->reflect($this->controller, $method);
+
+ $this->appManager->method('getAppPath')
+ ->with('files')
+ ->willReturn('foo');
+
+ $this->appManager->method('isEnabledForUser')
+ ->with('files')
+ ->willReturn(false);
+
+ $middleware->beforeController($this->controller, $method);
+ $this->addToAssertionCount(1);
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNoAdminRequiredNoCSRFRequired')]
+ public function testRestrictedAppLoggedIn(string $method): void {
+ $middleware = $this->getMiddleware(true, false, false, false);
+ $this->reader->reflect($this->controller, $method);
+
+ $this->appManager->method('getAppPath')
+ ->with('files')
+ ->willReturn('foo');
+
+ $this->expectException(AppNotEnabledException::class);
+ $middleware->beforeController($this->controller, $method);
+ }
- public function testAfterExceptionNotCaughtThrowsItAgain() {
+
+ public function testAfterExceptionNotCaughtThrowsItAgain(): void {
$ex = new \Exception();
$this->expectException(\Exception::class);
$this->middleware->afterException($this->controller, 'test', $ex);
}
- public function testAfterExceptionReturnsRedirectForNotLoggedInUser() {
+ public function testAfterExceptionReturnsRedirectForNotLoggedInUser(): void {
$this->request = new Request(
[
- 'server' =>
- [
+ 'server'
+ => [
'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'REQUEST_URI' => 'nextcloud/index.php/apps/specialapp'
]
@@ -526,7 +589,7 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$this->assertEquals($expected, $response);
}
- public function testAfterExceptionRedirectsToWebRootAfterStrictCookieFail() {
+ public function testAfterExceptionRedirectsToWebRootAfterStrictCookieFail(): void {
$this->request = new Request(
[
'server' => [
@@ -553,7 +616,7 @@ class SecurityMiddlewareTest extends \Test\TestCase {
/**
* @return array
*/
- public function exceptionProvider() {
+ public static function exceptionProvider(): array {
return [
[
new AppNotEnabledException(),
@@ -568,14 +631,14 @@ class SecurityMiddlewareTest extends \Test\TestCase {
}
/**
- * @dataProvider exceptionProvider
* @param SecurityException $exception
*/
- public function testAfterExceptionReturnsTemplateResponse(SecurityException $exception) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('exceptionProvider')]
+ public function testAfterExceptionReturnsTemplateResponse(SecurityException $exception): void {
$this->request = new Request(
[
- 'server' =>
- [
+ 'server'
+ => [
'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'REQUEST_URI' => 'nextcloud/index.php/apps/specialapp'
]
@@ -597,81 +660,42 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$this->assertEquals($expected, $response);
}
- public function testAfterAjaxExceptionReturnsJSONError() {
+ public function testAfterAjaxExceptionReturnsJSONError(): void {
$response = $this->middleware->afterException($this->controller, 'test',
$this->secAjaxException);
$this->assertTrue($response instanceof JSONResponse);
}
- public function dataRestrictedApp() {
- return [
- [false, false, false,],
- [false, false, true,],
- [false, true, false,],
- [false, true, true,],
- [ true, false, false,],
- [ true, false, true,],
- [ true, true, false,],
- [ true, true, true,],
- ];
- }
-
- /**
- * @PublicPage
- * @NoAdminRequired
- * @NoCSRFRequired
- */
- public function testRestrictedAppLoggedInPublicPage() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataExAppRequired')]
+ public function testExAppRequired(string $method): void {
$middleware = $this->getMiddleware(true, false, false);
- $this->reader->reflect(__CLASS__, __FUNCTION__);
-
- $this->appManager->method('getAppPath')
- ->with('files')
- ->willReturn('foo');
+ $this->reader->reflect($this->controller, $method);
- $this->appManager->method('isEnabledForUser')
- ->with('files')
- ->willReturn(false);
-
- $middleware->beforeController($this->controller, __FUNCTION__);
- $this->addToAssertionCount(1);
- }
-
- /**
- * @PublicPage
- * @NoAdminRequired
- * @NoCSRFRequired
- */
- public function testRestrictedAppNotLoggedInPublicPage() {
- $middleware = $this->getMiddleware(false, false, false);
- $this->reader->reflect(__CLASS__, __FUNCTION__);
+ $session = $this->createMock(ISession::class);
+ $session->method('get')->with('app_api')->willReturn(true);
+ $this->userSession->method('getSession')->willReturn($session);
- $this->appManager->method('getAppPath')
- ->with('files')
- ->willReturn('foo');
-
- $this->appManager->method('isEnabledForUser')
- ->with('files')
- ->willReturn(false);
+ $this->request->expects($this->once())
+ ->method('passesStrictCookieCheck')
+ ->willReturn(true);
+ $this->request->expects($this->once())
+ ->method('passesCSRFCheck')
+ ->willReturn(true);
- $middleware->beforeController($this->controller, __FUNCTION__);
- $this->addToAssertionCount(1);
+ $middleware->beforeController($this->controller, $method);
}
- /**
- * @NoAdminRequired
- * @NoCSRFRequired
- */
- public function testRestrictedAppLoggedIn() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataExAppRequired')]
+ public function testExAppRequiredError(string $method): void {
$middleware = $this->getMiddleware(true, false, false, false);
- $this->reader->reflect(__CLASS__, __FUNCTION__);
+ $this->reader->reflect($this->controller, $method);
- $this->appManager->method('getAppPath')
- ->with('files')
- ->willReturn('foo');
+ $session = $this->createMock(ISession::class);
+ $session->method('get')->with('app_api')->willReturn(false);
+ $this->userSession->method('getSession')->willReturn($session);
- $this->expectException(AppNotEnabledException::class);
- $middleware->beforeController($this->controller, __FUNCTION__);
+ $this->expectException(ExAppRequiredException::class);
+ $middleware->beforeController($this->controller, $method);
}
}
diff --git a/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php b/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php
index f9739044465..8ecc73791c9 100644
--- a/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php
@@ -1,84 +1,138 @@
<?php
+
+declare(strict_types=1);
/**
- * ownCloud - App Framework
- *
- * This file is licensed under the Affero General Public License version 3 or
- * later. See the COPYING file.
- *
- * @author Thomas Müller <deepdiver@owncloud.com>
- * @copyright Thomas Müller 2014
+ * SPDX-FileCopyrightText: 2016-2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace Test\AppFramework\Middleware;
use OC\AppFramework\Middleware\SessionMiddleware;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\Response;
+use OCP\IRequest;
+use OCP\ISession;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
-class SessionMiddlewareTest extends \Test\TestCase {
-
- /** @var ControllerMethodReflector */
- private $reflector;
-
- /** @var Controller */
- private $controller;
+class SessionMiddlewareTest extends TestCase {
+ private ControllerMethodReflector|MockObject $reflector;
+ private ISession|MockObject $session;
+ private Controller $controller;
+ private SessionMiddleware $middleware;
protected function setUp(): void {
parent::setUp();
- $this->reflector = new ControllerMethodReflector();
- $this->controller = $this->createMock(Controller::class);
+ $this->reflector = $this->createMock(ControllerMethodReflector::class);
+ $this->session = $this->createMock(ISession::class);
+ $this->controller = new class('app', $this->createMock(IRequest::class)) extends Controller {
+ /**
+ * @UseSession
+ */
+ public function withAnnotation() {
+ }
+ #[UseSession]
+ public function withAttribute() {
+ }
+ public function without() {
+ }
+ };
+ $this->middleware = new SessionMiddleware(
+ $this->reflector,
+ $this->session,
+ );
}
- /**
- * @UseSession
- */
- public function testSessionNotClosedOnBeforeController() {
- $session = $this->getSessionMock(0);
+ public function testSessionNotClosedOnBeforeController(): void {
+ $this->configureSessionMock(0, 1);
+ $this->reflector->expects(self::once())
+ ->method('hasAnnotation')
+ ->with('UseSession')
+ ->willReturn(true);
- $this->reflector->reflect($this, __FUNCTION__);
- $middleware = new SessionMiddleware($this->reflector, $session);
- $middleware->beforeController($this->controller, __FUNCTION__);
+ $this->middleware->beforeController($this->controller, 'withAnnotation');
}
- /**
- * @UseSession
- */
- public function testSessionClosedOnAfterController() {
- $session = $this->getSessionMock(1);
+ public function testSessionNotClosedOnBeforeControllerWithAttribute(): void {
+ $this->configureSessionMock(0, 1);
+ $this->reflector->expects(self::once())
+ ->method('hasAnnotation')
+ ->with('UseSession')
+ ->willReturn(false);
- $this->reflector->reflect($this, __FUNCTION__);
- $middleware = new SessionMiddleware($this->reflector, $session);
- $middleware->afterController($this->controller, __FUNCTION__, new Response());
+ $this->middleware->beforeController($this->controller, 'withAttribute');
}
- public function testSessionClosedOnBeforeController() {
- $session = $this->getSessionMock(1);
+ public function testSessionClosedOnAfterController(): void {
+ $this->configureSessionMock(1);
+ $this->reflector->expects(self::once())
+ ->method('hasAnnotation')
+ ->with('UseSession')
+ ->willReturn(true);
- $this->reflector->reflect($this, __FUNCTION__);
- $middleware = new SessionMiddleware($this->reflector, $session);
- $middleware->beforeController($this->controller, __FUNCTION__);
+ $this->middleware->afterController($this->controller, 'withAnnotation', new Response());
}
- public function testSessionNotClosedOnAfterController() {
- $session = $this->getSessionMock(0);
+ public function testSessionClosedOnAfterControllerWithAttribute(): void {
+ $this->configureSessionMock(1);
+ $this->reflector->expects(self::once())
+ ->method('hasAnnotation')
+ ->with('UseSession')
+ ->willReturn(true);
- $this->reflector->reflect($this, __FUNCTION__);
- $middleware = new SessionMiddleware($this->reflector, $session);
- $middleware->afterController($this->controller, __FUNCTION__, new Response());
+ $this->middleware->afterController($this->controller, 'withAttribute', new Response());
}
- /**
- * @return mixed
- */
- private function getSessionMock($expectedCloseCount) {
- $session = $this->getMockBuilder('\OC\Session\Memory')
- ->disableOriginalConstructor()
- ->getMock();
+ public function testSessionReopenedAndClosedOnBeforeController(): void {
+ $this->configureSessionMock(1, 1);
+ $this->reflector->expects(self::exactly(2))
+ ->method('hasAnnotation')
+ ->with('UseSession')
+ ->willReturn(true);
+
+ $this->middleware->beforeController($this->controller, 'withAnnotation');
+ $this->middleware->afterController($this->controller, 'withAnnotation', new Response());
+ }
+
+ public function testSessionReopenedAndClosedOnBeforeControllerWithAttribute(): void {
+ $this->configureSessionMock(1, 1);
+ $this->reflector->expects(self::exactly(2))
+ ->method('hasAnnotation')
+ ->with('UseSession')
+ ->willReturn(false);
+
+ $this->middleware->beforeController($this->controller, 'withAttribute');
+ $this->middleware->afterController($this->controller, 'withAttribute', new Response());
+ }
+
+ public function testSessionClosedOnBeforeController(): void {
+ $this->configureSessionMock(0);
+ $this->reflector->expects(self::once())
+ ->method('hasAnnotation')
+ ->with('UseSession')
+ ->willReturn(false);
+
+ $this->middleware->beforeController($this->controller, 'without');
+ }
+
+ public function testSessionNotClosedOnAfterController(): void {
+ $this->configureSessionMock(0);
+ $this->reflector->expects(self::once())
+ ->method('hasAnnotation')
+ ->with('UseSession')
+ ->willReturn(false);
+
+ $this->middleware->afterController($this->controller, 'without', new Response());
+ }
- $session->expects($this->exactly($expectedCloseCount))
+ private function configureSessionMock(int $expectedCloseCount, int $expectedReopenCount = 0): void {
+ $this->session->expects($this->exactly($expectedCloseCount))
->method('close');
- return $session;
+ $this->session->expects($this->exactly($expectedReopenCount))
+ ->method('reopen');
}
}