From 91ba332519631a1e1c418c9fd323c10fc6cdccba Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Tue, 14 Jan 2025 14:15:21 +0700 Subject: [PATCH 01/11] fix: ensure csrf token is string --- system/Security/Security.php | 2 +- tests/system/Security/SecurityTest.php | 45 ++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/system/Security/Security.php b/system/Security/Security.php index 5d86dbbe9984..18c5ef8a593f 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -307,7 +307,7 @@ private function getPostedToken(RequestInterface $request): ?string // Does the token exist in POST, HEADER or optionally php:://input - json data or PUT, DELETE, PATCH - raw data. if ($tokenValue = $request->getPost($this->config->tokenName)) { - return $tokenValue; + return is_string($tokenValue) ? $tokenValue : null; } if ($request->hasHeader($this->config->headerName) diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index fa7d29e775c3..48d6b5be2177 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -25,6 +25,8 @@ use Config\Security as SecurityConfig; use PHPUnit\Framework\Attributes\BackupGlobals; use PHPUnit\Framework\Attributes\Group; +use ReflectionClass; +use ReflectionMethod; /** * @internal @@ -49,6 +51,16 @@ private function createMockSecurity(?SecurityConfig $config = null): MockSecurit return new MockSecurity($config); } + private function getPostedTokenMethod(): ReflectionMethod + { + $reflection = new ReflectionClass(Security::class); + $method = $reflection->getMethod('getPostedToken'); + + $method->setAccessible(true); + + return $method; + } + public function testBasicConfigIsSaved(): void { $security = $this->createMockSecurity(); @@ -315,4 +327,37 @@ public function testGetters(): void $this->assertIsString($security->getCookieName()); $this->assertIsBool($security->shouldRedirect()); } + + public function testGetPostedTokenReturnsTokenWhenValid(): void + { + $method = $this->getPostedTokenMethod(); + $security = $this->createMockSecurity(); + + $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; + $request = $this->createIncomingRequest(); + + $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method->invoke($security, $request)); + } + + public function testGetPostedTokenReturnsNullWhenEmpty(): void + { + $method = $this->getPostedTokenMethod(); + $security = $this->createMockSecurity(); + + $_POST = []; + $request = $this->createIncomingRequest(); + + $this->assertNull($method->invoke($security, $request)); + } + + public function testGetPostedTokenReturnsNullWhenMaliciousData(): void + { + $method = $this->getPostedTokenMethod(); + $security = $this->createMockSecurity(); + + $_POST['csrf_test_name'] = ['malicious' => 'data']; + $request = $this->createIncomingRequest(); + + $this->assertNull($method->invoke($security, $request)); + } } From 9694783e0d21e2298a4f54f57014b70f061cffd7 Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Tue, 14 Jan 2025 14:26:40 +0700 Subject: [PATCH 02/11] fix: ensure csrf token is string --- tests/system/Security/SecurityTest.php | 30 ++++++-------------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index 48d6b5be2177..d2f83d4a83a2 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -25,8 +25,6 @@ use Config\Security as SecurityConfig; use PHPUnit\Framework\Attributes\BackupGlobals; use PHPUnit\Framework\Attributes\Group; -use ReflectionClass; -use ReflectionMethod; /** * @internal @@ -51,16 +49,6 @@ private function createMockSecurity(?SecurityConfig $config = null): MockSecurit return new MockSecurity($config); } - private function getPostedTokenMethod(): ReflectionMethod - { - $reflection = new ReflectionClass(Security::class); - $method = $reflection->getMethod('getPostedToken'); - - $method->setAccessible(true); - - return $method; - } - public function testBasicConfigIsSaved(): void { $security = $this->createMockSecurity(); @@ -330,34 +318,28 @@ public function testGetters(): void public function testGetPostedTokenReturnsTokenWhenValid(): void { - $method = $this->getPostedTokenMethod(); - $security = $this->createMockSecurity(); - $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $request = $this->createIncomingRequest(); + $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); - $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method->invoke($security, $request)); + $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } public function testGetPostedTokenReturnsNullWhenEmpty(): void { - $method = $this->getPostedTokenMethod(); - $security = $this->createMockSecurity(); - $_POST = []; $request = $this->createIncomingRequest(); + $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); - $this->assertNull($method->invoke($security, $request)); + $this->assertNull($method($request)); } public function testGetPostedTokenReturnsNullWhenMaliciousData(): void { - $method = $this->getPostedTokenMethod(); - $security = $this->createMockSecurity(); - $_POST['csrf_test_name'] = ['malicious' => 'data']; $request = $this->createIncomingRequest(); + $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); - $this->assertNull($method->invoke($security, $request)); + $this->assertNull($method($request)); } } From c3afea61b9515057a84075d0c077d3508dc037ba Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Tue, 14 Jan 2025 14:32:55 +0700 Subject: [PATCH 03/11] handle request php://input --- system/Security/Security.php | 4 +++- tests/system/Security/SecurityTest.php | 30 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/system/Security/Security.php b/system/Security/Security.php index 18c5ef8a593f..18e9b73d3946 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -321,7 +321,9 @@ private function getPostedToken(RequestInterface $request): ?string if ($body !== '') { $json = json_decode($body); if ($json !== null && json_last_error() === JSON_ERROR_NONE) { - return $json->{$this->config->tokenName} ?? null; + $tokenValue = $json->{$this->config->tokenName} ?? null; + + return is_string($tokenValue) ? $tokenValue : null; } parse_str($body, $parsed); diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index d2f83d4a83a2..308fe263279b 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -342,4 +342,34 @@ public function testGetPostedTokenReturnsNullWhenMaliciousData(): void $this->assertNull($method($request)); } + + public function testGetPostedTokenReturnsTokenFromJsonInput(): void + { + $_POST = []; + $jsonBody = json_encode(['csrf_test_name' => '8b9218a55906f9dcc1dc263dce7f005a']); + $request = $this->createIncomingRequest()->setBody($jsonBody); + $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); + + $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); + } + + public function testGetPostedTokenReturnsTokenFromFormEncodedInput(): void + { + $_POST = []; + $formBody = 'csrf_test_name=8b9218a55906f9dcc1dc263dce7f005a'; + $request = $this->createIncomingRequest()->setBody($formBody); + $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); + + $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); + } + + public function testGetPostedTokenReturnsNullFromMaliciousJsonInput(): void + { + $_POST = []; + $maliciousJson = json_encode(['csrf_test_name' => ['malicious' => 'data']]); + $request = $this->createIncomingRequest()->setBody($maliciousJson); + $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); + + $this->assertNull($method($request)); + } } From 4b4c8bc6358bee4337c278755aef2aaee381b7e8 Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Tue, 14 Jan 2025 14:59:25 +0700 Subject: [PATCH 04/11] handle request php://input --- system/Security/Security.php | 3 +- tests/system/Security/SecurityTest.php | 46 ++++++++++++++------------ 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/system/Security/Security.php b/system/Security/Security.php index 18e9b73d3946..56e793d23fce 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -327,8 +327,9 @@ private function getPostedToken(RequestInterface $request): ?string } parse_str($body, $parsed); + $tokenValue = $parsed[$this->config->tokenName] ?? null; - return $parsed[$this->config->tokenName] ?? null; + return is_string($tokenValue) ? $tokenValue : null; } return null; diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index 308fe263279b..4e968ed5d49b 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -316,7 +316,7 @@ public function testGetters(): void $this->assertIsBool($security->shouldRedirect()); } - public function testGetPostedTokenReturnsTokenWhenValid(): void + public function testGetPostedTokenReturnsTokenFromPost(): void { $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $request = $this->createIncomingRequest(); @@ -325,25 +325,16 @@ public function testGetPostedTokenReturnsTokenWhenValid(): void $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } - public function testGetPostedTokenReturnsNullWhenEmpty(): void + public function testGetPostedTokenReturnsTokenFromHeader(): void { $_POST = []; - $request = $this->createIncomingRequest(); + $request = $this->createIncomingRequest()->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); - $this->assertNull($method($request)); - } - - public function testGetPostedTokenReturnsNullWhenMaliciousData(): void - { - $_POST['csrf_test_name'] = ['malicious' => 'data']; - $request = $this->createIncomingRequest(); - $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); - - $this->assertNull($method($request)); + $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } - public function testGetPostedTokenReturnsTokenFromJsonInput(): void + public function testGetPostedTokenReturnsTokenFromJsonBody(): void { $_POST = []; $jsonBody = json_encode(['csrf_test_name' => '8b9218a55906f9dcc1dc263dce7f005a']); @@ -353,7 +344,7 @@ public function testGetPostedTokenReturnsTokenFromJsonInput(): void $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } - public function testGetPostedTokenReturnsTokenFromFormEncodedInput(): void + public function testGetPostedTokenReturnsTokenFromFormBody(): void { $_POST = []; $formBody = 'csrf_test_name=8b9218a55906f9dcc1dc263dce7f005a'; @@ -363,13 +354,24 @@ public function testGetPostedTokenReturnsTokenFromFormEncodedInput(): void $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } - public function testGetPostedTokenReturnsNullFromMaliciousJsonInput(): void + public function testGetPostedTokenReturnsNullForInvalidInputs(): void { - $_POST = []; - $maliciousJson = json_encode(['csrf_test_name' => ['malicious' => 'data']]); - $request = $this->createIncomingRequest()->setBody($maliciousJson); - $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); - - $this->assertNull($method($request)); + $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); + $testCases = [ + 'empty_post' => $this->createIncomingRequest(), + 'malicious_post' => $this->createIncomingRequest()->setGlobal('post', ['csrf_test_name' => ['malicious' => 'data']]), + 'empty_header' => $this->createIncomingRequest()->setHeader('X-CSRF-TOKEN', ''), + 'malicious_json' => $this->createIncomingRequest()->setBody(json_encode(['csrf_test_name' => ['malicious' => 'data']])), + 'invalid_json' => $this->createIncomingRequest()->setBody('{invalid json}'), + 'missing_token_in_body' => $this->createIncomingRequest()->setBody('other=value&another=test'), + 'malicious_form' => $this->createIncomingRequest()->setBody('csrf_test_name[]=malicious'), + ]; + + foreach ($testCases as $case => $request) { + $this->assertNull( + $method($request), + "Failed asserting that {$case} returns null" + ); + } } } From e62db7a2da54064800d2c1c9147d447fd2f9d13d Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Wed, 15 Jan 2025 11:10:08 +0700 Subject: [PATCH 05/11] wip --- system/Security/Security.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/system/Security/Security.php b/system/Security/Security.php index 56e793d23fce..5bf90d879c32 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -310,10 +310,10 @@ private function getPostedToken(RequestInterface $request): ?string return is_string($tokenValue) ? $tokenValue : null; } - if ($request->hasHeader($this->config->headerName) - && $request->header($this->config->headerName)->getValue() !== '' - && $request->header($this->config->headerName)->getValue() !== []) { - return $request->header($this->config->headerName)->getValue(); + if ($request->hasHeader($this->config->headerName)) { + $tokenValue = $request->header($this->config->headerName)->getValue(); + + return ($tokenValue !== '' && $tokenValue !== [] && is_string($tokenValue)) ? $tokenValue : null; } $body = (string) $request->getBody(); From d9d94e53206d576d0c7304b3cd11e6e4bf320485 Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Wed, 15 Jan 2025 11:11:19 +0700 Subject: [PATCH 06/11] wip --- tests/system/Security/SecurityTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index 4e968ed5d49b..835f982d4b0c 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -359,12 +359,12 @@ public function testGetPostedTokenReturnsNullForInvalidInputs(): void $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); $testCases = [ 'empty_post' => $this->createIncomingRequest(), - 'malicious_post' => $this->createIncomingRequest()->setGlobal('post', ['csrf_test_name' => ['malicious' => 'data']]), + 'invalid_post_data' => $this->createIncomingRequest()->setGlobal('post', ['csrf_test_name' => ['invalid' => 'data']]), 'empty_header' => $this->createIncomingRequest()->setHeader('X-CSRF-TOKEN', ''), - 'malicious_json' => $this->createIncomingRequest()->setBody(json_encode(['csrf_test_name' => ['malicious' => 'data']])), + 'invalid_json_data' => $this->createIncomingRequest()->setBody(json_encode(['csrf_test_name' => ['invalid' => 'data']])), 'invalid_json' => $this->createIncomingRequest()->setBody('{invalid json}'), 'missing_token_in_body' => $this->createIncomingRequest()->setBody('other=value&another=test'), - 'malicious_form' => $this->createIncomingRequest()->setBody('csrf_test_name[]=malicious'), + 'invalid_form_data' => $this->createIncomingRequest()->setBody('csrf_test_name[]=invalid'), ]; foreach ($testCases as $case => $request) { From 86178783ef95c7ebd90b76544973c89248408868 Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Wed, 15 Jan 2025 11:15:48 +0700 Subject: [PATCH 07/11] wip --- user_guide_src/source/changelogs/v4.5.8.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/v4.5.8.rst b/user_guide_src/source/changelogs/v4.5.8.rst index e62944df9334..5d0f28ae62a7 100644 --- a/user_guide_src/source/changelogs/v4.5.8.rst +++ b/user_guide_src/source/changelogs/v4.5.8.rst @@ -39,6 +39,7 @@ Bugs Fixed ********** - **Database:** Fixed a bug where ``Builder::affectedRows()`` threw an error when the previous query call failed in ``Postgre`` and ``SQLSRV`` drivers. +- **Security** Fixed a security issue in `Security` class where CSRF token validation might fail in specific malformed request inputs. See the repo's `CHANGELOG.md `_ From 333c7344e37e06cf3f4b5f784875ead18ec64262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ng=C3=B4=20Qu=E1=BB=91c=20=C4=90=E1=BA=A1t?= Date: Fri, 17 Jan 2025 16:46:07 +0700 Subject: [PATCH 08/11] wip Co-authored-by: Michal Sniatala --- system/Security/Security.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Security/Security.php b/system/Security/Security.php index 5bf90d879c32..574da8d50dc1 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -313,7 +313,7 @@ private function getPostedToken(RequestInterface $request): ?string if ($request->hasHeader($this->config->headerName)) { $tokenValue = $request->header($this->config->headerName)->getValue(); - return ($tokenValue !== '' && $tokenValue !== [] && is_string($tokenValue)) ? $tokenValue : null; + return (is_string($tokenValue) && $tokenValue !== '') ? $tokenValue : null; } $body = (string) $request->getBody(); From dc4c641b33cb31422d243b98d243a6da58fb6953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ng=C3=B4=20Qu=E1=BB=91c=20=C4=90=E1=BA=A1t?= Date: Fri, 17 Jan 2025 16:46:16 +0700 Subject: [PATCH 09/11] wip Co-authored-by: Michal Sniatala --- user_guide_src/source/changelogs/v4.5.8.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.5.8.rst b/user_guide_src/source/changelogs/v4.5.8.rst index 5d0f28ae62a7..3ed6806cd4e9 100644 --- a/user_guide_src/source/changelogs/v4.5.8.rst +++ b/user_guide_src/source/changelogs/v4.5.8.rst @@ -39,7 +39,7 @@ Bugs Fixed ********** - **Database:** Fixed a bug where ``Builder::affectedRows()`` threw an error when the previous query call failed in ``Postgre`` and ``SQLSRV`` drivers. -- **Security** Fixed a security issue in `Security` class where CSRF token validation might fail in specific malformed request inputs. +- **Security** Fixed a bug where the CSRF token validation could fail on malformed input, causing a generic 500 error instead of handling the input gracefully. See the repo's `CHANGELOG.md `_ From 9d24d4bb0a063f3325e057b629c5b8f4b8049a2d Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sat, 18 Jan 2025 21:59:18 +0800 Subject: [PATCH 10/11] Update user_guide_src/source/changelogs/v4.5.8.rst --- user_guide_src/source/changelogs/v4.5.8.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.5.8.rst b/user_guide_src/source/changelogs/v4.5.8.rst index 3ed6806cd4e9..910912ae5dc4 100644 --- a/user_guide_src/source/changelogs/v4.5.8.rst +++ b/user_guide_src/source/changelogs/v4.5.8.rst @@ -39,7 +39,7 @@ Bugs Fixed ********** - **Database:** Fixed a bug where ``Builder::affectedRows()`` threw an error when the previous query call failed in ``Postgre`` and ``SQLSRV`` drivers. -- **Security** Fixed a bug where the CSRF token validation could fail on malformed input, causing a generic 500 error instead of handling the input gracefully. +- **Security:** Fixed a bug where the CSRF token validation could fail on malformed input, causing a generic HTTP 500 status code instead of handling the input gracefully. See the repo's `CHANGELOG.md `_ From d11d76a3b2d5261c30759222ce76fbb56a289a02 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sat, 18 Jan 2025 22:17:56 +0800 Subject: [PATCH 11/11] Use data providers --- tests/system/Security/SecurityTest.php | 65 +++++++++++++++----------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index 835f982d4b0c..2f3aea06470b 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -24,6 +24,7 @@ use CodeIgniter\Test\Mock\MockSecurity; use Config\Security as SecurityConfig; use PHPUnit\Framework\Attributes\BackupGlobals; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; /** @@ -42,13 +43,23 @@ protected function setUp(): void $this->resetServices(); } - private function createMockSecurity(?SecurityConfig $config = null): MockSecurity + private static function createMockSecurity(SecurityConfig $config = new SecurityConfig()): MockSecurity { - $config ??= new SecurityConfig(); - return new MockSecurity($config); } + private static function createIncomingRequest(): IncomingRequest + { + $config = new MockAppConfig(); + + return new IncomingRequest( + $config, + new SiteURI($config), + null, + new UserAgent(), + ); + } + public function testBasicConfigIsSaved(): void { $security = $this->createMockSecurity(); @@ -108,18 +119,6 @@ public function testCSRFVerifyPostThrowsExceptionOnNoMatch(): void $security->verify($request); } - private function createIncomingRequest(): IncomingRequest - { - $config = new MockAppConfig(); - - return new IncomingRequest( - $config, - new SiteURI($config), - null, - new UserAgent(), - ); - } - public function testCSRFVerifyPostReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; @@ -354,24 +353,34 @@ public function testGetPostedTokenReturnsTokenFromFormBody(): void $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } - public function testGetPostedTokenReturnsNullForInvalidInputs(): void + #[DataProvider('provideGetPostedTokenReturnsNullForInvalidInputs')] + public function testGetPostedTokenReturnsNullForInvalidInputs(string $case, IncomingRequest $request): void + { + $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); + + $this->assertNull( + $method($request), + sprintf('Failed asserting that %s returns null on invalid input.', $case), + ); + } + + /** + * @return iterable + */ + public static function provideGetPostedTokenReturnsNullForInvalidInputs(): iterable { - $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); $testCases = [ - 'empty_post' => $this->createIncomingRequest(), - 'invalid_post_data' => $this->createIncomingRequest()->setGlobal('post', ['csrf_test_name' => ['invalid' => 'data']]), - 'empty_header' => $this->createIncomingRequest()->setHeader('X-CSRF-TOKEN', ''), - 'invalid_json_data' => $this->createIncomingRequest()->setBody(json_encode(['csrf_test_name' => ['invalid' => 'data']])), - 'invalid_json' => $this->createIncomingRequest()->setBody('{invalid json}'), - 'missing_token_in_body' => $this->createIncomingRequest()->setBody('other=value&another=test'), - 'invalid_form_data' => $this->createIncomingRequest()->setBody('csrf_test_name[]=invalid'), + 'empty_post' => self::createIncomingRequest(), + 'invalid_post_data' => self::createIncomingRequest()->setGlobal('post', ['csrf_test_name' => ['invalid' => 'data']]), + 'empty_header' => self::createIncomingRequest()->setHeader('X-CSRF-TOKEN', ''), + 'invalid_json_data' => self::createIncomingRequest()->setBody(json_encode(['csrf_test_name' => ['invalid' => 'data']])), + 'invalid_json' => self::createIncomingRequest()->setBody('{invalid json}'), + 'missing_token_in_body' => self::createIncomingRequest()->setBody('other=value&another=test'), + 'invalid_form_data' => self::createIncomingRequest()->setBody('csrf_test_name[]=invalid'), ]; foreach ($testCases as $case => $request) { - $this->assertNull( - $method($request), - "Failed asserting that {$case} returns null" - ); + yield $case => [$case, $request]; } } }