diff options
Diffstat (limited to 'tests/lib/Security')
32 files changed, 929 insertions, 954 deletions
diff --git a/tests/lib/Security/Bruteforce/Backend/MemoryCacheBackendTest.php b/tests/lib/Security/Bruteforce/Backend/MemoryCacheBackendTest.php new file mode 100644 index 00000000000..e0289fa7ca9 --- /dev/null +++ b/tests/lib/Security/Bruteforce/Backend/MemoryCacheBackendTest.php @@ -0,0 +1,137 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Security\Bruteforce\Backend; + +use OC\Security\Bruteforce\Backend\IBackend; +use OC\Security\Bruteforce\Backend\MemoryCacheBackend; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\ICache; +use OCP\ICacheFactory; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +class MemoryCacheBackendTest extends TestCase { + /** @var ICacheFactory|MockObject */ + private $cacheFactory; + /** @var ITimeFactory|MockObject */ + private $timeFactory; + /** @var ICache|MockObject */ + private $cache; + private IBackend $backend; + + protected function setUp(): void { + parent::setUp(); + + $this->cacheFactory = $this->createMock(ICacheFactory::class); + $this->timeFactory = $this->createMock(ITimeFactory::class); + $this->cache = $this->createMock(ICache::class); + + $this->cacheFactory + ->expects($this->once()) + ->method('createDistributed') + ->with(MemoryCacheBackend::class) + ->willReturn($this->cache); + + $this->backend = new MemoryCacheBackend( + $this->cacheFactory, + $this->timeFactory + ); + } + + public function testGetAttemptsWithNoAttemptsBefore(): void { + $this->cache + ->expects($this->once()) + ->method('get') + ->with('8b9da631d1f7b022bb2c3c489e16092f82b42fd4') + ->willReturn(null); + + $this->assertSame(0, $this->backend->getAttempts('10.10.10.10/32', 0)); + } + + public static function dataGetAttempts(): array { + return [ + [0, null, null, 4], + [100, null, null, 2], + [0, 'action1', null, 2], + [100, 'action1', null, 1], + [0, 'action1', ['metadata2'], 1], + [100, 'action1', ['metadata2'], 1], + [100, 'action1', ['metadata1'], 0], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetAttempts')] + public function testGetAttempts(int $maxAge, ?string $action, ?array $metadata, int $expected): void { + $this->cache + ->expects($this->once()) + ->method('get') + ->with('8b9da631d1f7b022bb2c3c489e16092f82b42fd4') + ->willReturn(json_encode([ + '1' . '#' . hash('sha1', 'action1') . '#' . hash('sha1', json_encode(['metadata1'])), + '300' . '#' . hash('sha1', 'action1') . '#' . hash('sha1', json_encode(['metadata2'])), + '1' . '#' . hash('sha1', 'action2') . '#' . hash('sha1', json_encode(['metadata1'])), + '300' . '#' . hash('sha1', 'action2') . '#' . hash('sha1', json_encode(['metadata2'])), + ])); + + $this->assertSame($expected, $this->backend->getAttempts('10.10.10.10/32', $maxAge, $action, $metadata)); + } + + public function testRegisterAttemptWithNoAttemptsBefore(): void { + $this->cache + ->expects($this->once()) + ->method('get') + ->with('8b9da631d1f7b022bb2c3c489e16092f82b42fd4') + ->willReturn(null); + $this->cache + ->expects($this->once()) + ->method('set') + ->with( + '8b9da631d1f7b022bb2c3c489e16092f82b42fd4', + json_encode(['223#' . hash('sha1', 'action1') . '#' . hash('sha1', json_encode(['metadata1']))]) + ); + + $this->backend->registerAttempt('10.10.10.10', '10.10.10.10/32', 223, 'action1', ['metadata1']); + } + + public function testRegisterAttempt(): void { + $this->timeFactory + ->expects($this->once()) + ->method('getTime') + ->willReturn(12 * 3600 + 86); + + $this->cache + ->expects($this->once()) + ->method('get') + ->with('8b9da631d1f7b022bb2c3c489e16092f82b42fd4') + ->willReturn(json_encode([ + '1#' . hash('sha1', 'action1') . '#' . hash('sha1', json_encode(['metadata1'])), + '2#' . hash('sha1', 'action2') . '#' . hash('sha1', json_encode(['metadata1'])), + '87#' . hash('sha1', 'action3') . '#' . hash('sha1', json_encode(['metadata1'])), + '123#' . hash('sha1', 'action4') . '#' . hash('sha1', json_encode(['metadata1'])), + '123#' . hash('sha1', 'action5') . '#' . hash('sha1', json_encode(['metadata1'])), + '124#' . hash('sha1', 'action6') . '#' . hash('sha1', json_encode(['metadata1'])), + ])); + $this->cache + ->expects($this->once()) + ->method('set') + ->with( + '8b9da631d1f7b022bb2c3c489e16092f82b42fd4', + json_encode([ + '87#' . hash('sha1', 'action3') . '#' . hash('sha1', json_encode(['metadata1'])), + '123#' . hash('sha1', 'action4') . '#' . hash('sha1', json_encode(['metadata1'])), + '123#' . hash('sha1', 'action5') . '#' . hash('sha1', json_encode(['metadata1'])), + '124#' . hash('sha1', 'action6') . '#' . hash('sha1', json_encode(['metadata1'])), + '186#' . hash('sha1', 'action7') . '#' . hash('sha1', json_encode(['metadata2'])), + ]) + ); + + $this->backend->registerAttempt('10.10.10.10', '10.10.10.10/32', 186, 'action7', ['metadata2']); + } +} diff --git a/tests/lib/Security/Bruteforce/CapabilitiesTest.php b/tests/lib/Security/Bruteforce/CapabilitiesTest.php index 1c2bbb6bc53..438a24f2240 100644 --- a/tests/lib/Security/Bruteforce/CapabilitiesTest.php +++ b/tests/lib/Security/Bruteforce/CapabilitiesTest.php @@ -3,30 +3,15 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2017 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\Security\Bruteforce; use OC\Security\Bruteforce\Capabilities; -use OC\Security\Bruteforce\Throttler; use OCP\IRequest; +use OCP\Security\Bruteforce\IThrottler; use Test\TestCase; class CapabilitiesTest extends TestCase { @@ -36,7 +21,7 @@ class CapabilitiesTest extends TestCase { /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ private $request; - /** @var Throttler|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IThrottler|\PHPUnit\Framework\MockObject\MockObject */ private $throttler; protected function setUp(): void { @@ -44,7 +29,7 @@ class CapabilitiesTest extends TestCase { $this->request = $this->createMock(IRequest::class); - $this->throttler = $this->createMock(Throttler::class); + $this->throttler = $this->createMock(IThrottler::class); $this->capabilities = new Capabilities( $this->request, @@ -52,18 +37,24 @@ class CapabilitiesTest extends TestCase { ); } - public function testGetCapabilities() { + public function testGetCapabilities(): void { $this->throttler->expects($this->atLeastOnce()) ->method('getDelay') ->with('10.10.10.10') ->willReturn(42); + $this->throttler->expects($this->atLeastOnce()) + ->method('isBypassListed') + ->with('10.10.10.10') + ->willReturn(true); + $this->request->method('getRemoteAddress') ->willReturn('10.10.10.10'); $expected = [ 'bruteforce' => [ - 'delay' => 42 + 'delay' => 42, + 'allow-listed' => true, ] ]; $result = $this->capabilities->getCapabilities(); @@ -71,7 +62,7 @@ class CapabilitiesTest extends TestCase { $this->assertEquals($expected, $result); } - public function testGetCapabilitiesOnCli() { + public function testGetCapabilitiesOnCli(): void { $this->throttler->expects($this->atLeastOnce()) ->method('getDelay') ->with('') @@ -82,7 +73,8 @@ class CapabilitiesTest extends TestCase { $expected = [ 'bruteforce' => [ - 'delay' => 0 + 'delay' => 0, + 'allow-listed' => false, ] ]; $result = $this->capabilities->getCapabilities(); diff --git a/tests/lib/Security/Bruteforce/ThrottlerTest.php b/tests/lib/Security/Bruteforce/ThrottlerTest.php deleted file mode 100644 index 6639f884ae1..00000000000 --- a/tests/lib/Security/Bruteforce/ThrottlerTest.php +++ /dev/null @@ -1,242 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright Copyright (c) 2016 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/>. - * - */ - -namespace Test\Security\Bruteforce; - -use OC\AppFramework\Utility\TimeFactory; -use OC\Security\Bruteforce\Throttler; -use OCP\IConfig; -use OCP\IDBConnection; -use Psr\Log\LoggerInterface; -use Test\TestCase; - -/** - * Based on the unit tests from Paragonie's Airship CMS - * Ref: https://github.com/paragonie/airship/blob/7e5bad7e3c0fbbf324c11f963fd1f80e59762606/test/unit/Engine/Security/AirBrakeTest.php - * - * @package Test\Security\Bruteforce - */ -class ThrottlerTest extends TestCase { - /** @var Throttler */ - private $throttler; - /** @var IDBConnection */ - private $dbConnection; - /** @var LoggerInterface */ - private $logger; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - private $config; - - protected function setUp(): void { - $this->dbConnection = $this->createMock(IDBConnection::class); - $this->logger = $this->createMock(LoggerInterface::class); - $this->config = $this->createMock(IConfig::class); - - $this->throttler = new Throttler( - $this->dbConnection, - new TimeFactory(), - $this->logger, - $this->config - ); - parent::setUp(); - } - - public function testCutoff() { - // precisely 31 second shy of 12 hours - $cutoff = self::invokePrivate($this->throttler, 'getCutoff', [43169]); - $this->assertSame(0, $cutoff->y); - $this->assertSame(0, $cutoff->m); - $this->assertSame(0, $cutoff->d); - $this->assertSame(11, $cutoff->h); - $this->assertSame(59, $cutoff->i); - $this->assertSame(29, $cutoff->s); - $cutoff = self::invokePrivate($this->throttler, 'getCutoff', [86401]); - $this->assertSame(0, $cutoff->y); - $this->assertSame(0, $cutoff->m); - $this->assertSame(1, $cutoff->d); - $this->assertSame(0, $cutoff->h); - $this->assertSame(0, $cutoff->i); - // Leap second tolerance: - $this->assertLessThan(2, $cutoff->s); - } - - public function dataIsIPWhitelisted() { - return [ - [ - '10.10.10.10', - [ - 'whitelist_0' => '10.10.10.0/24', - ], - true, - ], - [ - '10.10.10.10', - [ - 'whitelist_0' => '192.168.0.0/16', - ], - false, - ], - [ - '10.10.10.10', - [ - 'whitelist_0' => '192.168.0.0/16', - 'whitelist_1' => '10.10.10.0/24', - ], - true, - ], - [ - '10.10.10.10', - [ - 'whitelist_0' => '10.10.10.11/31', - ], - true, - ], - [ - '10.10.10.10', - [ - 'whitelist_0' => '10.10.10.9/31', - ], - false, - ], - [ - '10.10.10.10', - [ - 'whitelist_0' => '10.10.10.15/29', - ], - true, - ], - [ - 'dead:beef:cafe::1', - [ - 'whitelist_0' => '192.168.0.0/16', - 'whitelist_1' => '10.10.10.0/24', - 'whitelist_2' => 'deaf:beef:cafe:1234::/64' - ], - false, - ], - [ - 'dead:beef:cafe::1', - [ - 'whitelist_0' => '192.168.0.0/16', - 'whitelist_1' => '10.10.10.0/24', - 'whitelist_2' => 'deaf:beef::/64' - ], - false, - ], - [ - 'dead:beef:cafe::1', - [ - 'whitelist_0' => '192.168.0.0/16', - 'whitelist_1' => '10.10.10.0/24', - 'whitelist_2' => 'deaf:cafe::/8' - ], - true, - ], - [ - 'dead:beef:cafe::1111', - [ - 'whitelist_0' => 'dead:beef:cafe::1100/123', - - ], - true, - ], - [ - 'invalid', - [], - false, - ], - ]; - } - - /** - * @param string $ip - * @param string[] $whitelists - * @param bool $isWhiteListed - * @param bool $enabled - */ - private function isIpWhiteListedHelper($ip, - $whitelists, - $isWhiteListed, - $enabled) { - $this->config->method('getAppKeys') - ->with($this->equalTo('bruteForce')) - ->willReturn(array_keys($whitelists)); - $this->config - ->expects($this->once()) - ->method('getSystemValue') - ->with('auth.bruteforce.protection.enabled', true) - ->willReturn($enabled); - - $this->config->method('getAppValue') - ->willReturnCallback(function ($app, $key, $default) use ($whitelists) { - if ($app !== 'bruteForce') { - return $default; - } - if (isset($whitelists[$key])) { - return $whitelists[$key]; - } - return $default; - }); - - $this->assertSame( - ($enabled === false) ? true : $isWhiteListed, - self::invokePrivate($this->throttler, 'isIPWhitelisted', [$ip]) - ); - } - - /** - * @dataProvider dataIsIPWhitelisted - * - * @param string $ip - * @param string[] $whitelists - * @param bool $isWhiteListed - */ - public function testIsIpWhiteListedWithEnabledProtection($ip, - $whitelists, - $isWhiteListed) { - $this->isIpWhiteListedHelper( - $ip, - $whitelists, - $isWhiteListed, - true - ); - } - - /** - * @dataProvider dataIsIPWhitelisted - * - * @param string $ip - * @param string[] $whitelists - * @param bool $isWhiteListed - */ - public function testIsIpWhiteListedWithDisabledProtection($ip, - $whitelists, - $isWhiteListed) { - $this->isIpWhiteListedHelper( - $ip, - $whitelists, - $isWhiteListed, - false - ); - } -} diff --git a/tests/lib/Security/CSP/AddContentSecurityPolicyEventTest.php b/tests/lib/Security/CSP/AddContentSecurityPolicyEventTest.php index 7de4665ec58..39dd7a95890 100644 --- a/tests/lib/Security/CSP/AddContentSecurityPolicyEventTest.php +++ b/tests/lib/Security/CSP/AddContentSecurityPolicyEventTest.php @@ -3,25 +3,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\Security\CSP; @@ -32,7 +15,7 @@ use OCP\Security\CSP\AddContentSecurityPolicyEvent; use Test\TestCase; class AddContentSecurityPolicyEventTest extends TestCase { - public function testAddEvent() { + public function testAddEvent(): void { $cspManager = $this->createMock(ContentSecurityPolicyManager::class); $policy = $this->createMock(ContentSecurityPolicy::class); $event = new AddContentSecurityPolicyEvent($cspManager); diff --git a/tests/lib/Security/CSP/ContentSecurityPolicyManagerTest.php b/tests/lib/Security/CSP/ContentSecurityPolicyManagerTest.php index 082ef46330d..a32a4132287 100644 --- a/tests/lib/Security/CSP/ContentSecurityPolicyManagerTest.php +++ b/tests/lib/Security/CSP/ContentSecurityPolicyManagerTest.php @@ -3,35 +3,23 @@ declare(strict_types=1); /** - * @author Lukas Reschke <lukas@owncloud.com> - * - * @copyright Copyright (c) 2016, 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: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace Test\Security\CSP; use OC\Security\CSP\ContentSecurityPolicyManager; +use OCP\AppFramework\Http\ContentSecurityPolicy; +use OCP\AppFramework\Http\EmptyContentSecurityPolicy; use OCP\EventDispatcher\IEventDispatcher; use OCP\Security\CSP\AddContentSecurityPolicyEvent; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use OCP\Server; use Test\TestCase; class ContentSecurityPolicyManagerTest extends TestCase { - /** @var EventDispatcherInterface */ + /** @var IEventDispatcher */ private $dispatcher; /** @var ContentSecurityPolicyManager */ @@ -39,34 +27,32 @@ class ContentSecurityPolicyManagerTest extends TestCase { protected function setUp(): void { parent::setUp(); - $this->dispatcher = \OC::$server->query(IEventDispatcher::class); + $this->dispatcher = Server::get(IEventDispatcher::class); $this->contentSecurityPolicyManager = new ContentSecurityPolicyManager($this->dispatcher); } - public function testAddDefaultPolicy() { - $this->contentSecurityPolicyManager->addDefaultPolicy(new \OCP\AppFramework\Http\ContentSecurityPolicy()); + public function testAddDefaultPolicy(): void { + $this->contentSecurityPolicyManager->addDefaultPolicy(new ContentSecurityPolicy()); $this->addToAssertionCount(1); } - public function testGetDefaultPolicyWithPolicies() { - $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy(); + public function testGetDefaultPolicyWithPolicies(): void { + $policy = new ContentSecurityPolicy(); $policy->addAllowedFontDomain('mydomain.com'); $policy->addAllowedImageDomain('anotherdomain.de'); $this->contentSecurityPolicyManager->addDefaultPolicy($policy); - $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy(); + $policy = new ContentSecurityPolicy(); $policy->addAllowedFontDomain('example.com'); $policy->addAllowedImageDomain('example.org'); - $policy->allowInlineScript(true); $policy->allowEvalScript(true); $this->contentSecurityPolicyManager->addDefaultPolicy($policy); - $policy = new \OCP\AppFramework\Http\EmptyContentSecurityPolicy(); + $policy = new EmptyContentSecurityPolicy(); $policy->addAllowedChildSrcDomain('childdomain'); $policy->addAllowedFontDomain('anotherFontDomain'); $policy->addAllowedFormActionDomain('thirdDomain'); $this->contentSecurityPolicyManager->addDefaultPolicy($policy); $expected = new \OC\Security\CSP\ContentSecurityPolicy(); - $expected->allowInlineScript(true); $expected->allowEvalScript(true); $expected->addAllowedFontDomain('mydomain.com'); $expected->addAllowedFontDomain('example.com'); @@ -75,15 +61,15 @@ class ContentSecurityPolicyManagerTest extends TestCase { $expected->addAllowedImageDomain('anotherdomain.de'); $expected->addAllowedImageDomain('example.org'); $expected->addAllowedChildSrcDomain('childdomain'); - $expectedStringPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' 'unsafe-inline' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data: blob: anotherdomain.de example.org;font-src 'self' data: mydomain.com example.com anotherFontDomain;connect-src 'self';media-src 'self';child-src childdomain;frame-ancestors 'self';form-action 'self' thirdDomain"; + $expectedStringPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data: blob: anotherdomain.de example.org;font-src 'self' data: mydomain.com example.com anotherFontDomain;connect-src 'self';media-src 'self';child-src childdomain;frame-ancestors 'self';form-action 'self' thirdDomain"; $this->assertEquals($expected, $this->contentSecurityPolicyManager->getDefaultPolicy()); $this->assertSame($expectedStringPolicy, $this->contentSecurityPolicyManager->getDefaultPolicy()->buildPolicy()); } - public function testGetDefaultPolicyWithPoliciesViaEvent() { - $this->dispatcher->addListener(AddContentSecurityPolicyEvent::class, function (AddContentSecurityPolicyEvent $e) { - $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy(); + public function testGetDefaultPolicyWithPoliciesViaEvent(): void { + $this->dispatcher->addListener(AddContentSecurityPolicyEvent::class, function (AddContentSecurityPolicyEvent $e): void { + $policy = new ContentSecurityPolicy(); $policy->addAllowedFontDomain('mydomain.com'); $policy->addAllowedImageDomain('anotherdomain.de'); $policy->useStrictDynamic(true); @@ -92,17 +78,16 @@ class ContentSecurityPolicyManagerTest extends TestCase { $e->addPolicy($policy); }); - $this->dispatcher->addListener(AddContentSecurityPolicyEvent::class, function (AddContentSecurityPolicyEvent $e) { - $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy(); + $this->dispatcher->addListener(AddContentSecurityPolicyEvent::class, function (AddContentSecurityPolicyEvent $e): void { + $policy = new ContentSecurityPolicy(); $policy->addAllowedFontDomain('example.com'); $policy->addAllowedImageDomain('example.org'); - $policy->allowInlineScript(true); $policy->allowEvalScript(false); $e->addPolicy($policy); }); - $this->dispatcher->addListener(AddContentSecurityPolicyEvent::class, function (AddContentSecurityPolicyEvent $e) { - $policy = new \OCP\AppFramework\Http\EmptyContentSecurityPolicy(); + $this->dispatcher->addListener(AddContentSecurityPolicyEvent::class, function (AddContentSecurityPolicyEvent $e): void { + $policy = new EmptyContentSecurityPolicy(); $policy->addAllowedChildSrcDomain('childdomain'); $policy->addAllowedFontDomain('anotherFontDomain'); $policy->addAllowedFormActionDomain('thirdDomain'); @@ -110,7 +95,6 @@ class ContentSecurityPolicyManagerTest extends TestCase { }); $expected = new \OC\Security\CSP\ContentSecurityPolicy(); - $expected->allowInlineScript(true); $expected->allowEvalScript(true); $expected->addAllowedFontDomain('mydomain.com'); $expected->addAllowedFontDomain('example.com'); @@ -120,7 +104,7 @@ class ContentSecurityPolicyManagerTest extends TestCase { $expected->addAllowedChildSrcDomain('childdomain'); $expected->addAllowedFormActionDomain('thirdDomain'); $expected->useStrictDynamic(true); - $expectedStringPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' 'unsafe-inline' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data: blob: anotherdomain.de example.org;font-src 'self' data: mydomain.com example.com anotherFontDomain;connect-src 'self';media-src 'self';child-src childdomain;frame-ancestors 'self';form-action 'self' thirdDomain"; + $expectedStringPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data: blob: anotherdomain.de example.org;font-src 'self' data: mydomain.com example.com anotherFontDomain;connect-src 'self';media-src 'self';child-src childdomain;frame-ancestors 'self';form-action 'self' thirdDomain"; $this->assertEquals($expected, $this->contentSecurityPolicyManager->getDefaultPolicy()); $this->assertSame($expectedStringPolicy, $this->contentSecurityPolicyManager->getDefaultPolicy()->buildPolicy()); diff --git a/tests/lib/Security/CSP/ContentSecurityPolicyNonceManagerTest.php b/tests/lib/Security/CSP/ContentSecurityPolicyNonceManagerTest.php index 0e21f13e6f7..3765311155a 100644 --- a/tests/lib/Security/CSP/ContentSecurityPolicyNonceManagerTest.php +++ b/tests/lib/Security/CSP/ContentSecurityPolicyNonceManagerTest.php @@ -3,23 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2016 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: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Security\CSP; @@ -28,42 +13,46 @@ use OC\AppFramework\Http\Request; use OC\Security\CSP\ContentSecurityPolicyNonceManager; use OC\Security\CSRF\CsrfToken; use OC\Security\CSRF\CsrfTokenManager; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class ContentSecurityPolicyNonceManagerTest extends TestCase { - /** @var CsrfTokenManager */ - private $csrfTokenManager; - /** @var Request */ + /** @var CsrfTokenManager&MockObject */ + private $CSRFTokenManager; + /** @var Request&MockObject */ private $request; /** @var ContentSecurityPolicyNonceManager */ private $nonceManager; protected function setUp(): void { - $this->csrfTokenManager = $this->createMock(CsrfTokenManager::class); + $this->CSRFTokenManager = $this->createMock(CsrfTokenManager::class); $this->request = $this->createMock(Request::class); $this->nonceManager = new ContentSecurityPolicyNonceManager( - $this->csrfTokenManager, + $this->CSRFTokenManager, $this->request ); } - public function testGetNonce() { + public function testGetNonce(): void { + $secret = base64_encode('secret'); + $tokenValue = base64_encode('secret' ^ 'value_') . ':' . $secret; $token = $this->createMock(CsrfToken::class); $token ->expects($this->once()) ->method('getEncryptedValue') - ->willReturn('MyToken'); + ->willReturn($tokenValue); - $this->csrfTokenManager + $this->CSRFTokenManager ->expects($this->once()) ->method('getToken') ->willReturn($token); - $this->assertSame('TXlUb2tlbg==', $this->nonceManager->getNonce()); - $this->assertSame('TXlUb2tlbg==', $this->nonceManager->getNonce()); + $this->assertSame($secret, $this->nonceManager->getNonce()); + // call it twice but `getEncryptedValue` is expected to be called only once + $this->assertSame($secret, $this->nonceManager->getNonce()); } - public function testGetNonceServerVar() { + public function testGetNonceServerVar(): void { $token = 'SERVERNONCE'; $this->request ->method('__isset') @@ -76,6 +65,7 @@ class ContentSecurityPolicyNonceManagerTest extends TestCase { ->willReturn(['CSP_NONCE' => $token]); $this->assertSame($token, $this->nonceManager->getNonce()); + // call it twice but `CSP_NONCE` variable is expected to be loaded only once $this->assertSame($token, $this->nonceManager->getNonce()); } } diff --git a/tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php b/tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php index 256199eff15..86f458d8ea8 100644 --- a/tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php +++ b/tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php @@ -3,29 +3,18 @@ declare(strict_types=1); /** - * @author Lukas Reschke <lukas@owncloud.com> - * - * @copyright Copyright (c) 2016, 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: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace Test\Security\CSRF; +use OC\Security\CSRF\CsrfTokenGenerator; +use OCP\Security\ISecureRandom; + class CsrfTokenGeneratorTest extends \Test\TestCase { - /** @var \OCP\Security\ISecureRandom */ + /** @var ISecureRandom */ private $random; /** @var \OC\Security\CSRF\CsrfTokenGenerator */ private $csrfTokenGenerator; @@ -34,10 +23,10 @@ class CsrfTokenGeneratorTest extends \Test\TestCase { parent::setUp(); $this->random = $this->getMockBuilder('\OCP\Security\ISecureRandom') ->disableOriginalConstructor()->getMock(); - $this->csrfTokenGenerator = new \OC\Security\CSRF\CsrfTokenGenerator($this->random); + $this->csrfTokenGenerator = new CsrfTokenGenerator($this->random); } - public function testGenerateTokenWithCustomNumber() { + public function testGenerateTokenWithCustomNumber(): void { $this->random ->expects($this->once()) ->method('generate') @@ -46,7 +35,7 @@ class CsrfTokenGeneratorTest extends \Test\TestCase { $this->assertSame('abc', $this->csrfTokenGenerator->generateToken(3)); } - public function testGenerateTokenWithDefault() { + public function testGenerateTokenWithDefault(): void { $this->random ->expects($this->once()) ->method('generate') diff --git a/tests/lib/Security/CSRF/CsrfTokenManagerTest.php b/tests/lib/Security/CSRF/CsrfTokenManagerTest.php index 44a9a7a929d..66ee18475a4 100644 --- a/tests/lib/Security/CSRF/CsrfTokenManagerTest.php +++ b/tests/lib/Security/CSRF/CsrfTokenManagerTest.php @@ -3,27 +3,16 @@ declare(strict_types=1); /** - * @author Lukas Reschke <lukas@owncloud.com> - * - * @copyright Copyright (c) 2016, 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\Security\CSRF; +use OC\Security\CSRF\CsrfToken; +use OC\Security\CSRF\CsrfTokenManager; + class CsrfTokenManagerTest extends \Test\TestCase { /** @var \OC\Security\CSRF\CsrfTokenManager */ private $csrfTokenManager; @@ -39,13 +28,13 @@ class CsrfTokenManagerTest extends \Test\TestCase { $this->storageInterface = $this->getMockBuilder('\OC\Security\CSRF\TokenStorage\SessionStorage') ->disableOriginalConstructor()->getMock(); - $this->csrfTokenManager = new \OC\Security\CSRF\CsrfTokenManager( + $this->csrfTokenManager = new CsrfTokenManager( $this->tokenGenerator, $this->storageInterface ); } - public function testGetTokenWithExistingToken() { + public function testGetTokenWithExistingToken(): void { $this->storageInterface ->expects($this->once()) ->method('hasToken') @@ -55,11 +44,11 @@ class CsrfTokenManagerTest extends \Test\TestCase { ->method('getToken') ->willReturn('MyExistingToken'); - $expected = new \OC\Security\CSRF\CsrfToken('MyExistingToken'); + $expected = new CsrfToken('MyExistingToken'); $this->assertEquals($expected, $this->csrfTokenManager->getToken()); } - public function testGetTokenWithExistingTokenKeepsOnSecondRequest() { + public function testGetTokenWithExistingTokenKeepsOnSecondRequest(): void { $this->storageInterface ->expects($this->once()) ->method('hasToken') @@ -69,13 +58,13 @@ class CsrfTokenManagerTest extends \Test\TestCase { ->method('getToken') ->willReturn('MyExistingToken'); - $expected = new \OC\Security\CSRF\CsrfToken('MyExistingToken'); + $expected = new CsrfToken('MyExistingToken'); $token = $this->csrfTokenManager->getToken(); $this->assertSame($token, $this->csrfTokenManager->getToken()); $this->assertSame($token, $this->csrfTokenManager->getToken()); } - public function testGetTokenWithoutExistingToken() { + public function testGetTokenWithoutExistingToken(): void { $this->storageInterface ->expects($this->once()) ->method('hasToken') @@ -89,11 +78,11 @@ class CsrfTokenManagerTest extends \Test\TestCase { ->method('setToken') ->with('MyNewToken'); - $expected = new \OC\Security\CSRF\CsrfToken('MyNewToken'); + $expected = new CsrfToken('MyNewToken'); $this->assertEquals($expected, $this->csrfTokenManager->getToken()); } - public function testRefreshToken() { + public function testRefreshToken(): void { $this->tokenGenerator ->expects($this->once()) ->method('generateToken') @@ -103,11 +92,11 @@ class CsrfTokenManagerTest extends \Test\TestCase { ->method('setToken') ->with('MyNewToken'); - $expected = new \OC\Security\CSRF\CsrfToken('MyNewToken'); + $expected = new CsrfToken('MyNewToken'); $this->assertEquals($expected, $this->csrfTokenManager->refreshToken()); } - public function testRemoveToken() { + public function testRemoveToken(): void { $this->storageInterface ->expects($this->once()) ->method('removeToken'); @@ -115,22 +104,22 @@ class CsrfTokenManagerTest extends \Test\TestCase { $this->csrfTokenManager->removeToken(); } - public function testIsTokenValidWithoutToken() { + public function testIsTokenValidWithoutToken(): void { $this->storageInterface ->expects($this->once()) ->method('hasToken') ->willReturn(false); - $token = new \OC\Security\CSRF\CsrfToken('Token'); + $token = new CsrfToken('Token'); $this->assertSame(false, $this->csrfTokenManager->isTokenValid($token)); } - public function testIsTokenValidWithWrongToken() { + public function testIsTokenValidWithWrongToken(): void { $this->storageInterface ->expects($this->once()) ->method('hasToken') ->willReturn(true); - $token = new \OC\Security\CSRF\CsrfToken('Token'); + $token = new CsrfToken('Token'); $this->storageInterface ->expects($this->once()) ->method('getToken') @@ -139,20 +128,20 @@ class CsrfTokenManagerTest extends \Test\TestCase { $this->assertSame(false, $this->csrfTokenManager->isTokenValid($token)); } - public function testIsTokenValidWithValidToken() { + public function testIsTokenValidWithValidToken(): void { $a = 'abc'; $b = 'def'; $xorB64 = 'BQcF'; $tokenVal = sprintf('%s:%s', $xorB64, base64_encode($a)); $this->storageInterface - ->expects($this->once()) - ->method('hasToken') - ->willReturn(true); - $token = new \OC\Security\CSRF\CsrfToken($tokenVal); + ->expects($this->once()) + ->method('hasToken') + ->willReturn(true); + $token = new CsrfToken($tokenVal); $this->storageInterface - ->expects($this->once()) - ->method('getToken') - ->willReturn($b); + ->expects($this->once()) + ->method('getToken') + ->willReturn($b); $this->assertSame(true, $this->csrfTokenManager->isTokenValid($token)); } diff --git a/tests/lib/Security/CSRF/CsrfTokenTest.php b/tests/lib/Security/CSRF/CsrfTokenTest.php index b694e797232..5b5ba5ae54f 100644 --- a/tests/lib/Security/CSRF/CsrfTokenTest.php +++ b/tests/lib/Security/CSRF/CsrfTokenTest.php @@ -3,47 +3,35 @@ declare(strict_types=1); /** - * @author Lukas Reschke <lukas@owncloud.com> - * - * @copyright Copyright (c) 2016, 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\Security\CSRF; +use OC\Security\CSRF\CsrfToken; + class CsrfTokenTest extends \Test\TestCase { - public function testGetEncryptedValue() { - $csrfToken = new \OC\Security\CSRF\CsrfToken('MyCsrfToken'); + public function testGetEncryptedValue(): void { + $csrfToken = new CsrfToken('MyCsrfToken'); $this->assertSame(33, strlen($csrfToken->getEncryptedValue())); $this->assertSame(':', $csrfToken->getEncryptedValue()[16]); } - public function testGetEncryptedValueStaysSameOnSecondRequest() { - $csrfToken = new \OC\Security\CSRF\CsrfToken('MyCsrfToken'); + public function testGetEncryptedValueStaysSameOnSecondRequest(): void { + $csrfToken = new CsrfToken('MyCsrfToken'); $tokenValue = $csrfToken->getEncryptedValue(); $this->assertSame($tokenValue, $csrfToken->getEncryptedValue()); $this->assertSame($tokenValue, $csrfToken->getEncryptedValue()); } - public function testGetDecryptedValue() { + public function testGetDecryptedValue(): void { $a = 'abc'; $b = 'def'; $xorB64 = 'BQcF'; $tokenVal = sprintf('%s:%s', $xorB64, base64_encode($a)); - $csrfToken = new \OC\Security\CSRF\CsrfToken($tokenVal); + $csrfToken = new CsrfToken($tokenVal); $this->assertSame($b, $csrfToken->getDecryptedValue()); } } diff --git a/tests/lib/Security/CSRF/TokenStorage/SessionStorageTest.php b/tests/lib/Security/CSRF/TokenStorage/SessionStorageTest.php index f55cf49f142..2b2c4af0444 100644 --- a/tests/lib/Security/CSRF/TokenStorage/SessionStorageTest.php +++ b/tests/lib/Security/CSRF/TokenStorage/SessionStorageTest.php @@ -3,31 +3,18 @@ declare(strict_types=1); /** - * @author Lukas Reschke <lukas@owncloud.com> - * - * @copyright Copyright (c) 2016, 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\Security\CSRF\TokenStorage; +use OC\Security\CSRF\TokenStorage\SessionStorage; use OCP\ISession; class SessionStorageTest extends \Test\TestCase { - /** @var \OCP\ISession */ + /** @var ISession */ private $session; /** @var \OC\Security\CSRF\TokenStorage\SessionStorage */ private $sessionStorage; @@ -36,13 +23,13 @@ class SessionStorageTest extends \Test\TestCase { parent::setUp(); $this->session = $this->getMockBuilder(ISession::class) ->disableOriginalConstructor()->getMock(); - $this->sessionStorage = new \OC\Security\CSRF\TokenStorage\SessionStorage($this->session); + $this->sessionStorage = new SessionStorage($this->session); } /** * @return array */ - public function getTokenDataProvider() { + public static function getTokenDataProvider(): array { return [ [ '', @@ -55,10 +42,10 @@ class SessionStorageTest extends \Test\TestCase { /** * @param string $token - * @dataProvider getTokenDataProvider * */ - public function testGetTokenWithEmptyToken($token) { + #[\PHPUnit\Framework\Attributes\DataProvider('getTokenDataProvider')] + public function testGetTokenWithEmptyToken($token): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('Session does not contain a requesttoken'); @@ -70,7 +57,7 @@ class SessionStorageTest extends \Test\TestCase { $this->sessionStorage->getToken(); } - public function testGetTokenWithValidToken() { + public function testGetTokenWithValidToken(): void { $this->session ->expects($this->once()) ->method('get') @@ -79,7 +66,7 @@ class SessionStorageTest extends \Test\TestCase { $this->assertSame('MyFancyCsrfToken', $this->sessionStorage->getToken()); } - public function testSetToken() { + public function testSetToken(): void { $this->session ->expects($this->once()) ->method('set') @@ -87,7 +74,7 @@ class SessionStorageTest extends \Test\TestCase { $this->sessionStorage->setToken('TokenToSet'); } - public function testRemoveToken() { + public function testRemoveToken(): void { $this->session ->expects($this->once()) ->method('remove') @@ -95,7 +82,7 @@ class SessionStorageTest extends \Test\TestCase { $this->sessionStorage->removeToken(); } - public function testHasTokenWithExistingToken() { + public function testHasTokenWithExistingToken(): void { $this->session ->expects($this->once()) ->method('exists') @@ -104,7 +91,7 @@ class SessionStorageTest extends \Test\TestCase { $this->assertSame(true, $this->sessionStorage->hasToken()); } - public function testHasTokenWithoutExistingToken() { + public function testHasTokenWithoutExistingToken(): void { $this->session ->expects($this->once()) ->method('exists') @@ -113,7 +100,7 @@ class SessionStorageTest extends \Test\TestCase { $this->assertSame(false, $this->sessionStorage->hasToken()); } - public function testSetSession() { + public function testSetSession(): void { $session = $this->createMock(ISession::class); $session ->expects($this->once()) diff --git a/tests/lib/Security/CertificateManagerTest.php b/tests/lib/Security/CertificateManagerTest.php index fdc6b40533e..4dadc824ef6 100644 --- a/tests/lib/Security/CertificateManagerTest.php +++ b/tests/lib/Security/CertificateManagerTest.php @@ -3,18 +3,24 @@ declare(strict_types=1); /** - * Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Security; +use OC\Files\Filesystem; +use OC\Files\Storage\Temporary; use OC\Files\View; +use OC\Security\Certificate; use OC\Security\CertificateManager; +use OCP\Files\InvalidPathException; use OCP\IConfig; +use OCP\IUserManager; use OCP\Security\ISecureRandom; +use OCP\Server; +use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; /** @@ -26,12 +32,9 @@ class CertificateManagerTest extends \Test\TestCase { use \Test\Traits\UserTrait; use \Test\Traits\MountProviderTrait; - /** @var CertificateManager */ - private $certificateManager; - /** @var String */ - private $username; - /** @var ISecureRandom */ - private $random; + private CertificateManager $certificateManager; + private string $username; + private ISecureRandom&MockObject $random; protected function setUp(): void { parent::setUp(); @@ -39,16 +42,16 @@ class CertificateManagerTest extends \Test\TestCase { $this->username = $this->getUniqueID('', 20); $this->createUser($this->username, ''); - $storage = new \OC\Files\Storage\Temporary(); + $storage = new Temporary(); $this->registerMount($this->username, $storage, '/' . $this->username . '/'); \OC_Util::tearDownFS(); - \OC_User::setUserId(''); - \OC\Files\Filesystem::tearDown(); + \OC_User::setUserId($this->username); + Filesystem::tearDown(); \OC_Util::setupFS($this->username); $config = $this->createMock(IConfig::class); - $config->expects($this->any())->method('getSystemValue') + $config->expects($this->any())->method('getSystemValueBool') ->with('installed', false)->willReturn(true); $this->random = $this->createMock(ISecureRandom::class); @@ -56,7 +59,7 @@ class CertificateManagerTest extends \Test\TestCase { ->willReturn('random'); $this->certificateManager = new CertificateManager( - new \OC\Files\View(), + new View(), $config, $this->createMock(LoggerInterface::class), $this->random @@ -64,7 +67,7 @@ class CertificateManagerTest extends \Test\TestCase { } protected function tearDown(): void { - $user = \OC::$server->getUserManager()->get($this->username); + $user = Server::get(IUserManager::class)->get($this->username); if ($user !== null) { $user->delete(); } @@ -78,34 +81,31 @@ class CertificateManagerTest extends \Test\TestCase { $this->assertEquals($expected, $actual); } - public function testListCertificates() { + public function testListCertificates(): void { // Test empty certificate bundle $this->assertSame([], $this->certificateManager->listCertificates()); // Add some certificates $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); $certificateStore = []; - $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); + $certificateStore[] = new Certificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); $this->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates()); // Add another certificates $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate'); - $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate'); + $certificateStore[] = new Certificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate'); $this->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates()); } - public function testAddInvalidCertificate() { + public function testAddInvalidCertificate(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('Certificate could not get parsed.'); $this->certificateManager->addCertificate('InvalidCertificate', 'invalidCertificate'); } - /** - * @return array - */ - public function dangerousFileProvider() { + public static function dangerousFileProvider(): array { return [ ['.htaccess'], ['../../foo.txt'], @@ -114,42 +114,40 @@ class CertificateManagerTest extends \Test\TestCase { } /** - * @dataProvider dangerousFileProvider * @param string $filename */ - public function testAddDangerousFile($filename) { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Filename is not valid'); - + #[\PHPUnit\Framework\Attributes\DataProvider('dangerousFileProvider')] + public function testAddDangerousFile($filename): void { + $this->expectException(InvalidPathException::class); $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), $filename); } - public function testRemoveDangerousFile() { + public function testRemoveDangerousFile(): void { $this->assertFalse($this->certificateManager->removeCertificate('../../foo.txt')); } - public function testRemoveExistingFile() { + public function testRemoveExistingFile(): void { $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); $this->assertTrue($this->certificateManager->removeCertificate('GoodCertificate')); } - public function testGetCertificateBundle() { + public function testGetCertificateBundle(): void { $this->assertSame('/files_external/rootcerts.crt', $this->certificateManager->getCertificateBundle()); } /** - * @dataProvider dataTestNeedRebundling * * @param int $CaBundleMtime * @param int $targetBundleMtime * @param int $targetBundleExists * @param bool $expected */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataTestNeedRebundling')] public function testNeedRebundling($CaBundleMtime, - $targetBundleMtime, - $targetBundleExists, - $expected - ) { + $targetBundleMtime, + $targetBundleExists, + $expected, + ): void { $view = $this->getMockBuilder(View::class) ->disableOriginalConstructor()->getMock(); $config = $this->createMock(IConfig::class); @@ -157,7 +155,7 @@ class CertificateManagerTest extends \Test\TestCase { /** @var CertificateManager | \PHPUnit\Framework\MockObject\MockObject $certificateManager */ $certificateManager = $this->getMockBuilder('OC\Security\CertificateManager') ->setConstructorArgs([$view, $config, $this->createMock(LoggerInterface::class), $this->random]) - ->setMethods(['getFilemtimeOfCaBundle', 'getCertificateBundle']) + ->onlyMethods(['getFilemtimeOfCaBundle', 'getCertificateBundle']) ->getMock(); $certificateManager->expects($this->any())->method('getFilemtimeOfCaBundle') @@ -185,7 +183,7 @@ class CertificateManagerTest extends \Test\TestCase { ); } - public function dataTestNeedRebundling() { + public static function dataTestNeedRebundling(): array { return [ //values: CaBundleMtime, targetBundleMtime, targetBundleExists, expected diff --git a/tests/lib/Security/CertificateTest.php b/tests/lib/Security/CertificateTest.php index 2c430fc1273..732b431d73e 100644 --- a/tests/lib/Security/CertificateTest.php +++ b/tests/lib/Security/CertificateTest.php @@ -3,23 +3,9 @@ declare(strict_types=1); /** - * @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: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace Test\Security; @@ -45,8 +31,8 @@ class CertificateTest extends \Test\TestCase { $this->expiredCertificate = new Certificate($expiredCertificate, 'ExpiredCertificate'); } - - public function testBogusData() { + + public function testBogusData(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('Certificate could not get parsed.'); @@ -54,37 +40,42 @@ class CertificateTest extends \Test\TestCase { $certificate->getIssueDate(); } - - public function testCertificateStartingWithFileReference() { + public function testOpenSslTrustedCertificateFormat(): void { + $trustedCertificate = file_get_contents(__DIR__ . '/../../data/certificates/openSslTrustedCertificate.crt'); + $certificate = new Certificate($trustedCertificate, 'TrustedCertificate'); + $this->assertSame('thawte, Inc.', $certificate->getOrganization()); + } + + public function testCertificateStartingWithFileReference(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('Certificate could not get parsed.'); - new Certificate('file://'.__DIR__ . '/../../data/certificates/goodCertificate.crt', 'bar'); + new Certificate('file://' . __DIR__ . '/../../data/certificates/goodCertificate.crt', 'bar'); } - public function testGetName() { + public function testGetName(): void { $this->assertSame('GoodCertificate', $this->goodCertificate->getName()); $this->assertSame('BadCertificate', $this->invalidCertificate->getName()); } - public function testGetCommonName() { + public function testGetCommonName(): void { $this->assertSame('security.owncloud.com', $this->goodCertificate->getCommonName()); $this->assertSame(null, $this->invalidCertificate->getCommonName()); } - public function testGetOrganization() { + public function testGetOrganization(): void { $this->assertSame('ownCloud Security', $this->goodCertificate->getOrganization()); $this->assertSame('Internet Widgits Pty Ltd', $this->invalidCertificate->getOrganization()); } - public function testGetIssueDate() { + public function testGetIssueDate(): void { $expected = new \DateTime('2015-08-27 20:03:42 GMT'); $this->assertEquals($expected->getTimestamp(), $this->goodCertificate->getIssueDate()->getTimestamp()); $expected = new \DateTime('2015-08-27 20:19:13 GMT'); $this->assertEquals($expected->getTimestamp(), $this->invalidCertificate->getIssueDate()->getTimestamp()); } - public function testGetExpireDate() { + public function testGetExpireDate(): void { $expected = new \DateTime('2025-08-24 20:03:42 GMT'); $this->assertEquals($expected->getTimestamp(), $this->goodCertificate->getExpireDate()->getTimestamp()); $expected = new \DateTime('2025-08-24 20:19:13 GMT'); @@ -93,19 +84,19 @@ class CertificateTest extends \Test\TestCase { $this->assertEquals($expected->getTimestamp(), $this->expiredCertificate->getExpireDate()->getTimestamp()); } - public function testIsExpired() { + public function testIsExpired(): void { $this->assertSame(false, $this->goodCertificate->isExpired()); $this->assertSame(false, $this->invalidCertificate->isExpired()); $this->assertSame(true, $this->expiredCertificate->isExpired()); } - public function testGetIssuerName() { + public function testGetIssuerName(): void { $this->assertSame('security.owncloud.com', $this->goodCertificate->getIssuerName()); $this->assertSame(null, $this->invalidCertificate->getIssuerName()); $this->assertSame(null, $this->expiredCertificate->getIssuerName()); } - public function testGetIssuerOrganization() { + public function testGetIssuerOrganization(): void { $this->assertSame('ownCloud Security', $this->goodCertificate->getIssuerOrganization()); $this->assertSame('Internet Widgits Pty Ltd', $this->invalidCertificate->getIssuerOrganization()); $this->assertSame('Internet Widgits Pty Ltd', $this->expiredCertificate->getIssuerOrganization()); diff --git a/tests/lib/Security/CredentialsManagerTest.php b/tests/lib/Security/CredentialsManagerTest.php index 6f535c84275..4dfe8c5681d 100644 --- a/tests/lib/Security/CredentialsManagerTest.php +++ b/tests/lib/Security/CredentialsManagerTest.php @@ -3,36 +3,23 @@ declare(strict_types=1); /** - * @author Robin McCorkell <rmccorkell@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\Security; +use OCP\Security\ICredentialsManager; +use OCP\Server; + /** * @group DB */ class CredentialsManagerTest extends \Test\TestCase { - /** - * @dataProvider credentialsProvider - */ - public function testWithDB($userId, $identifier) { - $credentialsManager = \OC::$server->getCredentialsManager(); + #[\PHPUnit\Framework\Attributes\DataProvider('credentialsProvider')] + public function testWithDB($userId, $identifier): void { + $credentialsManager = Server::get(ICredentialsManager::class); $secrets = 'Open Sesame'; @@ -45,7 +32,21 @@ class CredentialsManagerTest extends \Test\TestCase { $this->assertSame(1, $removedRows); } - public function credentialsProvider() { + #[\PHPUnit\Framework\Attributes\DataProvider('credentialsProvider')] + public function testUpdate($userId, $identifier): void { + $credentialsManager = Server::get(ICredentialsManager::class); + + $secrets = 'Open Sesame'; + $secretsRev = strrev($secrets); + + $credentialsManager->store($userId, $identifier, $secrets); + $credentialsManager->store($userId, $identifier, $secretsRev); + $received = $credentialsManager->retrieve($userId, $identifier); + + $this->assertSame($secretsRev, $received); + } + + public static function credentialsProvider(): array { return [ [ 'alice', diff --git a/tests/lib/Security/CryptoTest.php b/tests/lib/Security/CryptoTest.php index bdbad8b2610..0f8575ab0b5 100644 --- a/tests/lib/Security/CryptoTest.php +++ b/tests/lib/Security/CryptoTest.php @@ -3,18 +3,19 @@ declare(strict_types=1); /** - * Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Security; use OC\Security\Crypto; +use OCP\IConfig; +use OCP\Server; class CryptoTest extends \Test\TestCase { - public function defaultEncryptionProvider() { + public static function defaultEncryptionProvider(): array { return [ ['Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.'], [''], @@ -27,19 +28,17 @@ class CryptoTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->crypto = new Crypto(\OC::$server->getConfig()); + $this->crypto = new Crypto(Server::get(IConfig::class)); } - /** - * @dataProvider defaultEncryptionProvider - */ - public function testDefaultEncrypt($stringToEncrypt) { + #[\PHPUnit\Framework\Attributes\DataProvider('defaultEncryptionProvider')] + public function testDefaultEncrypt($stringToEncrypt): void { $ciphertext = $this->crypto->encrypt($stringToEncrypt); $this->assertEquals($stringToEncrypt, $this->crypto->decrypt($ciphertext)); } - public function testWrongPassword() { + public function testWrongPassword(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('HMAC does not match.'); @@ -48,14 +47,14 @@ class CryptoTest extends \Test\TestCase { $this->crypto->decrypt($ciphertext, 'A wrong password!'); } - public function testLaterDecryption() { + public function testLaterDecryption(): void { $stringToEncrypt = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.'; $encryptedString = '44a35023cca2e7a6125e06c29fc4b2ad9d8a33d0873a8b45b0de4ef9284f260c6c46bf25dc62120644c59b8bafe4281ddc47a70c35ae6c29ef7a63d79eefacc297e60b13042ac582733598d0a6b4de37311556bb5c480fd2633de4e6ebafa868c2d1e2d80a5d24f9660360dba4d6e0c8|lhrFgK0zd9U160Wo|a75e57ab701f9124e1113543fd1dc596f21e20d456a0d1e813d5a8aaec9adcb11213788e96598b67fe9486a9f0b99642c18296d0175db44b1ae426e4e91080ee'; $this->assertEquals($stringToEncrypt, $this->crypto->decrypt($encryptedString, 'ThisIsAVeryS3cur3P4ssw0rd')); } - public function testWrongIV() { + public function testWrongIV(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('HMAC does not match.'); @@ -64,7 +63,7 @@ class CryptoTest extends \Test\TestCase { } - public function testWrongParameters() { + public function testWrongParameters(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('Authenticated ciphertext could not be decoded.'); @@ -72,14 +71,14 @@ class CryptoTest extends \Test\TestCase { $this->crypto->decrypt($encryptedString, 'ThisIsAVeryS3cur3P4ssw0rd'); } - public function testLegacy() { + public function testLegacy(): void { $cipherText = 'e16599188e3d212f5c7f17fdc2abca46|M1WfLAxbcAmITeD6|509457885d6ca5e6c3bfd3741852687a7f2bffce197f8d5ae97b65818b15a1b7f616b68326ff312371540f4ca8ac55f8e2de4aa13aab3474bd3431e51214e3ee'; $password = 'mypass'; $this->assertSame('legacy test', $this->crypto->decrypt($cipherText, $password)); } - public function testVersion2CiphertextDecryptsToCorrectPlaintext() { + public function testVersion2CiphertextDecryptsToCorrectPlaintext(): void { $this->assertSame( 'This is a plaintext value that will be encrypted with version 2. Which addresses the reduced permutations on the IV.', $this->crypto->decrypt( @@ -89,7 +88,20 @@ class CryptoTest extends \Test\TestCase { ); } - public function testVersion3CiphertextDecryptsToCorrectPlaintext() { + /** + * Test data taken from https://github.com/owncloud/core/blob/9deb8196b20354c8de0cd720ad4d18d52ccc96d8/tests/lib/Security/CryptoTest.php#L56-L60 + */ + public function testOcVersion2CiphertextDecryptsToCorrectPlaintext(): void { + $this->assertSame( + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.', + $this->crypto->decrypt( + 'v2|d57dbe4d1317cdf19d4ddc2df807f6b5d63ab1e119c46590ce54bae56a9cd3969168c4ec1600ac9758dd7e7afb9c4c962dd23072c1463add1d9c77c467723b37bb768ef00e3c50898e59247cbb59ce56b74ce5990648ffe9e40d0e95076c27a785bdcf32c219ea4ad5c316b1f12f48c1|6bd21db258a5e406a2c288a444de195f|a19111a4cf1a11ee95fc1734699c20964eaa05bb007e1cecc4cc6872f827a4b7deedc977c13b138d728d68116aa3d82f9673e20c7e447a9788aa3be994b67cd6', + 'ThisIsAVeryS3cur3P4ssw0rd' + ) + ); + } + + public function testVersion3CiphertextDecryptsToCorrectPlaintext(): void { $this->assertSame( 'Another plaintext value that will be encrypted with version 3. It addresses the related key issue. Old ciphertexts should be decrypted properly, but only use the better version for encryption.', $this->crypto->decrypt( diff --git a/tests/lib/Security/Events/GenerateSecurePasswordEventTest.php b/tests/lib/Security/Events/GenerateSecurePasswordEventTest.php new file mode 100644 index 00000000000..e589f20f62c --- /dev/null +++ b/tests/lib/Security/Events/GenerateSecurePasswordEventTest.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Security\Events; + +use OCP\Security\Events\GenerateSecurePasswordEvent; +use OCP\Security\PasswordContext; + +class GenerateSecurePasswordEventTest extends \Test\TestCase { + + public function testDefaultProperties(): void { + $event = new GenerateSecurePasswordEvent(); + $this->assertNull($event->getPassword()); + $this->assertEquals(PasswordContext::ACCOUNT, $event->getContext()); + } + + public function testSettingPassword(): void { + $event = new GenerateSecurePasswordEvent(); + $event->setPassword('example'); + $this->assertEquals('example', $event->getPassword()); + } + + public function testSettingContext(): void { + $event = new GenerateSecurePasswordEvent(PasswordContext::SHARING); + $this->assertEquals(PasswordContext::SHARING, $event->getContext()); + } +} diff --git a/tests/lib/Security/Events/ValidatePasswordPolicyEventTest.php b/tests/lib/Security/Events/ValidatePasswordPolicyEventTest.php new file mode 100644 index 00000000000..272f34e31aa --- /dev/null +++ b/tests/lib/Security/Events/ValidatePasswordPolicyEventTest.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Security\Events; + +use OCP\Security\Events\ValidatePasswordPolicyEvent; +use OCP\Security\PasswordContext; + +class ValidatePasswordPolicyEventTest extends \Test\TestCase { + + public function testDefaultProperties(): void { + $password = 'example'; + $event = new ValidatePasswordPolicyEvent($password); + $this->assertEquals($password, $event->getPassword()); + $this->assertEquals(PasswordContext::ACCOUNT, $event->getContext()); + } + + public function testSettingContext(): void { + $event = new ValidatePasswordPolicyEvent('example', PasswordContext::SHARING); + $this->assertEquals(PasswordContext::SHARING, $event->getContext()); + } +} diff --git a/tests/lib/Security/FeaturePolicy/AddFeaturePolicyEventTest.php b/tests/lib/Security/FeaturePolicy/AddFeaturePolicyEventTest.php index 6e6433adbeb..1fe01e26280 100644 --- a/tests/lib/Security/FeaturePolicy/AddFeaturePolicyEventTest.php +++ b/tests/lib/Security/FeaturePolicy/AddFeaturePolicyEventTest.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\Security\CSP; @@ -31,7 +14,7 @@ use OCP\Security\FeaturePolicy\AddFeaturePolicyEvent; use Test\TestCase; class AddFeaturePolicyEventTest extends TestCase { - public function testAddEvent() { + public function testAddEvent(): void { $manager = $this->createMock(FeaturePolicyManager::class); $policy = $this->createMock(FeaturePolicy::class); $event = new AddFeaturePolicyEvent($manager); diff --git a/tests/lib/Security/FeaturePolicy/FeaturePolicyManagerTest.php b/tests/lib/Security/FeaturePolicy/FeaturePolicyManagerTest.php index b8f558719dc..01624cb92d3 100644 --- a/tests/lib/Security/FeaturePolicy/FeaturePolicyManagerTest.php +++ b/tests/lib/Security/FeaturePolicy/FeaturePolicyManagerTest.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\Security\CSP; @@ -29,11 +12,11 @@ use OC\Security\FeaturePolicy\FeaturePolicyManager; use OCP\AppFramework\Http\FeaturePolicy; use OCP\EventDispatcher\IEventDispatcher; use OCP\Security\FeaturePolicy\AddFeaturePolicyEvent; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use OCP\Server; use Test\TestCase; class FeaturePolicyManagerTest extends TestCase { - /** @var EventDispatcherInterface */ + /** @var IEventDispatcher */ private $dispatcher; /** @var FeaturePolicyManager */ @@ -41,17 +24,17 @@ class FeaturePolicyManagerTest extends TestCase { protected function setUp(): void { parent::setUp(); - $this->dispatcher = \OC::$server->query(IEventDispatcher::class); + $this->dispatcher = Server::get(IEventDispatcher::class); $this->manager = new FeaturePolicyManager($this->dispatcher); } - public function testAddDefaultPolicy() { + public function testAddDefaultPolicy(): void { $this->manager->addDefaultPolicy(new FeaturePolicy()); $this->addToAssertionCount(1); } - public function testGetDefaultPolicyWithPoliciesViaEvent() { - $this->dispatcher->addListener(AddFeaturePolicyEvent::class, function (AddFeaturePolicyEvent $e) { + public function testGetDefaultPolicyWithPoliciesViaEvent(): void { + $this->dispatcher->addListener(AddFeaturePolicyEvent::class, function (AddFeaturePolicyEvent $e): void { $policy = new FeaturePolicy(); $policy->addAllowedMicrophoneDomain('mydomain.com'); $policy->addAllowedPaymentDomain('mypaymentdomain.com'); @@ -59,7 +42,7 @@ class FeaturePolicyManagerTest extends TestCase { $e->addPolicy($policy); }); - $this->dispatcher->addListener(AddFeaturePolicyEvent::class, function (AddFeaturePolicyEvent $e) { + $this->dispatcher->addListener(AddFeaturePolicyEvent::class, function (AddFeaturePolicyEvent $e): void { $policy = new FeaturePolicy(); $policy->addAllowedPaymentDomain('mydomainother.com'); $policy->addAllowedGeoLocationDomain('mylocation.here'); @@ -67,7 +50,7 @@ class FeaturePolicyManagerTest extends TestCase { $e->addPolicy($policy); }); - $this->dispatcher->addListener(AddFeaturePolicyEvent::class, function (AddFeaturePolicyEvent $e) { + $this->dispatcher->addListener(AddFeaturePolicyEvent::class, function (AddFeaturePolicyEvent $e): void { $policy = new FeaturePolicy(); $policy->addAllowedAutoplayDomain('youtube.com'); diff --git a/tests/lib/Security/HasherTest.php b/tests/lib/Security/HasherTest.php index 37e2adcc13c..33130f86a73 100644 --- a/tests/lib/Security/HasherTest.php +++ b/tests/lib/Security/HasherTest.php @@ -3,10 +3,9 @@ declare(strict_types=1); /** - * Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Security; @@ -18,10 +17,7 @@ use OCP\IConfig; * Class HasherTest */ class HasherTest extends \Test\TestCase { - /** - * @return array - */ - public function versionHashProvider() { + public static function versionHashProvider(): array { return [ ['asf32äà $$a.|3', null], ['asf32äà $$a.|3|5', null], @@ -31,7 +27,7 @@ class HasherTest extends \Test\TestCase { ]; } - public function hashProviders70_71(): array { + public static function hashProviders70_71(): array { return [ // Valid SHA1 strings ['password', '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8', true], @@ -67,7 +63,7 @@ class HasherTest extends \Test\TestCase { ]; } - public function hashProviders72(): array { + public static function hashProviders72(): array { return [ // Valid ARGON2 hashes ['password', '2|$argon2i$v=19$m=1024,t=2,p=2$T3JGcEkxVFNOVktNSjZUcg$4/hyLtSejxNgAuzSFFV/HLM3qRQKBwEtKw61qPN4zWA', true], @@ -84,7 +80,7 @@ class HasherTest extends \Test\TestCase { ]; } - public function hashProviders73(): array { + public static function hashProviders73(): array { return [ // Valid ARGON2ID hashes ['password', '2|$argon2id$v=19$m=65536,t=4,p=1$TEtIMnhUczliQzI0Y01WeA$BpMUDrApy25iagIogUAnlc0rNTPJmGs8lOEeVHujJ9Q', true], @@ -123,24 +119,20 @@ class HasherTest extends \Test\TestCase { $this->hasher = new Hasher($this->config); } - public function testHash() { + public function testHash(): void { $hash = $this->hasher->hash('String To Hash'); $this->assertNotNull($hash); } - /** - * @dataProvider versionHashProvider - */ - public function testSplitHash($hash, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('versionHashProvider')] + public function testSplitHash($hash, $expected): void { $relativePath = self::invokePrivate($this->hasher, 'splitHash', [$hash]); $this->assertSame($expected, $relativePath); } - /** - * @dataProvider hashProviders70_71 - */ - public function testVerify($password, $hash, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('hashProviders70_71')] + public function testVerify($password, $hash, $expected): void { $this->config ->expects($this->any()) ->method('getSystemValue') @@ -155,10 +147,8 @@ class HasherTest extends \Test\TestCase { $this->assertSame($expected, $result); } - /** - * @dataProvider hashProviders72 - */ - public function testVerifyArgon2i($password, $hash, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('hashProviders72')] + public function testVerifyArgon2i($password, $hash, $expected): void { if (!\defined('PASSWORD_ARGON2I')) { $this->markTestSkipped('Need ARGON2 support to test ARGON2 hashes'); } @@ -167,10 +157,8 @@ class HasherTest extends \Test\TestCase { $this->assertSame($expected, $result); } - /** - * @dataProvider hashProviders73 - */ - public function testVerifyArgon2id(string $password, string $hash, bool $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('hashProviders73')] + public function testVerifyArgon2id(string $password, string $hash, bool $expected): void { if (!\defined('PASSWORD_ARGON2ID')) { $this->markTestSkipped('Need ARGON2ID support to test ARGON2ID hashes'); } @@ -179,7 +167,7 @@ class HasherTest extends \Test\TestCase { $this->assertSame($expected, $result); } - public function testUpgradeHashBlowFishToArgon2() { + public function testUpgradeHashBlowFishToArgon2(): void { if (!\defined('PASSWORD_ARGON2I')) { $this->markTestSkipped('Need ARGON2 support to test ARGON2 hashes'); } @@ -204,12 +192,12 @@ class HasherTest extends \Test\TestCase { $this->assertFalse(password_needs_rehash($relativePath['hash'], $newAlg, [])); } - public function testUsePasswordDefaultArgon2iVerify() { + public function testUsePasswordDefaultArgon2iVerify(): void { if (!\defined('PASSWORD_ARGON2I')) { $this->markTestSkipped('Need ARGON2 support to test ARGON2 hashes'); } - $this->config->method('getSystemValue') + $this->config->method('getSystemValueBool') ->with('hashing_default_password') ->willReturn(true); @@ -228,12 +216,12 @@ class HasherTest extends \Test\TestCase { $this->assertTrue(password_verify($message, $relativePath['hash'])); } - public function testDoNotUsePasswordDefaultArgon2idVerify() { + public function testDoNotUsePasswordDefaultArgon2idVerify(): void { if (!\defined('PASSWORD_ARGON2ID')) { $this->markTestSkipped('Need ARGON2ID support to test ARGON2ID hashes'); } - $this->config->method('getSystemValue') + $this->config->method('getSystemValueBool') ->with('hashing_default_password') ->willReturn(false); @@ -246,12 +234,12 @@ class HasherTest extends \Test\TestCase { $this->assertNull($newHash); } - public function testHashUsePasswordDefault() { + public function testHashUsePasswordDefault(): void { if (!\defined('PASSWORD_ARGON2I')) { $this->markTestSkipped('Need ARGON2 support to test ARGON2 hashes'); } - $this->config->method('getSystemValue') + $this->config->method('getSystemValueBool') ->with('hashing_default_password') ->willReturn(true); @@ -265,4 +253,29 @@ class HasherTest extends \Test\TestCase { $info = password_get_info($relativePath['hash']); $this->assertEquals(PASSWORD_BCRYPT, $info['algo']); } + + public function testValidHash(): void { + $hash = '3|$argon2id$v=19$m=65536,t=4,p=1$czFCSjk3LklVdXppZ2VCWA$li0NgdXe2/jwSRxgteGQPWlzJU0E0xdtfHbCbrpych0'; + + $isValid = $this->hasher->validate($hash); + + $this->assertTrue($isValid); + } + + public function testValidGeneratedHash(): void { + $message = 'secret'; + $hash = $this->hasher->hash($message); + + $isValid = $this->hasher->validate($hash); + + $this->assertTrue($isValid); + } + + public function testInvalidHash(): void { + $invalidHash = 'someInvalidHash'; + + $isValid = $this->hasher->validate($invalidHash); + + $this->assertFalse($isValid); + } } diff --git a/tests/lib/Security/IdentityProof/KeyTest.php b/tests/lib/Security/IdentityProof/KeyTest.php index 4c852ff7020..572bfbea619 100644 --- a/tests/lib/Security/IdentityProof/KeyTest.php +++ b/tests/lib/Security/IdentityProof/KeyTest.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright 2016, 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: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Security\IdentityProof; @@ -39,11 +22,11 @@ class KeyTest extends TestCase { $this->key = new Key('public', 'private'); } - public function testGetPrivate() { + public function testGetPrivate(): void { $this->assertSame('private', $this->key->getPrivate()); } - public function testGetPublic() { + public function testGetPublic(): void { $this->assertSame('public', $this->key->getPublic()); } } diff --git a/tests/lib/Security/IdentityProof/ManagerTest.php b/tests/lib/Security/IdentityProof/ManagerTest.php index 8733d5de8be..921d72388a1 100644 --- a/tests/lib/Security/IdentityProof/ManagerTest.php +++ b/tests/lib/Security/IdentityProof/ManagerTest.php @@ -3,23 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2016 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: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Security\IdentityProof; @@ -31,6 +16,8 @@ use OC\Security\IdentityProof\Manager; use OCP\Files\IAppData; use OCP\Files\SimpleFS\ISimpleFile; use OCP\Files\SimpleFS\ISimpleFolder; +use OCP\ICache; +use OCP\ICacheFactory; use OCP\IConfig; use OCP\IUser; use OCP\Security\ICrypto; @@ -39,18 +26,14 @@ use Psr\Log\LoggerInterface; use Test\TestCase; class ManagerTest extends TestCase { - /** @var Factory|MockObject */ - private $factory; - /** @var IAppData|MockObject */ - private $appData; - /** @var ICrypto|MockObject */ - private $crypto; - /** @var Manager|MockObject */ - private $manager; - /** @var IConfig|MockObject */ - private $config; - /** @var LoggerInterface|MockObject */ - private $logger; + private Factory&MockObject $factory; + private IAppData&MockObject $appData; + private ICrypto&MockObject $crypto; + private Manager&MockObject $manager; + private IConfig&MockObject $config; + private LoggerInterface&MockObject $logger; + private ICacheFactory&MockObject $cacheFactory; + private ICache&MockObject $cache; protected function setUp(): void { parent::setUp(); @@ -64,6 +47,12 @@ class ManagerTest extends TestCase { ->with('identityproof') ->willReturn($this->appData); $this->logger = $this->createMock(LoggerInterface::class); + $this->cacheFactory = $this->createMock(ICacheFactory::class); + $this->cache = $this->createMock(ICache::class); + + $this->cacheFactory->expects($this->any()) + ->method('createDistributed') + ->willReturn($this->cache); $this->crypto = $this->createMock(ICrypto::class); $this->manager = $this->getManager(['generateKeyPair']); @@ -81,7 +70,8 @@ class ManagerTest extends TestCase { $this->factory, $this->crypto, $this->config, - $this->logger + $this->logger, + $this->cacheFactory, ); } else { return $this->getMockBuilder(Manager::class) @@ -89,12 +79,15 @@ class ManagerTest extends TestCase { $this->factory, $this->crypto, $this->config, - $this->logger - ])->setMethods($setMethods)->getMock(); + $this->logger, + $this->cacheFactory, + ]) + ->onlyMethods($setMethods) + ->getMock(); } } - public function testGetKeyWithExistingKey() { + public function testGetKeyWithExistingKey(): void { $user = $this->createMock(IUser::class); $user ->expects($this->once()) @@ -119,25 +112,48 @@ class ManagerTest extends TestCase { $folder ->expects($this->exactly(2)) ->method('getFile') - ->withConsecutive( - ['private'], - ['public'] - ) - ->willReturnOnConsecutiveCalls( - $privateFile, - $publicFile - ); + ->willReturnMap([ + ['private', $privateFile], + ['public', $publicFile], + ]); $this->appData ->expects($this->once()) ->method('getFolder') ->with('user-MyUid') ->willReturn($folder); + $this->cache + ->expects($this->exactly(2)) + ->method('get') + ->willReturn(null); + + $expected = new Key('MyPublicKey', 'MyPrivateKey'); + $this->assertEquals($expected, $this->manager->getKey($user)); + } + + public function testGetKeyWithExistingKeyCached(): void { + $user = $this->createMock(IUser::class); + $user + ->expects($this->once()) + ->method('getUID') + ->willReturn('MyUid'); + $this->crypto + ->expects($this->once()) + ->method('decrypt') + ->with('EncryptedPrivateKey') + ->willReturn('MyPrivateKey'); + $this->cache + ->expects($this->exactly(2)) + ->method('get') + ->willReturnMap([ + ['user-MyUid-public', 'MyPublicKey'], + ['user-MyUid-private', 'EncryptedPrivateKey'], + ]); $expected = new Key('MyPublicKey', 'MyPrivateKey'); $this->assertEquals($expected, $this->manager->getKey($user)); } - public function testGetKeyWithNotExistingKey() { + public function testGetKeyWithNotExistingKey(): void { $user = $this->createMock(IUser::class); $user ->expects($this->once()) @@ -170,14 +186,10 @@ class ManagerTest extends TestCase { $folder ->expects($this->exactly(2)) ->method('newFile') - ->withConsecutive( - ['private'], - ['public'] - ) - ->willReturnOnConsecutiveCalls( - $privateFile, - $publicFile - ); + ->willReturnMap([ + ['private', null, $privateFile], + ['public', null, $publicFile], + ]); $this->appData ->expects($this->exactly(2)) ->method('getFolder') @@ -192,7 +204,7 @@ class ManagerTest extends TestCase { $this->assertEquals($expected, $this->manager->getKey($user)); } - public function testGenerateKeyPair() { + public function testGenerateKeyPair(): void { $manager = $this->getManager(); $data = 'MyTestData'; @@ -204,7 +216,7 @@ class ManagerTest extends TestCase { $this->assertSame(2048, $details['bits']); } - public function testGetSystemKey() { + public function testGetSystemKey(): void { $manager = $this->getManager(['retrieveKey']); /** @var Key|\PHPUnit\Framework\MockObject\MockObject $key */ @@ -221,7 +233,7 @@ class ManagerTest extends TestCase { - public function testGetSystemKeyFailure() { + public function testGetSystemKeyFailure(): void { $this->expectException(\RuntimeException::class); $manager = $this->getManager(['retrieveKey']); diff --git a/tests/lib/Security/IdentityProof/SignerTest.php b/tests/lib/Security/IdentityProof/SignerTest.php index 36b7ef97bb6..6dc73c072e4 100644 --- a/tests/lib/Security/IdentityProof/SignerTest.php +++ b/tests/lib/Security/IdentityProof/SignerTest.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright 2016, 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: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Security\IdentityProof; @@ -107,7 +90,7 @@ gQIDAQAB ); } - public function testSign() { + public function testSign(): void { $user = $this->createMock(IUser::class); $user->method('getCloudId') ->willReturn('foo@example.com'); @@ -140,7 +123,7 @@ gQIDAQAB $this->assertEquals($expects, $result); } - public function testVerifyValid() { + public function testVerifyValid(): void { $data = [ 'message' => [ 'data' => [ @@ -168,7 +151,7 @@ gQIDAQAB $this->assertTrue($this->signer->verify($data)); } - public function testVerifyInvalid() { + public function testVerifyInvalid(): void { $data = [ 'message' => [ 'data' => [ @@ -196,7 +179,7 @@ gQIDAQAB $this->assertFalse($this->signer->verify($data)); } - public function testVerifyInvalidData() { + public function testVerifyInvalidData(): void { $data = [ ]; diff --git a/tests/lib/Security/Ip/BruteforceAllowListTest.php b/tests/lib/Security/Ip/BruteforceAllowListTest.php new file mode 100644 index 00000000000..1454b779c1b --- /dev/null +++ b/tests/lib/Security/Ip/BruteforceAllowListTest.php @@ -0,0 +1,161 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Security\Ip; + +use OC\Security\Ip\BruteforceAllowList; +use OC\Security\Ip\Factory; +use OCP\IAppConfig; +use OCP\Security\Ip\IFactory; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +/** + * Based on the unit tests from Paragonie's Airship CMS + * Ref: https://github.com/paragonie/airship/blob/7e5bad7e3c0fbbf324c11f963fd1f80e59762606/test/unit/Engine/Security/AirBrakeTest.php + * + * @package Test\Security\Bruteforce + */ +class BruteforceAllowListTest extends TestCase { + /** @var IAppConfig|MockObject */ + private $appConfig; + /** @var IFactory|MockObject */ + private $factory; + /** @var BruteforceAllowList */ + private $allowList; + + protected function setUp(): void { + parent::setUp(); + + $this->appConfig = $this->createMock(IAppConfig::class); + $this->factory = new Factory(); + + $this->allowList = new BruteforceAllowList( + $this->appConfig, + $this->factory, + ); + } + + public static function dataIsBypassListed(): array { + return [ + [ + '10.10.10.10', + [ + 'whitelist_0' => '10.10.10.0/24', + ], + true, + ], + [ + '10.10.10.10', + [ + 'whitelist_0' => '192.168.0.0/16', + ], + false, + ], + [ + '10.10.10.10', + [ + 'whitelist_0' => '192.168.0.0/16', + 'whitelist_1' => '10.10.10.0/24', + ], + true, + ], + [ + '10.10.10.10', + [ + 'whitelist_0' => '10.10.10.11/31', + ], + true, + ], + [ + '10.10.10.10', + [ + 'whitelist_0' => '10.10.10.9/31', + ], + false, + ], + [ + '10.10.10.10', + [ + 'whitelist_0' => '10.10.10.15/29', + ], + true, + ], + [ + 'dead:beef:cafe::1', + [ + 'whitelist_0' => '192.168.0.0/16', + 'whitelist_1' => '10.10.10.0/24', + 'whitelist_2' => 'deaf:beef:cafe:1234::/64' + ], + false, + ], + [ + 'dead:beef:cafe::1', + [ + 'whitelist_0' => '192.168.0.0/16', + 'whitelist_1' => '10.10.10.0/24', + 'whitelist_2' => 'deaf:beef::/64' + ], + false, + ], + [ + 'dead:beef:cafe::1', + [ + 'whitelist_0' => '192.168.0.0/16', + 'whitelist_1' => '10.10.10.0/24', + 'whitelist_2' => 'deaf:cafe::/8' + ], + true, + ], + [ + 'dead:beef:cafe::1111', + [ + 'whitelist_0' => 'dead:beef:cafe::1100/123', + ], + true, + ], + [ + 'invalid', + [], + false, + ], + ]; + } + + /** + * @param string[] $allowList + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataIsBypassListed')] + public function testIsBypassListed( + string $ip, + array $allowList, + bool $isAllowListed, + ): void { + $this->appConfig->method('searchKeys') + ->with($this->equalTo('bruteForce'), $this->equalTo('whitelist_')) + ->willReturn(array_keys($allowList)); + + $this->appConfig->method('getValueString') + ->willReturnCallback(function ($app, $key, $default) use ($allowList) { + if ($app !== 'bruteForce') { + return $default; + } + if (isset($allowList[$key])) { + return $allowList[$key]; + } + return $default; + }); + + $this->assertSame( + $isAllowListed, + $this->allowList->isBypassListed($ip) + ); + } +} diff --git a/tests/lib/Security/Ip/RemoteAddressTest.php b/tests/lib/Security/Ip/RemoteAddressTest.php new file mode 100644 index 00000000000..a6619cffe8e --- /dev/null +++ b/tests/lib/Security/Ip/RemoteAddressTest.php @@ -0,0 +1,79 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Security\Ip; + +use OC\Security\Ip\RemoteAddress; +use OCP\IConfig; +use OCP\IRequest; + +class RemoteAddressTest extends \Test\TestCase { + private IConfig $config; + private IRequest $request; + + protected function setUp(): void { + parent::setUp(); + $this->config = $this->createMock(IConfig::class); + $this->request = $this->createMock(IRequest::class); + } + + /** + * @param mixed $allowedRanges + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataProvider')] + public function testAllowedIps(string $remoteIp, $allowedRanges, bool $expected): void { + $this->request + ->method('getRemoteAddress') + ->willReturn($remoteIp); + $this->config + ->method('getSystemValue') + ->with('allowed_admin_ranges', false) + ->willReturn($allowedRanges); + + $remoteAddress = new RemoteAddress($this->config, $this->request); + + $this->assertEquals($expected, $remoteAddress->allowsAdminActions()); + } + + /** + * @return array<string, mixed, bool> + */ + public static function dataProvider(): array { + return [ + // No IP (ie. CLI) + ['', ['192.168.1.2/24'], true], + ['', ['fe80/8'], true], + // No configuration + ['1.2.3.4', false, true], + ['1234:4567:8910::', false, true], + // v6 Zone ID + ['fe80::1fc4:15d8:78db:2319%enp4s0', false, true], + // Empty configuration + ['1.2.3.4', [], true], + ['1234:4567:8910::', [], true], + // Invalid configuration + ['1.2.3.4', 'hello', true], + ['1234:4567:8910::', 'world', true], + // Mixed configuration + ['192.168.1.5', ['1.2.3.*', '1234::/8'], false], + ['::1', ['127.0.0.1', '1234::/8'], false], + ['192.168.1.5', ['192.168.1.0/24', '1234::/8'], true], + // Allowed IP + ['1.2.3.4', ['1.2.3.*'], true], + ['fc00:1:2:3::1', ['fc00::/7'], true], + ['1.2.3.4', ['192.168.1.2/24', '1.2.3.0/24'], true], + ['1234:4567:8910::1', ['fe80::/8','1234:4567::/16'], true], + // Blocked IP + ['192.168.1.5', ['1.2.3.*'], false], + ['9234:4567:8910::', ['1234:4567::1'], false], + ['192.168.2.1', ['192.168.1.2/24', '1.2.3.0/24'], false], + ['9234:4567:8910::', ['fe80::/8','1234:4567::/16'], false], + ]; + } +} diff --git a/tests/lib/Security/Normalizer/IpAddressTest.php b/tests/lib/Security/Normalizer/IpAddressTest.php index bb487659ced..f7adfb4a0dd 100644 --- a/tests/lib/Security/Normalizer/IpAddressTest.php +++ b/tests/lib/Security/Normalizer/IpAddressTest.php @@ -3,23 +3,8 @@ 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\Security\Normalizer; @@ -28,7 +13,7 @@ use OC\Security\Normalizer\IpAddress; use Test\TestCase; class IpAddressTest extends TestCase { - public function subnetDataProvider() { + public static function subnetDataProvider(): array { return [ [ '64.233.191.254', @@ -51,35 +36,35 @@ class IpAddressTest extends TestCase { '192.168.0.123/32', ], [ - '2001:0db8:85a3:0000:0000:8a2e:0370:7334', - '2001:db8:85a3::/64', + '2001:0db8:0000:0000:0000:8a2e:0370:7334', + '2001:db8::/56', ], [ '2001:db8:3333:4444:5555:6666:7777:8888', - '2001:db8:3333:4444::/64', + '2001:db8:3333:4400::/56', ], [ '::1234:5678', - '::/64', + '::/56', ], [ '[::1]', - '::/64', + '::/56', ], ]; } /** - * @dataProvider subnetDataProvider * * @param string $input * @param string $expected */ - public function testGetSubnet($input, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('subnetDataProvider')] + public function testGetSubnet($input, $expected): void { $this->assertSame($expected, (new IpAddress($input))->getSubnet()); } - public function testToString() { + public function testToString(): void { $this->assertSame('127.0.0.1', (string)(new IpAddress('127.0.0.1'))); } } diff --git a/tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php b/tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php index e7cb4a93a29..24e3ab1a209 100644 --- a/tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php +++ b/tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php @@ -3,23 +3,8 @@ 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\Security\RateLimiting\Backend; @@ -28,9 +13,12 @@ use OC\Security\RateLimiting\Backend\MemoryCacheBackend; use OCP\AppFramework\Utility\ITimeFactory; use OCP\ICache; use OCP\ICacheFactory; +use OCP\IConfig; use Test\TestCase; class MemoryCacheBackendTest extends TestCase { + /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + private $config; /** @var ICacheFactory|\PHPUnit\Framework\MockObject\MockObject */ private $cacheFactory; /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */ @@ -43,6 +31,7 @@ class MemoryCacheBackendTest extends TestCase { protected function setUp(): void { parent::setUp(); + $this->config = $this->createMock(IConfig::class); $this->cacheFactory = $this->createMock(ICacheFactory::class); $this->timeFactory = $this->createMock(ITimeFactory::class); $this->cache = $this->createMock(ICache::class); @@ -53,13 +42,18 @@ class MemoryCacheBackendTest extends TestCase { ->with('OC\Security\RateLimiting\Backend\MemoryCacheBackend') ->willReturn($this->cache); + $this->config->method('getSystemValueBool') + ->with('ratelimit.protection.enabled') + ->willReturn(true); + $this->memoryCache = new MemoryCacheBackend( + $this->config, $this->cacheFactory, $this->timeFactory ); } - public function testGetAttemptsWithNoAttemptsBefore() { + public function testGetAttemptsWithNoAttemptsBefore(): void { $this->cache ->expects($this->once()) ->method('get') @@ -69,7 +63,7 @@ class MemoryCacheBackendTest extends TestCase { $this->assertSame(0, $this->memoryCache->getAttempts('Method', 'User')); } - public function testGetAttempts() { + public function testGetAttempts(): void { $this->timeFactory ->expects($this->once()) ->method('getTime') @@ -90,7 +84,7 @@ class MemoryCacheBackendTest extends TestCase { $this->assertSame(3, $this->memoryCache->getAttempts('Method', 'User')); } - public function testRegisterAttemptWithNoAttemptsBefore() { + public function testRegisterAttemptWithNoAttemptsBefore(): void { $this->timeFactory ->expects($this->once()) ->method('getTime') @@ -112,7 +106,7 @@ class MemoryCacheBackendTest extends TestCase { $this->memoryCache->registerAttempt('Method', 'User', 100); } - public function testRegisterAttempt() { + public function testRegisterAttempt(): void { $this->timeFactory ->expects($this->once()) ->method('getTime') diff --git a/tests/lib/Security/RateLimiting/LimiterTest.php b/tests/lib/Security/RateLimiting/LimiterTest.php index a5b187fb546..b19d5c6feba 100644 --- a/tests/lib/Security/RateLimiting/LimiterTest.php +++ b/tests/lib/Security/RateLimiting/LimiterTest.php @@ -3,51 +3,42 @@ 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\Security\RateLimiting; use OC\Security\RateLimiting\Backend\IBackend; +use OC\Security\RateLimiting\Exception\RateLimitExceededException; use OC\Security\RateLimiting\Limiter; use OCP\IUser; +use OCP\Security\RateLimiting\ILimiter; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; use Test\TestCase; class LimiterTest extends TestCase { - /** @var IBackend|\PHPUnit\Framework\MockObject\MockObject */ - private $backend; - /** @var Limiter */ - private $limiter; + + private IBackend&MockObject $backend; + private ILimiter $limiter; + private LoggerInterface $logger; protected function setUp(): void { parent::setUp(); $this->backend = $this->createMock(IBackend::class); + $this->logger = $this->createMock(LoggerInterface::class); $this->limiter = new Limiter( - $this->backend + $this->backend, + $this->logger, ); } - public function testRegisterAnonRequestExceeded() { - $this->expectException(\OC\Security\RateLimiting\Exception\RateLimitExceededException::class); + public function testRegisterAnonRequestExceeded(): void { + $this->expectException(RateLimitExceededException::class); $this->expectExceptionMessage('Rate limit exceeded'); $this->backend @@ -58,11 +49,13 @@ class LimiterTest extends TestCase { '4664f0d9c88dcb7552be47b37bb52ce35977b2e60e1ac13757cf625f31f87050a41f3da064887fa87d49fd042e4c8eb20de8f10464877d3959677ab011b73a47' ) ->willReturn(101); + $this->logger->expects($this->once()) + ->method('info'); $this->limiter->registerAnonRequest('MyIdentifier', 100, 100, '127.0.0.1'); } - public function testRegisterAnonRequestSuccess() { + public function testRegisterAnonRequestSuccess(): void { $this->backend ->expects($this->once()) ->method('getAttempts') @@ -79,13 +72,15 @@ class LimiterTest extends TestCase { '4664f0d9c88dcb7552be47b37bb52ce35977b2e60e1ac13757cf625f31f87050a41f3da064887fa87d49fd042e4c8eb20de8f10464877d3959677ab011b73a47', 100 ); + $this->logger->expects($this->never()) + ->method('info'); $this->limiter->registerAnonRequest('MyIdentifier', 100, 100, '127.0.0.1'); } - public function testRegisterUserRequestExceeded() { - $this->expectException(\OC\Security\RateLimiting\Exception\RateLimitExceededException::class); + public function testRegisterUserRequestExceeded(): void { + $this->expectException(RateLimitExceededException::class); $this->expectExceptionMessage('Rate limit exceeded'); /** @var IUser|\PHPUnit\Framework\MockObject\MockObject $user */ @@ -102,11 +97,13 @@ class LimiterTest extends TestCase { 'ddb2ec50fa973fd49ecf3d816f677c8095143e944ad10485f30fb3dac85c13a346dace4dae2d0a15af91867320957bfd38a43d9eefbb74fe6919e15119b6d805' ) ->willReturn(101); + $this->logger->expects($this->once()) + ->method('info'); $this->limiter->registerUserRequest('MyIdentifier', 100, 100, $user); } - public function testRegisterUserRequestSuccess() { + public function testRegisterUserRequestSuccess(): void { /** @var IUser|\PHPUnit\Framework\MockObject\MockObject $user */ $user = $this->createMock(IUser::class); $user @@ -130,6 +127,8 @@ class LimiterTest extends TestCase { 'ddb2ec50fa973fd49ecf3d816f677c8095143e944ad10485f30fb3dac85c13a346dace4dae2d0a15af91867320957bfd38a43d9eefbb74fe6919e15119b6d805', 100 ); + $this->logger->expects($this->never()) + ->method('info'); $this->limiter->registerUserRequest('MyIdentifier', 100, 100, $user); } diff --git a/tests/lib/Security/RemoteHostValidatorIntegrationTest.php b/tests/lib/Security/RemoteHostValidatorIntegrationTest.php index 3cf99161b77..913acfa054d 100644 --- a/tests/lib/Security/RemoteHostValidatorIntegrationTest.php +++ b/tests/lib/Security/RemoteHostValidatorIntegrationTest.php @@ -2,25 +2,9 @@ declare(strict_types=1); -/* - * @copyright 2022 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author 2022 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @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: 2022 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace lib\Security; @@ -53,7 +37,7 @@ class RemoteHostValidatorIntegrationTest extends TestCase { ); } - public function localHostsData(): array { + public static function localHostsData(): array { return [ ['[::1]'], ['[::]'], @@ -89,9 +73,7 @@ class RemoteHostValidatorIntegrationTest extends TestCase { ]; } - /** - * @dataProvider localHostsData - */ + #[\PHPUnit\Framework\Attributes\DataProvider('localHostsData')] public function testLocalHostsWhenNotAllowed(string $host): void { $this->config ->method('getSystemValueBool') @@ -103,9 +85,7 @@ class RemoteHostValidatorIntegrationTest extends TestCase { self::assertFalse($isValid); } - /** - * @dataProvider localHostsData - */ + #[\PHPUnit\Framework\Attributes\DataProvider('localHostsData')] public function testLocalHostsWhenAllowed(string $host): void { $this->config ->method('getSystemValueBool') @@ -117,7 +97,7 @@ class RemoteHostValidatorIntegrationTest extends TestCase { self::assertTrue($isValid); } - public function externalAddressesData():array { + public static function externalAddressesData():array { return [ ['8.8.8.8'], ['8.8.4.4'], @@ -127,9 +107,7 @@ class RemoteHostValidatorIntegrationTest extends TestCase { ]; } - /** - * @dataProvider externalAddressesData - */ + #[\PHPUnit\Framework\Attributes\DataProvider('externalAddressesData')] public function testExternalHost(string $host): void { $this->config ->method('getSystemValueBool') diff --git a/tests/lib/Security/RemoteHostValidatorTest.php b/tests/lib/Security/RemoteHostValidatorTest.php index 030a75b1e79..b048b9dafd1 100644 --- a/tests/lib/Security/RemoteHostValidatorTest.php +++ b/tests/lib/Security/RemoteHostValidatorTest.php @@ -2,25 +2,9 @@ declare(strict_types=1); -/* - * @copyright 2022 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author 2022 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @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: 2022 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace lib\Security; @@ -60,8 +44,15 @@ class RemoteHostValidatorTest extends TestCase { ); } - public function testValid(): void { - $host = 'nextcloud.com'; + public static function dataValid(): array { + return [ + ['nextcloud.com', true], + ['com.one-.nextcloud-one.com', false], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataValid')] + public function testValid(string $host, bool $expected): void { $this->hostnameClassifier ->method('isLocalHostname') ->with($host) @@ -73,7 +64,7 @@ class RemoteHostValidatorTest extends TestCase { $valid = $this->validator->isValid($host); - self::assertTrue($valid); + self::assertSame($expected, $valid); } public function testLocalHostname(): void { diff --git a/tests/lib/Security/SecureRandomTest.php b/tests/lib/Security/SecureRandomTest.php index c7ee76a96bb..954fd85eaf1 100644 --- a/tests/lib/Security/SecureRandomTest.php +++ b/tests/lib/Security/SecureRandomTest.php @@ -3,10 +3,9 @@ declare(strict_types=1); /** - * Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Security; @@ -14,7 +13,7 @@ namespace Test\Security; use OC\Security\SecureRandom; class SecureRandomTest extends \Test\TestCase { - public function stringGenerationProvider() { + public static function stringGenerationProvider(): array { return [ [1, 1], [128, 128], @@ -25,7 +24,7 @@ class SecureRandomTest extends \Test\TestCase { ]; } - public static function charCombinations() { + public static function charCombinations(): array { return [ ['CHAR_LOWER', '[a-z]'], ['CHAR_UPPER', '[A-Z]'], @@ -38,56 +37,46 @@ class SecureRandomTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->rng = new \OC\Security\SecureRandom(); + $this->rng = new SecureRandom(); } - /** - * @dataProvider stringGenerationProvider - */ - public function testGetLowStrengthGeneratorLength($length, $expectedLength) { + #[\PHPUnit\Framework\Attributes\DataProvider('stringGenerationProvider')] + public function testGetLowStrengthGeneratorLength($length, $expectedLength): void { $generator = $this->rng; $this->assertEquals($expectedLength, strlen($generator->generate($length))); } - /** - * @dataProvider stringGenerationProvider - */ - public function testMediumLowStrengthGeneratorLength($length, $expectedLength) { + #[\PHPUnit\Framework\Attributes\DataProvider('stringGenerationProvider')] + public function testMediumLowStrengthGeneratorLength($length, $expectedLength): void { $generator = $this->rng; $this->assertEquals($expectedLength, strlen($generator->generate($length))); } - /** - * @dataProvider stringGenerationProvider - */ - public function testUninitializedGenerate($length, $expectedLength) { + #[\PHPUnit\Framework\Attributes\DataProvider('stringGenerationProvider')] + public function testUninitializedGenerate($length, $expectedLength): void { $this->assertEquals($expectedLength, strlen($this->rng->generate($length))); } - /** - * @dataProvider charCombinations - */ - public function testScheme($charName, $chars) { + #[\PHPUnit\Framework\Attributes\DataProvider('charCombinations')] + public function testScheme($charName, $chars): void { $generator = $this->rng; $scheme = constant('OCP\Security\ISecureRandom::' . $charName); $randomString = $generator->generate(100, $scheme); - $matchesRegex = preg_match('/^'.$chars.'+$/', $randomString); + $matchesRegex = preg_match('/^' . $chars . '+$/', $randomString); $this->assertSame(1, $matchesRegex); } - public static function invalidLengths() { + public static function invalidLengths(): array { return [ [0], [-1], ]; } - /** - * @dataProvider invalidLengths - */ - public function testInvalidLengths($length) { + #[\PHPUnit\Framework\Attributes\DataProvider('invalidLengths')] + public function testInvalidLengths($length): void { $this->expectException(\LengthException::class); $generator = $this->rng; $generator->generate($length); diff --git a/tests/lib/Security/TrustedDomainHelperTest.php b/tests/lib/Security/TrustedDomainHelperTest.php index 3fedf8964c5..8b671a93d06 100644 --- a/tests/lib/Security/TrustedDomainHelperTest.php +++ b/tests/lib/Security/TrustedDomainHelperTest.php @@ -3,10 +3,9 @@ declare(strict_types=1); /** - * Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Security; @@ -28,12 +27,12 @@ class TrustedDomainHelperTest extends \Test\TestCase { } /** - * @dataProvider trustedDomainDataProvider * @param string $trustedDomains * @param string $testDomain * @param bool $result */ - public function testIsTrustedUrl($trustedDomains, $testDomain, $result) { + #[\PHPUnit\Framework\Attributes\DataProvider('trustedDomainDataProvider')] + public function testIsTrustedUrl($trustedDomains, $testDomain, $result): void { $this->config->method('getSystemValue') ->willReturnMap([ ['overwritehost', '', ''], @@ -45,12 +44,12 @@ class TrustedDomainHelperTest extends \Test\TestCase { } /** - * @dataProvider trustedDomainDataProvider * @param string $trustedDomains * @param string $testDomain * @param bool $result */ - public function testIsTrustedDomain($trustedDomains, $testDomain, $result) { + #[\PHPUnit\Framework\Attributes\DataProvider('trustedDomainDataProvider')] + public function testIsTrustedDomain($trustedDomains, $testDomain, $result): void { $this->config->method('getSystemValue') ->willReturnMap([ ['overwritehost', '', ''], @@ -64,7 +63,7 @@ class TrustedDomainHelperTest extends \Test\TestCase { /** * @return array */ - public function trustedDomainDataProvider() { + public static function trustedDomainDataProvider(): array { $trustedHostTestList = [ 'host.one.test', 'host.two.test', @@ -135,7 +134,7 @@ class TrustedDomainHelperTest extends \Test\TestCase { ]; } - public function testIsTrustedDomainOverwriteHost() { + public function testIsTrustedDomainOverwriteHost(): void { $this->config->method('getSystemValue') ->with('overwritehost') ->willReturn('myproxyhost'); diff --git a/tests/lib/Security/VerificationToken/VerificationTokenTest.php b/tests/lib/Security/VerificationToken/VerificationTokenTest.php index 481646f26ab..7123cc8b013 100644 --- a/tests/lib/Security/VerificationToken/VerificationTokenTest.php +++ b/tests/lib/Security/VerificationToken/VerificationTokenTest.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2021 Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @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 <https://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Security\VerificationToken; @@ -34,8 +17,8 @@ use OCP\IUser; use OCP\Security\ICrypto; use OCP\Security\ISecureRandom; use OCP\Security\VerificationToken\InvalidTokenException; -use Test\TestCase; use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; class VerificationTokenTest extends TestCase { /** @var VerificationToken */ @@ -69,13 +52,13 @@ class VerificationTokenTest extends TestCase { ); } - public function testTokenUserUnknown() { + public function testTokenUserUnknown(): void { $this->expectException(InvalidTokenException::class); $this->expectExceptionCode(InvalidTokenException::USER_UNKNOWN); $this->token->check('encryptedToken', null, 'fingerprintToken', 'foobar'); } - public function testTokenUserUnknown2() { + public function testTokenUserUnknown2(): void { $user = $this->createMock(IUser::class); $user->expects($this->atLeastOnce()) ->method('isEnabled') @@ -86,7 +69,7 @@ class VerificationTokenTest extends TestCase { $this->token->check('encryptedToken', $user, 'fingerprintToken', 'foobar'); } - public function testTokenNotFound() { + public function testTokenNotFound(): void { $user = $this->createMock(IUser::class); $user->expects($this->atLeastOnce()) ->method('isEnabled') @@ -102,7 +85,7 @@ class VerificationTokenTest extends TestCase { $this->token->check('encryptedToken', $user, 'fingerprintToken', 'foobar'); } - public function testTokenDecryptionError() { + public function testTokenDecryptionError(): void { $user = $this->createMock(IUser::class); $user->expects($this->atLeastOnce()) ->method('isEnabled') @@ -116,7 +99,7 @@ class VerificationTokenTest extends TestCase { ->with('alice', 'core', 'fingerprintToken', null) ->willReturn('encryptedToken'); $this->config->expects($this->any()) - ->method('getSystemValue') + ->method('getSystemValueString') ->with('secret') ->willReturn('357111317'); @@ -129,7 +112,7 @@ class VerificationTokenTest extends TestCase { $this->token->check('encryptedToken', $user, 'fingerprintToken', 'foobar'); } - public function testTokenInvalidFormat() { + public function testTokenInvalidFormat(): void { $user = $this->createMock(IUser::class); $user->expects($this->atLeastOnce()) ->method('isEnabled') @@ -143,7 +126,7 @@ class VerificationTokenTest extends TestCase { ->with('alice', 'core', 'fingerprintToken', null) ->willReturn('encryptedToken'); $this->config->expects($this->any()) - ->method('getSystemValue') + ->method('getSystemValueString') ->with('secret') ->willReturn('357111317'); @@ -156,7 +139,7 @@ class VerificationTokenTest extends TestCase { $this->token->check('encryptedToken', $user, 'fingerprintToken', 'foobar'); } - public function testTokenExpired() { + public function testTokenExpired(): void { $user = $this->createMock(IUser::class); $user->expects($this->atLeastOnce()) ->method('isEnabled') @@ -173,7 +156,7 @@ class VerificationTokenTest extends TestCase { ->with('alice', 'core', 'fingerprintToken', null) ->willReturn('encryptedToken'); $this->config->expects($this->any()) - ->method('getSystemValue') + ->method('getSystemValueString') ->with('secret') ->willReturn('357111317'); @@ -190,7 +173,7 @@ class VerificationTokenTest extends TestCase { $this->token->check('encryptedToken', $user, 'fingerprintToken', 'foobar'); } - public function testTokenExpiredByLogin() { + public function testTokenExpiredByLogin(): void { $user = $this->createMock(IUser::class); $user->expects($this->atLeastOnce()) ->method('isEnabled') @@ -207,7 +190,7 @@ class VerificationTokenTest extends TestCase { ->with('alice', 'core', 'fingerprintToken', null) ->willReturn('encryptedToken'); $this->config->expects($this->any()) - ->method('getSystemValue') + ->method('getSystemValueString') ->with('secret') ->willReturn('357111317'); @@ -224,7 +207,7 @@ class VerificationTokenTest extends TestCase { $this->token->check('encryptedToken', $user, 'fingerprintToken', 'foobar', true); } - public function testTokenMismatch() { + public function testTokenMismatch(): void { $user = $this->createMock(IUser::class); $user->expects($this->atLeastOnce()) ->method('isEnabled') @@ -241,7 +224,7 @@ class VerificationTokenTest extends TestCase { ->with('alice', 'core', 'fingerprintToken', null) ->willReturn('encryptedToken'); $this->config->expects($this->any()) - ->method('getSystemValue') + ->method('getSystemValueString') ->with('secret') ->willReturn('357111317'); @@ -258,7 +241,7 @@ class VerificationTokenTest extends TestCase { $this->token->check('encryptedToken', $user, 'fingerprintToken', 'foobar'); } - public function testTokenSuccess() { + public function testTokenSuccess(): void { $user = $this->createMock(IUser::class); $user->expects($this->atLeastOnce()) ->method('isEnabled') @@ -275,7 +258,7 @@ class VerificationTokenTest extends TestCase { ->with('alice', 'core', 'fingerprintToken', null) ->willReturn('encryptedToken'); $this->config->expects($this->any()) - ->method('getSystemValue') + ->method('getSystemValueString') ->with('secret') ->willReturn('357111317'); @@ -290,7 +273,7 @@ class VerificationTokenTest extends TestCase { $this->token->check('barfoo', $user, 'fingerprintToken', 'foobar'); } - public function testCreate() { + public function testCreate(): void { $user = $this->createMock(IUser::class); $user->expects($this->any()) ->method('getUID') |