diff options
Diffstat (limited to 'tests/lib/AppFramework/Http/RequestTest.php')
-rw-r--r-- | tests/lib/AppFramework/Http/RequestTest.php | 1196 |
1 files changed, 657 insertions, 539 deletions
diff --git a/tests/lib/AppFramework/Http/RequestTest.php b/tests/lib/AppFramework/Http/RequestTest.php index 7260b31b27e..7ea2cb31482 100644 --- a/tests/lib/AppFramework/Http/RequestTest.php +++ b/tests/lib/AppFramework/Http/RequestTest.php @@ -1,20 +1,17 @@ <?php + /** - * @copyright 2013 Thomas Tanghus (thomas@tanghus.net) - * @copyright 2016 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\AppFramework\Http; use OC\AppFramework\Http\Request; use OC\Security\CSRF\CsrfToken; use OC\Security\CSRF\CsrfTokenManager; use OCP\IConfig; -use OCP\Security\ISecureRandom; +use OCP\IRequestId; /** * Class RequestTest @@ -24,8 +21,8 @@ use OCP\Security\ISecureRandom; class RequestTest extends \Test\TestCase { /** @var string */ protected $stream = 'fakeinput://data'; - /** @var ISecureRandom */ - protected $secureRandom; + /** @var IRequestId */ + protected $requestId; /** @var IConfig */ protected $config; /** @var CsrfTokenManager */ @@ -39,10 +36,11 @@ class RequestTest extends \Test\TestCase { } stream_wrapper_register('fakeinput', 'Test\AppFramework\Http\RequestStream'); - $this->secureRandom = $this->getMockBuilder('\OCP\Security\ISecureRandom')->getMock(); - $this->config = $this->getMockBuilder(IConfig::class)->getMock(); - $this->csrfTokenManager = $this->getMockBuilder('\OC\Security\CSRF\CsrfTokenManager') - ->disableOriginalConstructor()->getMock(); + $this->requestId = $this->createMock(IRequestId::class); + $this->config = $this->createMock(IConfig::class); + $this->csrfTokenManager = $this->getMockBuilder(CsrfTokenManager::class) + ->disableOriginalConstructor() + ->getMock(); } protected function tearDown(): void { @@ -50,7 +48,7 @@ class RequestTest extends \Test\TestCase { parent::tearDown(); } - public function testRequestAccessors() { + public function testRequestAccessors(): void { $vars = [ 'get' => ['name' => 'John Q. Public', 'nickname' => 'Joey'], 'method' => 'GET', @@ -58,7 +56,7 @@ class RequestTest extends \Test\TestCase { $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -80,7 +78,7 @@ class RequestTest extends \Test\TestCase { } // urlParams has precedence over POST which has precedence over GET - public function testPrecedence() { + public function testPrecedence(): void { $vars = [ 'get' => ['name' => 'John Q. Public', 'nickname' => 'Joey'], 'post' => ['name' => 'Jane Doe', 'nickname' => 'Janey'], @@ -90,7 +88,7 @@ class RequestTest extends \Test\TestCase { $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -103,7 +101,7 @@ class RequestTest extends \Test\TestCase { - public function testImmutableArrayAccess() { + public function testImmutableArrayAccess(): void { $this->expectException(\RuntimeException::class); $vars = [ @@ -113,7 +111,7 @@ class RequestTest extends \Test\TestCase { $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -123,7 +121,7 @@ class RequestTest extends \Test\TestCase { } - public function testImmutableMagicAccess() { + public function testImmutableMagicAccess(): void { $this->expectException(\RuntimeException::class); $vars = [ @@ -133,7 +131,7 @@ class RequestTest extends \Test\TestCase { $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -143,7 +141,7 @@ class RequestTest extends \Test\TestCase { } - public function testGetTheMethodRight() { + public function testGetTheMethodRight(): void { $this->expectException(\LogicException::class); $vars = [ @@ -153,7 +151,7 @@ class RequestTest extends \Test\TestCase { $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -162,7 +160,7 @@ class RequestTest extends \Test\TestCase { $request->post; } - public function testTheMethodIsRight() { + public function testTheMethodIsRight(): void { $vars = [ 'get' => ['name' => 'John Q. Public', 'nickname' => 'Joey'], 'method' => 'GET', @@ -170,7 +168,7 @@ class RequestTest extends \Test\TestCase { $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -182,7 +180,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('Joey', $result['nickname']); } - public function testJsonPost() { + public function testJsonPost(): void { global $data; $data = '{"name": "John Q. Public", "nickname": "Joey"}'; $vars = [ @@ -192,7 +190,7 @@ class RequestTest extends \Test\TestCase { $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -206,9 +204,66 @@ class RequestTest extends \Test\TestCase { $this->assertSame('Joey', $request['nickname']); } - public function testNotJsonPost() { + public function testScimJsonPost(): void { global $data; - $data = 'this is not valid json'; + $data = '{"userName":"testusername", "displayName":"Example User"}'; + $vars = [ + 'method' => 'POST', + 'server' => ['CONTENT_TYPE' => 'application/scim+json; utf-8'] + ]; + + $request = new Request( + $vars, + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertSame('POST', $request->method); + $result = $request->post; + $this->assertSame('testusername', $result['userName']); + $this->assertSame('Example User', $result['displayName']); + $this->assertSame('Example User', $request->params['displayName']); + $this->assertSame('Example User', $request['displayName']); + } + + public function testCustomJsonPost(): void { + global $data; + $data = '{"propertyA":"sometestvalue", "propertyB":"someothertestvalue"}'; + + // Note: the content type used here is fictional and intended to check if the regex for JSON content types works fine + $vars = [ + 'method' => 'POST', + 'server' => ['CONTENT_TYPE' => 'application/custom-type+json; utf-8'] + ]; + + $request = new Request( + $vars, + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertSame('POST', $request->method); + $result = $request->post; + $this->assertSame('sometestvalue', $result['propertyA']); + $this->assertSame('someothertestvalue', $result['propertyB']); + } + + public static function dataNotJsonData(): array { + return [ + ['this is not valid json'], + ['"just a string"'], + ['{"just a string"}'], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataNotJsonData')] + public function testNotJsonPost(string $testData): void { + global $data; + $data = $testData; $vars = [ 'method' => 'POST', 'server' => ['CONTENT_TYPE' => 'application/json; utf-8'] @@ -216,7 +271,28 @@ class RequestTest extends \Test\TestCase { $request = new Request( $vars, - $this->secureRandom, + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertEquals('POST', $request->method); + $result = $request->post; + // ensure there's no error attempting to decode the content + } + + public function testNotScimJsonPost(): void { + global $data; + $data = 'this is not valid scim json'; + $vars = [ + 'method' => 'POST', + 'server' => ['CONTENT_TYPE' => 'application/scim+json; utf-8'] + ]; + + $request = new Request( + $vars, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -227,7 +303,28 @@ class RequestTest extends \Test\TestCase { // ensure there's no error attempting to decode the content } - public function testPatch() { + public function testNotCustomJsonPost(): void { + global $data; + $data = 'this is not valid json'; + $vars = [ + 'method' => 'POST', + 'server' => ['CONTENT_TYPE' => 'application/custom-type+json; utf-8'] + ]; + + $request = new Request( + $vars, + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertEquals('POST', $request->method); + $result = $request->post; + // ensure there's no error attempting to decode the content + } + + public function testPatch(): void { global $data; $data = http_build_query(['name' => 'John Q. Public', 'nickname' => 'Joey'], '', '&'); @@ -238,7 +335,7 @@ class RequestTest extends \Test\TestCase { $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -251,7 +348,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('Joey', $result['nickname']); } - public function testJsonPatchAndPut() { + public function testJsonPatchAndPut(): void { global $data; // PUT content @@ -263,7 +360,7 @@ class RequestTest extends \Test\TestCase { $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -284,7 +381,7 @@ class RequestTest extends \Test\TestCase { $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -297,373 +394,342 @@ class RequestTest extends \Test\TestCase { $this->assertSame(null, $result['nickname']); } - public function testPutStream() { + public function testScimJsonPatchAndPut(): void { global $data; - $data = file_get_contents(__DIR__ . '/../../../data/testimage.png'); + // PUT content + $data = '{"userName": "sometestusername", "displayName": "Example User"}'; $vars = [ - 'put' => $data, 'method' => 'PUT', - 'server' => [ - 'CONTENT_TYPE' => 'image/png', - 'CONTENT_LENGTH' => (string)strlen($data) - ], + 'server' => ['CONTENT_TYPE' => 'application/scim+json; utf-8'], ]; $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); $this->assertSame('PUT', $request->method); - $resource = $request->put; - $contents = stream_get_contents($resource); - $this->assertSame($data, $contents); - - try { - $resource = $request->put; - } catch (\LogicException $e) { - return; - } - $this->fail('Expected LogicException.'); - } + $result = $request->put; + $this->assertSame('sometestusername', $result['userName']); + $this->assertSame('Example User', $result['displayName']); - public function testSetUrlParameters() { + // PATCH content + $data = '{"userName": "sometestusername", "displayName": null}'; $vars = [ - 'post' => [], - 'method' => 'POST', - 'urlParams' => ['id' => '2'], + 'method' => 'PATCH', + 'server' => ['CONTENT_TYPE' => 'application/scim+json; utf-8'], ]; $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $newParams = ['id' => '3', 'test' => 'test2']; - $request->setUrlParameters($newParams); - $this->assertSame('test2', $request->getParam('test')); - $this->assertEquals('3', $request->getParam('id')); - $this->assertEquals('3', $request->getParams()['id']); + $this->assertSame('PATCH', $request->method); + $result = $request->patch; + + $this->assertSame('sometestusername', $result['userName']); + $this->assertSame(null, $result['displayName']); } - public function testGetIdWithModUnique() { + public function testCustomJsonPatchAndPut(): void { + global $data; + + // PUT content + $data = '{"propertyA": "sometestvalue", "propertyB": "someothertestvalue"}'; $vars = [ - 'server' => [ - 'UNIQUE_ID' => 'GeneratedUniqueIdByModUnique' - ], + 'method' => 'PUT', + 'server' => ['CONTENT_TYPE' => 'application/custom-type+json; utf-8'], ]; $request = new Request( $vars, - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('GeneratedUniqueIdByModUnique', $request->getId()); - } + $this->assertSame('PUT', $request->method); + $result = $request->put; - public function testGetIdWithoutModUnique() { - $this->secureRandom->expects($this->once()) - ->method('generate') - ->with('20') - ->willReturn('GeneratedByOwnCloudItself'); + $this->assertSame('sometestvalue', $result['propertyA']); + $this->assertSame('someothertestvalue', $result['propertyB']); + + // PATCH content + $data = '{"propertyA": "sometestvalue", "propertyB": null}'; + $vars = [ + 'method' => 'PATCH', + 'server' => ['CONTENT_TYPE' => 'application/custom-type+json; utf-8'], + ]; $request = new Request( - [], - $this->secureRandom, + $vars, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('GeneratedByOwnCloudItself', $request->getId()); + $this->assertSame('PATCH', $request->method); + $result = $request->patch; + + $this->assertSame('sometestvalue', $result['propertyA']); + $this->assertSame(null, $result['propertyB']); } - public function testGetIdWithoutModUniqueStable() { + public function testPutStream(): void { + global $data; + $data = file_get_contents(__DIR__ . '/../../../data/testimage.png'); + + $vars = [ + 'put' => $data, + 'method' => 'PUT', + 'server' => [ + 'CONTENT_TYPE' => 'image/png', + 'CONTENT_LENGTH' => (string)strlen($data) + ], + ]; + $request = new Request( - [], - \OC::$server->getSecureRandom(), + $vars, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $firstId = $request->getId(); - $secondId = $request->getId(); - $this->assertSame($firstId, $secondId); + + $this->assertSame('PUT', $request->method); + $resource = $request->put; + $contents = stream_get_contents($resource); + $this->assertSame($data, $contents); + + try { + $resource = $request->put; + } catch (\LogicException $e) { + return; + } + $this->fail('Expected LogicException.'); } - public function testGetRemoteAddressWithoutTrustedRemote() { - $this->config - ->expects($this->once()) - ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn([]); + + public function testSetUrlParameters(): void { + $vars = [ + 'post' => [], + 'method' => 'POST', + 'urlParams' => ['id' => '2'], + ]; $request = new Request( - [ - 'server' => [ - 'REMOTE_ADDR' => '10.0.0.2', - 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' - ], - ], - $this->secureRandom, + $vars, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('10.0.0.2', $request->getRemoteAddress()); + $newParams = ['id' => '3', 'test' => 'test2']; + $request->setUrlParameters($newParams); + $this->assertSame('test2', $request->getParam('test')); + $this->assertEquals('3', $request->getParam('id')); + $this->assertEquals('3', $request->getParams()['id']); } - public function testGetRemoteAddressWithNoTrustedHeader() { - $this->config - ->expects($this->at(0)) - ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn(['10.0.0.2']); - $this->config - ->expects($this->at(1)) - ->method('getSystemValue') - ->with('forwarded_for_headers') - ->willReturn([]); - - $request = new Request( - [ - 'server' => [ + public static function dataGetRemoteAddress(): array { + return [ + 'IPv4 without trusted remote' => [ + [ 'REMOTE_ADDR' => '10.0.0.2', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], + [], + [], + '10.0.0.2', ], - $this->secureRandom, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('10.0.0.2', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressWithSingleTrustedRemote() { - $this->config - ->expects($this->at(0)) - ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn(['10.0.0.2']); - $this->config - ->expects($this->at(1)) - ->method('getSystemValue') - ->with('forwarded_for_headers') - ->willReturn(['HTTP_X_FORWARDED']); - - $request = new Request( - [ - 'server' => [ + 'IPv4 without trusted headers' => [ + [ 'REMOTE_ADDR' => '10.0.0.2', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], + ['10.0.0.2'], + [], + '10.0.0.2', ], - $this->secureRandom, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('10.4.0.5', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressIPv6WithSingleTrustedRemote() { - $this->config - ->expects($this->at(0)) - ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn(['2001:db8:85a3:8d3:1319:8a2e:370:7348']); - $this->config - ->expects($this->at(1)) - ->method('getSystemValue') - ->with('forwarded_for_headers') - ->willReturn(['HTTP_X_FORWARDED']); - - $request = new Request( - [ - 'server' => [ + 'IPv4 with single trusted remote' => [ + [ + 'REMOTE_ADDR' => '10.0.0.2', + 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', + ], + ['10.0.0.2'], + ['HTTP_X_FORWARDED'], + '10.4.0.4', + ], + 'IPv6 with single trusted remote' => [ + [ 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], + ['2001:db8:85a3:8d3:1319:8a2e:370:7348'], + ['HTTP_X_FORWARDED'], + '10.4.0.4', ], - $this->secureRandom, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('10.4.0.5', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressVerifyPriorityHeader() { - $this->config - ->expects($this->at(0)) - ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn(['10.0.0.2']); - $this->config - ->expects($this->at(1)) - ->method('getSystemValue') - ->with('forwarded_for_headers') - ->willReturn([ - 'HTTP_CLIENT_IP', - 'HTTP_X_FORWARDED_FOR', - 'HTTP_X_FORWARDED' - ]); - - $request = new Request( - [ - 'server' => [ + 'IPv4 with multiple trusted remotes' => [ + [ + 'REMOTE_ADDR' => '10.0.0.2', + 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4, ::1', + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', + ], + ['10.0.0.2', '::1'], + ['HTTP_X_FORWARDED'], + '10.4.0.4', + ], + 'IPv4 order of forwarded-for headers' => [ + [ 'REMOTE_ADDR' => '10.0.0.2', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], + ['10.0.0.2'], + [ + 'HTTP_X_FORWARDED', + 'HTTP_X_FORWARDED_FOR', + 'HTTP_CLIENT_IP', + ], + '192.168.0.233', ], - $this->secureRandom, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('192.168.0.233', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressIPv6VerifyPriorityHeader() { - $this->config - ->expects($this->at(0)) - ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn(['2001:db8:85a3:8d3:1319:8a2e:370:7348']); - $this->config - ->expects($this->at(1)) - ->method('getSystemValue') - ->with('forwarded_for_headers') - ->willReturn([ - 'HTTP_CLIENT_IP', - 'HTTP_X_FORWARDED_FOR', - 'HTTP_X_FORWARDED' - ]); - - $request = new Request( - [ - 'server' => [ - 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348', + 'IPv4 order of forwarded-for headers (reversed)' => [ + [ + 'REMOTE_ADDR' => '10.0.0.2', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], + ['10.0.0.2'], + [ + 'HTTP_CLIENT_IP', + 'HTTP_X_FORWARDED_FOR', + 'HTTP_X_FORWARDED', + ], + '10.4.0.4', ], - $this->secureRandom, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('192.168.0.233', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressWithMatchingCidrTrustedRemote() { - $this->config - ->expects($this->at(0)) - ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn(['192.168.2.0/24']); - $this->config - ->expects($this->at(1)) - ->method('getSystemValue') - ->with('forwarded_for_headers') - ->willReturn(['HTTP_X_FORWARDED_FOR']); - - $request = new Request( - [ - 'server' => [ - 'REMOTE_ADDR' => '192.168.2.99', + 'IPv6 order of forwarded-for headers' => [ + [ + 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', + ], + ['2001:db8:85a3:8d3:1319:8a2e:370:7348'], + [ + 'HTTP_X_FORWARDED', + 'HTTP_X_FORWARDED_FOR', + 'HTTP_CLIENT_IP', ], + '192.168.0.233', ], - $this->secureRandom, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('192.168.0.233', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressWithNotMatchingCidrTrustedRemote() { - $this->config - ->expects($this->once()) - ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn(['192.168.2.0/24']); - - $request = new Request( - [ - 'server' => [ + 'IPv4 matching CIDR of trusted proxy' => [ + [ 'REMOTE_ADDR' => '192.168.3.99', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], + ['192.168.2.0/24'], + ['HTTP_X_FORWARDED_FOR'], + '192.168.3.99', ], - $this->secureRandom, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('192.168.3.99', $request->getRemoteAddress()); + 'IPv6 matching CIDR of trusted proxy' => [ + [ + 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a21:370:7348', + 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', + ], + ['2001:db8:85a3:8d3:1319:8a20::/95'], + ['HTTP_X_FORWARDED_FOR'], + '192.168.0.233', + ], + 'IPv6 not matching CIDR of trusted proxy' => [ + [ + 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348', + 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', + ], + ['fd::/8'], + [], + '2001:db8:85a3:8d3:1319:8a2e:370:7348', + ], + 'IPv6 with invalid trusted proxy' => [ + [ + 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348', + 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', + ], + ['fx::/8'], + [], + '2001:db8:85a3:8d3:1319:8a2e:370:7348', + ], + 'IPv4 forwarded for IPv6' => [ + [ + 'REMOTE_ADDR' => '192.168.2.99', + 'HTTP_X_FORWARDED_FOR' => '[2001:db8:85a3:8d3:1319:8a2e:370:7348]', + ], + ['192.168.2.0/24'], + ['HTTP_X_FORWARDED_FOR'], + '2001:db8:85a3:8d3:1319:8a2e:370:7348', + ], + 'IPv4 with port' => [ + [ + 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348', + 'HTTP_X_FORWARDED_FOR' => '192.168.2.99:8080', + ], + ['2001:db8::/8'], + ['HTTP_X_FORWARDED_FOR'], + '192.168.2.99', + ], + 'IPv6 with port' => [ + [ + 'REMOTE_ADDR' => '192.168.2.99', + 'HTTP_X_FORWARDED_FOR' => '[2001:db8:85a3:8d3:1319:8a2e:370:7348]:8080', + ], + ['192.168.2.0/24'], + ['HTTP_X_FORWARDED_FOR'], + '2001:db8:85a3:8d3:1319:8a2e:370:7348', + ], + ]; } - public function testGetRemoteAddressWithXForwardedForIPv6() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetRemoteAddress')] + public function testGetRemoteAddress(array $headers, array $trustedProxies, array $forwardedForHeaders, string $expected): void { $this->config - ->expects($this->at(0)) ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn(['192.168.2.0/24']); - $this->config - ->expects($this->at(1)) - ->method('getSystemValue') - ->with('forwarded_for_headers') - ->willReturn(['HTTP_X_FORWARDED_FOR']); + ->willReturnMap([ + ['trusted_proxies', [], $trustedProxies], + ['forwarded_for_headers', ['HTTP_X_FORWARDED_FOR'], $forwardedForHeaders], + ]); $request = new Request( [ - 'server' => [ - 'REMOTE_ADDR' => '192.168.2.99', - 'HTTP_X_FORWARDED_FOR' => '[2001:db8:85a3:8d3:1319:8a2e:370:7348]', - ], + 'server' => $headers, ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('2001:db8:85a3:8d3:1319:8a2e:370:7348', $request->getRemoteAddress()); + $this->assertSame($expected, $request->getRemoteAddress()); } - /** - * @return array - */ - public function httpProtocolProvider() { + public static function dataHttpProtocol(): array { return [ // Valid HTTP 1.0 ['HTTP/1.0', 'HTTP/1.0'], @@ -690,19 +756,19 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider httpProtocolProvider * * @param mixed $input * @param string $expected */ - public function testGetHttpProtocol($input, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataHttpProtocol')] + public function testGetHttpProtocol($input, $expected): void { $request = new Request( [ 'server' => [ 'SERVER_PROTOCOL' => $input, ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -711,35 +777,47 @@ class RequestTest extends \Test\TestCase { $this->assertSame($expected, $request->getHttpProtocol()); } - public function testGetServerProtocolWithOverride() { - $this->config - ->expects($this->at(0)) - ->method('getSystemValue') - ->with('overwriteprotocol') - ->willReturn('customProtocol'); + public function testGetServerProtocolWithOverrideValid(): void { $this->config - ->expects($this->at(1)) - ->method('getSystemValue') - ->with('overwritecondaddr') - ->willReturn(''); + ->expects($this->exactly(3)) + ->method('getSystemValueString') + ->willReturnMap([ + ['overwriteprotocol', '', 'HTTPS'], // should be automatically lowercased + ['overwritecondaddr', '', ''], + ]); + + $request = new Request( + [], + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertSame('https', $request->getServerProtocol()); + } + + public function testGetServerProtocolWithOverrideInValid(): void { $this->config - ->expects($this->at(2)) - ->method('getSystemValue') - ->with('overwriteprotocol') - ->willReturn('customProtocol'); + ->expects($this->exactly(3)) + ->method('getSystemValueString') + ->willReturnMap([ + ['overwriteprotocol', '', 'bogusProtocol'], // should trigger fallback to http + ['overwritecondaddr', '', ''], + ]); $request = new Request( [], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('customProtocol', $request->getServerProtocol()); + $this->assertSame('http', $request->getServerProtocol()); } - public function testGetServerProtocolWithProtoValid() { + public function testGetServerProtocolWithProtoValid(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -757,7 +835,7 @@ class RequestTest extends \Test\TestCase { 'REMOTE_ADDR' => '1.2.3.4', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -769,7 +847,7 @@ class RequestTest extends \Test\TestCase { 'REMOTE_ADDR' => '1.2.3.4', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -780,7 +858,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('http', $requestHttp->getServerProtocol()); } - public function testGetServerProtocolWithHttpsServerValueOn() { + public function testGetServerProtocolWithHttpsServerValueOn(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -793,7 +871,7 @@ class RequestTest extends \Test\TestCase { 'HTTPS' => 'on' ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -801,7 +879,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('https', $request->getServerProtocol()); } - public function testGetServerProtocolWithHttpsServerValueOff() { + public function testGetServerProtocolWithHttpsServerValueOff(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -814,7 +892,7 @@ class RequestTest extends \Test\TestCase { 'HTTPS' => 'off' ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -822,7 +900,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('http', $request->getServerProtocol()); } - public function testGetServerProtocolWithHttpsServerValueEmpty() { + public function testGetServerProtocolWithHttpsServerValueEmpty(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -835,7 +913,7 @@ class RequestTest extends \Test\TestCase { 'HTTPS' => '' ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -843,7 +921,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('http', $request->getServerProtocol()); } - public function testGetServerProtocolDefault() { + public function testGetServerProtocolDefault(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -852,7 +930,7 @@ class RequestTest extends \Test\TestCase { $request = new Request( [], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -860,7 +938,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('http', $request->getServerProtocol()); } - public function testGetServerProtocolBehindLoadBalancers() { + public function testGetServerProtocolBehindLoadBalancers(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -878,7 +956,7 @@ class RequestTest extends \Test\TestCase { 'REMOTE_ADDR' => '1.2.3.4', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -888,19 +966,19 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider userAgentProvider * @param string $testAgent * @param array $userAgent * @param bool $matches */ - public function testUserAgent($testAgent, $userAgent, $matches) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataUserAgent')] + public function testUserAgent($testAgent, $userAgent, $matches): void { $request = new Request( [ 'server' => [ 'HTTP_USER_AGENT' => $testAgent, ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -910,15 +988,15 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider userAgentProvider * @param string $testAgent * @param array $userAgent * @param bool $matches */ - public function testUndefinedUserAgent($testAgent, $userAgent, $matches) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataUserAgent')] + public function testUndefinedUserAgent($testAgent, $userAgent, $matches): void { $request = new Request( [], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -927,10 +1005,7 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->isUserAgent($userAgent)); } - /** - * @return array - */ - public function userAgentProvider() { + public static function dataUserAgent(): array { return [ [ 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)', @@ -1049,23 +1124,80 @@ class RequestTest extends \Test\TestCase { ]; } - public function testInsecureServerHostServerNameHeader() { + public static function dataMatchClientVersion(): array { + return [ + [ + 'Mozilla/5.0 (Android) Nextcloud-android/3.24.1', + Request::USER_AGENT_CLIENT_ANDROID, + '3.24.1', + ], + [ + 'Mozilla/5.0 (iOS) Nextcloud-iOS/4.8.2', + Request::USER_AGENT_CLIENT_IOS, + '4.8.2', + ], + [ + 'Mozilla/5.0 (Windows) mirall/3.8.1', + Request::USER_AGENT_CLIENT_DESKTOP, + '3.8.1', + ], + [ + 'Mozilla/5.0 (Android) Nextcloud-Talk v17.10.0', + Request::USER_AGENT_TALK_ANDROID, + '17.10.0', + ], + [ + 'Mozilla/5.0 (iOS) Nextcloud-Talk v17.0.1', + Request::USER_AGENT_TALK_IOS, + '17.0.1', + ], + [ + 'Mozilla/5.0 (Windows) Nextcloud-Talk v0.6.0', + Request::USER_AGENT_TALK_DESKTOP, + '0.6.0', + ], + [ + 'Mozilla/5.0 (Windows) Nextcloud-Outlook v1.0.0', + Request::USER_AGENT_OUTLOOK_ADDON, + '1.0.0', + ], + [ + 'Filelink for *cloud/1.0.0', + Request::USER_AGENT_THUNDERBIRD_ADDON, + '1.0.0', + ], + ]; + } + + /** + * @param string $testAgent + * @param string $userAgent + * @param string $version + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataMatchClientVersion')] + public function testMatchClientVersion(string $testAgent, string $userAgent, string $version): void { + preg_match($userAgent, $testAgent, $matches); + + $this->assertSame($version, $matches[1]); + } + + public function testInsecureServerHostServerNameHeader(): void { $request = new Request( [ 'server' => [ 'SERVER_NAME' => 'from.server.name:8080', ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('from.server.name:8080', $request->getInsecureServerHost()); + $this->assertSame('from.server.name:8080', $request->getInsecureServerHost()); } - public function testInsecureServerHostHttpHostHeader() { + public function testInsecureServerHostHttpHostHeader(): void { $request = new Request( [ 'server' => [ @@ -1073,16 +1205,16 @@ class RequestTest extends \Test\TestCase { 'HTTP_HOST' => 'from.host.header:8080', ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('from.host.header:8080', $request->getInsecureServerHost()); + $this->assertSame('from.host.header:8080', $request->getInsecureServerHost()); } - public function testInsecureServerHostHttpFromForwardedHeaderSingle() { + public function testInsecureServerHostHttpFromForwardedHeaderSingle(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1102,16 +1234,16 @@ class RequestTest extends \Test\TestCase { 'REMOTE_ADDR' => '1.2.3.4', ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('from.forwarded.host:8080', $request->getInsecureServerHost()); + $this->assertSame('from.forwarded.host:8080', $request->getInsecureServerHost()); } - public function testInsecureServerHostHttpFromForwardedHeaderStacked() { + public function testInsecureServerHostHttpFromForwardedHeaderStacked(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1131,18 +1263,18 @@ class RequestTest extends \Test\TestCase { 'REMOTE_ADDR' => '1.2.3.4', ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('from.forwarded.host2:8080', $request->getInsecureServerHost()); + $this->assertSame('from.forwarded.host2:8080', $request->getInsecureServerHost()); } - public function testGetServerHostWithOverwriteHost() { + public function testGetServerHostWithOverwriteHost(): void { $this->config - ->method('getSystemValue') + ->method('getSystemValueString') ->willReturnCallback(function ($key, $default) { if ($key === 'overwritecondaddr') { return ''; @@ -1155,16 +1287,16 @@ class RequestTest extends \Test\TestCase { $request = new Request( [], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('my.overwritten.host', $request->getServerHost()); + $this->assertSame('my.overwritten.host', $request->getServerHost()); } - public function testGetServerHostWithTrustedDomain() { + public function testGetServerHostWithTrustedDomain(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1184,16 +1316,16 @@ class RequestTest extends \Test\TestCase { 'REMOTE_ADDR' => '1.2.3.4', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('my.trusted.host', $request->getServerHost()); + $this->assertSame('my.trusted.host', $request->getServerHost()); } - public function testGetServerHostWithUntrustedDomain() { + public function testGetServerHostWithUntrustedDomain(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1213,16 +1345,16 @@ class RequestTest extends \Test\TestCase { 'REMOTE_ADDR' => '1.2.3.4', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('my.trusted.host', $request->getServerHost()); + $this->assertSame('my.trusted.host', $request->getServerHost()); } - public function testGetServerHostWithNoTrustedDomain() { + public function testGetServerHostWithNoTrustedDomain(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1239,19 +1371,16 @@ class RequestTest extends \Test\TestCase { 'REMOTE_ADDR' => '1.2.3.4', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream ); - $this->assertSame('', $request->getServerHost()); + $this->assertSame('', $request->getServerHost()); } - /** - * @return array - */ - public function dataGetServerHostTrustedDomain() { + public static function dataGetServerHostTrustedDomain(): array { return [ 'is array' => ['my.trusted.host', ['my.trusted.host']], 'is array but undefined index 0' => ['my.trusted.host', [2 => 'my.trusted.host']], @@ -1260,12 +1389,8 @@ class RequestTest extends \Test\TestCase { ]; } - /** - * @dataProvider dataGetServerHostTrustedDomain - * @param $expected - * @param $trustedDomain - */ - public function testGetServerHostTrustedDomain($expected, $trustedDomain) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetServerHostTrustedDomain')] + public function testGetServerHostTrustedDomain(string $expected, $trustedDomain): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) use ($trustedDomain) { @@ -1285,7 +1410,7 @@ class RequestTest extends \Test\TestCase { 'REMOTE_ADDR' => '1.2.3.4', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1294,15 +1419,15 @@ class RequestTest extends \Test\TestCase { $this->assertSame($expected, $request->getServerHost()); } - public function testGetOverwriteHostDefaultNull() { + public function testGetOverwriteHostDefaultNull(): void { $this->config ->expects($this->once()) - ->method('getSystemValue') + ->method('getSystemValueString') ->with('overwritehost') ->willReturn(''); $request = new Request( [], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1311,26 +1436,18 @@ class RequestTest extends \Test\TestCase { $this->assertNull(self::invokePrivate($request, 'getOverwriteHost')); } - public function testGetOverwriteHostWithOverwrite() { - $this->config - ->expects($this->at(0)) - ->method('getSystemValue') - ->with('overwritehost') - ->willReturn('www.owncloud.org'); + public function testGetOverwriteHostWithOverwrite(): void { $this->config - ->expects($this->at(1)) - ->method('getSystemValue') - ->with('overwritecondaddr') - ->willReturn(''); - $this->config - ->expects($this->at(2)) - ->method('getSystemValue') - ->with('overwritehost') - ->willReturn('www.owncloud.org'); + ->expects($this->exactly(3)) + ->method('getSystemValueString') + ->willReturnMap([ + ['overwritehost', '', 'www.owncloud.org'], + ['overwritecondaddr', '', ''], + ]); $request = new Request( [], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1340,7 +1457,7 @@ class RequestTest extends \Test\TestCase { } - public function testGetPathInfoNotProcessible() { + public function testGetPathInfoNotProcessible(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('The requested uri(/foo.php) cannot be processed by the script \'/var/www/index.php\')'); @@ -1351,7 +1468,7 @@ class RequestTest extends \Test\TestCase { 'SCRIPT_NAME' => '/var/www/index.php', ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1361,7 +1478,7 @@ class RequestTest extends \Test\TestCase { } - public function testGetRawPathInfoNotProcessible() { + public function testGetRawPathInfoNotProcessible(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('The requested uri(/foo.php) cannot be processed by the script \'/var/www/index.php\')'); @@ -1372,7 +1489,7 @@ class RequestTest extends \Test\TestCase { 'SCRIPT_NAME' => '/var/www/index.php', ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1382,12 +1499,12 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider genericPathInfoProvider * @param string $requestUri * @param string $scriptName * @param string $expected */ - public function testGetPathInfoWithoutSetEnvGeneric($requestUri, $scriptName, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGenericPathInfo')] + public function testGetPathInfoWithoutSetEnvGeneric($requestUri, $scriptName, $expected): void { $request = new Request( [ 'server' => [ @@ -1395,7 +1512,7 @@ class RequestTest extends \Test\TestCase { 'SCRIPT_NAME' => $scriptName, ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1405,12 +1522,12 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider genericPathInfoProvider * @param string $requestUri * @param string $scriptName * @param string $expected */ - public function testGetRawPathInfoWithoutSetEnvGeneric($requestUri, $scriptName, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGenericPathInfo')] + public function testGetRawPathInfoWithoutSetEnvGeneric($requestUri, $scriptName, $expected): void { $request = new Request( [ 'server' => [ @@ -1418,7 +1535,7 @@ class RequestTest extends \Test\TestCase { 'SCRIPT_NAME' => $scriptName, ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1428,12 +1545,12 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider rawPathInfoProvider * @param string $requestUri * @param string $scriptName * @param string $expected */ - public function testGetRawPathInfoWithoutSetEnv($requestUri, $scriptName, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataRawPathInfo')] + public function testGetRawPathInfoWithoutSetEnv($requestUri, $scriptName, $expected): void { $request = new Request( [ 'server' => [ @@ -1441,7 +1558,7 @@ class RequestTest extends \Test\TestCase { 'SCRIPT_NAME' => $scriptName, ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1451,12 +1568,12 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider pathInfoProvider * @param string $requestUri * @param string $scriptName * @param string $expected */ - public function testGetPathInfoWithoutSetEnv($requestUri, $scriptName, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataPathInfo')] + public function testGetPathInfoWithoutSetEnv($requestUri, $scriptName, $expected): void { $request = new Request( [ 'server' => [ @@ -1464,7 +1581,7 @@ class RequestTest extends \Test\TestCase { 'SCRIPT_NAME' => $scriptName, ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1473,10 +1590,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame($expected, $request->getPathInfo()); } - /** - * @return array - */ - public function genericPathInfoProvider() { + public static function dataGenericPathInfo(): array { return [ ['/core/index.php?XDEBUG_SESSION_START=14600', '/core/index.php', ''], ['/index.php/apps/files/', 'index.php', '/apps/files/'], @@ -1488,28 +1602,22 @@ class RequestTest extends \Test\TestCase { ]; } - /** - * @return array - */ - public function rawPathInfoProvider() { + public static function dataRawPathInfo(): array { return [ ['/foo%2Fbar/subfolder', '', 'foo%2Fbar/subfolder'], ]; } - /** - * @return array - */ - public function pathInfoProvider() { + public static function dataPathInfo(): array { return [ ['/foo%2Fbar/subfolder', '', 'foo/bar/subfolder'], ]; } - public function testGetRequestUriWithoutOverwrite() { + public function testGetRequestUriWithoutOverwrite(): void { $this->config ->expects($this->once()) - ->method('getSystemValue') + ->method('getSystemValueString') ->with('overwritewebroot') ->willReturn(''); @@ -1519,7 +1627,7 @@ class RequestTest extends \Test\TestCase { 'REQUEST_URI' => '/test.php' ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1528,38 +1636,34 @@ class RequestTest extends \Test\TestCase { $this->assertSame('/test.php', $request->getRequestUri()); } - public function providesGetRequestUriWithOverwriteData() { + public static function dataGetRequestUriWithOverwrite(): array { return [ ['/scriptname.php/some/PathInfo', '/owncloud/', ''], - ['/scriptname.php/some/PathInfo', '/owncloud/', '123'], + ['/scriptname.php/some/PathInfo', '/owncloud/', '123', '123.123.123.123'], ]; } - /** - * @dataProvider providesGetRequestUriWithOverwriteData - */ - public function testGetRequestUriWithOverwrite($expectedUri, $overwriteWebRoot, $overwriteCondAddr) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetRequestUriWithOverwrite')] + public function testGetRequestUriWithOverwrite($expectedUri, $overwriteWebRoot, $overwriteCondAddr, $remoteAddr = ''): void { $this->config - ->expects($this->at(0)) - ->method('getSystemValue') - ->with('overwritewebroot') - ->willReturn($overwriteWebRoot); - $this->config - ->expects($this->at(1)) - ->method('getSystemValue') - ->with('overwritecondaddr') - ->willReturn($overwriteCondAddr); + ->expects($this->exactly(2)) + ->method('getSystemValueString') + ->willReturnMap([ + ['overwritewebroot', '', $overwriteWebRoot], + ['overwritecondaddr', '', $overwriteCondAddr], + ]); - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ 'REQUEST_URI' => '/test.php/some/PathInfo', 'SCRIPT_NAME' => '/test.php', + 'REMOTE_ADDR' => $remoteAddr ] ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1573,10 +1677,10 @@ class RequestTest extends \Test\TestCase { $this->assertSame($expectedUri, $request->getRequestUri()); } - public function testPassesCSRFCheckWithGet() { + public function testPassesCSRFCheckWithGet(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'get' => [ @@ -1587,7 +1691,7 @@ class RequestTest extends \Test\TestCase { 'nc_sameSiteCookielax' => 'true', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1603,10 +1707,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesCSRFCheck()); } - public function testPassesCSRFCheckWithPost() { + public function testPassesCSRFCheckWithPost(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'post' => [ @@ -1617,7 +1721,7 @@ class RequestTest extends \Test\TestCase { 'nc_sameSiteCookielax' => 'true', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1633,10 +1737,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesCSRFCheck()); } - public function testPassesCSRFCheckWithHeader() { + public function testPassesCSRFCheckWithHeader(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -1647,7 +1751,7 @@ class RequestTest extends \Test\TestCase { 'nc_sameSiteCookielax' => 'true', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1663,17 +1767,17 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesCSRFCheck()); } - public function testPassesCSRFCheckWithGetAndWithoutCookies() { + public function testPassesCSRFCheckWithGetAndWithoutCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'get' => [ 'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1687,17 +1791,17 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesCSRFCheck()); } - public function testPassesCSRFCheckWithPostAndWithoutCookies() { + public function testPassesCSRFCheckWithPostAndWithoutCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'post' => [ 'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1711,17 +1815,17 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesCSRFCheck()); } - public function testPassesCSRFCheckWithHeaderAndWithoutCookies() { + public function testPassesCSRFCheckWithHeaderAndWithoutCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1735,10 +1839,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesCSRFCheck()); } - public function testFailsCSRFCheckWithHeaderAndNotAllChecksPassing() { + public function testFailsCSRFCheckWithHeaderAndNotAllChecksPassing(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -1749,7 +1853,7 @@ class RequestTest extends \Test\TestCase { 'nc_sameSiteCookiestrict' => 'true', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1762,10 +1866,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesCSRFCheck()); } - public function testPassesStrictCookieCheckWithAllCookiesAndStrict() { + public function testPassesStrictCookieCheckWithAllCookiesAndStrict(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName', 'getCookieParams']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName', 'getCookieParams']) ->setConstructorArgs([ [ 'server' => [ @@ -1777,7 +1881,7 @@ class RequestTest extends \Test\TestCase { '__Host-nc_sameSiteCookielax' => 'true', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1794,10 +1898,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesStrictCookieCheck()); } - public function testFailsStrictCookieCheckWithAllCookiesAndMissingStrict() { + public function testFailsStrictCookieCheckWithAllCookiesAndMissingStrict(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName', 'getCookieParams']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName', 'getCookieParams']) ->setConstructorArgs([ [ 'server' => [ @@ -1809,7 +1913,7 @@ class RequestTest extends \Test\TestCase { 'nc_sameSiteCookielax' => 'true', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1826,13 +1930,13 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesStrictCookieCheck()); } - public function testGetCookieParams() { + public function testGetCookieParams(): void { /** @var Request $request */ $request = $this->getMockBuilder(Request::class) - ->setMethods(['getScriptName']) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1842,10 +1946,10 @@ class RequestTest extends \Test\TestCase { $this->assertSame(session_get_cookie_params(), $actual); } - public function testPassesStrictCookieCheckWithAllCookies() { + public function testPassesStrictCookieCheckWithAllCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -1857,7 +1961,7 @@ class RequestTest extends \Test\TestCase { 'nc_sameSiteCookielax' => 'true', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1867,10 +1971,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesStrictCookieCheck()); } - public function testPassesStrictCookieCheckWithRandomCookies() { + public function testPassesStrictCookieCheckWithRandomCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -1880,7 +1984,7 @@ class RequestTest extends \Test\TestCase { 'RandomCookie' => 'asdf', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1890,10 +1994,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesStrictCookieCheck()); } - public function testFailsStrictCookieCheckWithSessionCookie() { + public function testFailsStrictCookieCheckWithSessionCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -1903,7 +2007,7 @@ class RequestTest extends \Test\TestCase { session_name() => 'asdf', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1913,10 +2017,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesStrictCookieCheck()); } - public function testFailsStrictCookieCheckWithRememberMeCookie() { + public function testFailsStrictCookieCheckWithRememberMeCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -1926,7 +2030,7 @@ class RequestTest extends \Test\TestCase { 'nc_token' => 'asdf', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1936,10 +2040,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesStrictCookieCheck()); } - public function testFailsCSRFCheckWithPostAndWithCookies() { + public function testFailsCSRFCheckWithPostAndWithCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'post' => [ @@ -1950,7 +2054,7 @@ class RequestTest extends \Test\TestCase { 'foo' => 'bar', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1963,10 +2067,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesCSRFCheck()); } - public function testFailStrictCookieCheckWithOnlyLaxCookie() { + public function testFailStrictCookieCheckWithOnlyLaxCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -1977,7 +2081,7 @@ class RequestTest extends \Test\TestCase { 'nc_sameSiteCookielax' => 'true', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -1987,10 +2091,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesStrictCookieCheck()); } - public function testFailStrictCookieCheckWithOnlyStrictCookie() { + public function testFailStrictCookieCheckWithOnlyStrictCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2001,7 +2105,7 @@ class RequestTest extends \Test\TestCase { 'nc_sameSiteCookiestrict' => 'true', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -2011,10 +2115,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesStrictCookieCheck()); } - public function testPassesLaxCookieCheck() { + public function testPassesLaxCookieCheck(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2025,7 +2129,7 @@ class RequestTest extends \Test\TestCase { 'nc_sameSiteCookielax' => 'true', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -2035,10 +2139,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesLaxCookieCheck()); } - public function testFailsLaxCookieCheckWithOnlyStrictCookie() { + public function testFailsLaxCookieCheckWithOnlyStrictCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2049,7 +2153,7 @@ class RequestTest extends \Test\TestCase { 'nc_sameSiteCookiestrict' => 'true', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -2059,10 +2163,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesLaxCookieCheck()); } - public function testSkipCookieCheckForOCSRequests() { + public function testSkipCookieCheckForOCSRequests(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2074,7 +2178,7 @@ class RequestTest extends \Test\TestCase { 'nc_sameSiteCookiestrict' => 'false', ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -2084,10 +2188,7 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesStrictCookieCheck()); } - /** - * @return array - */ - public function invalidTokenDataProvider() { + public static function dataInvalidToken(): array { return [ ['InvalidSentToken'], ['InvalidSentToken:InvalidSecret'], @@ -2095,21 +2196,18 @@ class RequestTest extends \Test\TestCase { ]; } - /** - * @dataProvider invalidTokenDataProvider - * @param string $invalidToken - */ - public function testPassesCSRFCheckWithInvalidToken($invalidToken) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataInvalidToken')] + public function testPassesCSRFCheckWithInvalidToken(string $invalidToken): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ 'HTTP_REQUESTTOKEN' => $invalidToken, ], ], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -2126,13 +2224,13 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesCSRFCheck()); } - public function testPassesCSRFCheckWithoutTokenFail() { + public function testPassesCSRFCheckWithoutTokenFail(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [], - $this->secureRandom, + $this->requestId, $this->config, $this->csrfTokenManager, $this->stream @@ -2141,4 +2239,24 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesCSRFCheck()); } + + public function testPassesCSRFCheckWithOCSAPIRequestHeader(): void { + /** @var Request $request */ + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) + ->setConstructorArgs([ + [ + 'server' => [ + 'HTTP_OCS_APIREQUEST' => 'true', + ], + ], + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ]) + ->getMock(); + + $this->assertTrue($request->passesCSRFCheck()); + } } |