Browse Source

Merge pull request #14100 from cakephp/issue-14085

Fix FormProtection not comparing unlocked fields properly
ADmad 6 years ago
parent
commit
039992e6a5

+ 7 - 7
src/Controller/Component/FormProtectionComponent.php

@@ -84,13 +84,13 @@ class FormProtectionComponent extends Component
             && $hasData
             && $this->_config['validate']
         ) {
-            $formProtector = new FormProtector();
-            $request->getSession()->start();
-            $isValid = $formProtector->validate(
-                $data,
-                Router::url($request->getRequestTarget()),
-                $request->getSession()->id()
-            );
+            $session = $request->getSession();
+
+            $session->start();
+            $sessionId = $session->id();
+            $url = Router::url($request->getRequestTarget());
+            $formProtector = new FormProtector($url, $sessionId, $this->_config);
+            $isValid = $formProtector->validate($data, $url, $sessionId);
 
             if (!$isValid) {
                 return $this->validationFailure($formProtector);

+ 49 - 0
tests/TestCase/Controller/Component/FormProtectionComponentTest.php

@@ -216,6 +216,55 @@ class FormProtectionComponentTest extends TestCase
         $this->FormProtection->startup($event);
     }
 
+    public function testValidationUnlockedFieldsMismatch()
+    {
+        // Unlocked is empty when the token is created.
+        $unlocked = '';
+        $fields = ['open', 'title'];
+        $debug = urlencode(json_encode([
+            '/articles/index',
+            $fields,
+            [''],
+        ]));
+        $fields = hash_hmac('sha1', '/articles/index' . serialize($fields) . $unlocked . 'cli', Security::getSalt());
+
+        $this->Controller->setRequest($this->Controller->getRequest()->withParsedBody([
+            'open' => 'yes',
+            'title' => 'yay',
+            '_Token' => compact('fields', 'unlocked', 'debug'),
+        ]));
+
+        $this->expectException(BadRequestException::class);
+        $this->expectExceptionMessage('Missing unlocked field');
+
+        $event = new Event('Controller.startup', $this->Controller);
+        $this->FormProtection->setConfig('unlockedFields', ['open']);
+        $this->FormProtection->startup($event);
+    }
+
+    public function testValidationUnlockedFieldsSuccess()
+    {
+        $unlocked = 'open';
+        $fields = ['title'];
+        $debug = urlencode(json_encode([
+            '/articles/index',
+            $fields,
+            ['open'],
+        ]));
+        $fields = hash_hmac('sha1', '/articles/index' . serialize($fields) . $unlocked . 'cli', Security::getSalt());
+
+        $this->Controller->setRequest($this->Controller->getRequest()->withParsedBody([
+            'title' => 'yay',
+            'open' => 'yes',
+            '_Token' => compact('fields', 'unlocked', 'debug'),
+        ]));
+
+        $event = new Event('Controller.startup', $this->Controller);
+        $this->FormProtection->setConfig('unlockedFields', ['open']);
+        $result = $this->FormProtection->startup($event);
+        $this->assertNull($result);
+    }
+
     public function testCallbackReturnResponse()
     {
         $this->FormProtection->setConfig('validationFailureCallback', function (BadRequestException $exception) {

+ 1 - 1
tests/TestCase/TestSuite/IntegrationTestTraitTest.php

@@ -833,7 +833,7 @@ class IntegrationTestTraitTest extends TestCase
         ];
         $this->post('/posts/securePost', $data);
         $this->assertResponseCode(400);
-        $this->assertResponseContains('Invalid security debug token.');
+        $this->assertResponseContains('Invalid form protection debug token.');
     }
 
     /**

+ 3 - 3
tests/test_app/TestApp/Controller/PostsController.php

@@ -28,7 +28,7 @@ class PostsController extends AppController
     {
         $this->loadComponent('Flash');
         $this->loadComponent('RequestHandler');
-        $this->loadComponent('Security');
+        $this->loadComponent('FormProtection');
     }
 
     /**
@@ -39,10 +39,10 @@ class PostsController extends AppController
     public function beforeFilter(EventInterface $event)
     {
         if ($this->request->getParam('action') !== 'securePost') {
-            $this->getEventManager()->off($this->Security);
+            $this->getEventManager()->off($this->FormProtection);
         }
 
-        $this->Security->setConfig('unlockedFields', ['some_unlocked_field']);
+        $this->FormProtection->setConfig('unlockedFields', ['some_unlocked_field']);
     }
 
     /**