diff options
Diffstat (limited to 'tests/lib/Security/Ip')
-rw-r--r-- | tests/lib/Security/Ip/BruteforceAllowListTest.php | 161 | ||||
-rw-r--r-- | tests/lib/Security/Ip/RemoteAddressTest.php | 79 |
2 files changed, 240 insertions, 0 deletions
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], + ]; + } +} |