Browse Source

Fixing issue where postLink() would fail when used with SecurityComponent.

Mark Story 14 years ago
parent
commit
2ce2d06de2
2 changed files with 57 additions and 18 deletions
  1. 29 5
      lib/Cake/Test/Case/View/Helper/FormHelperTest.php
  2. 28 13
      lib/Cake/View/Helper/FormHelper.php

+ 29 - 5
lib/Cake/Test/Case/View/Helper/FormHelperTest.php

@@ -5713,9 +5713,7 @@ class FormHelperTest extends CakeTestCase {
 				'method' => 'post', 'action' => '/posts/delete/1',
 				'name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;'
 			),
-			'div' => array('style' => 'display:none;'),
 			'input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST'),
-			'/div',
 			'/form',
 			'a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\); event\.returnValue = false; return false;/'),
 			'Delete',
@@ -5728,9 +5726,7 @@ class FormHelperTest extends CakeTestCase {
 				'method' => 'post', 'action' => '/posts/delete/1',
 				'name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;'
 			),
-			'div' => array('style' => 'display:none;'),
 			'input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST'),
-			'/div',
 			'/form',
 			'a' => array('href' => '#', 'onclick' => 'preg:/if \(confirm\('Confirm\?'\)\) \{ document\.post_\w+\.submit\(\); \} event\.returnValue = false; return false;/'),
 			'Delete',
@@ -5738,7 +5734,35 @@ class FormHelperTest extends CakeTestCase {
 		));
 
 		$result = $this->Form->postLink('Delete', '/posts/delete', array('data' => array('id' => 1)));
-		$this->assertTrue(strpos($result, '<input type="hidden" name="data[id]" value="1"/>') !== false);
+		$this->assertContains('<input type="hidden" name="data[id]" value="1"/>', $result);
+	}
+
+/**
+ * Test that postLink adds _Token fields.
+ *
+ * @return void
+ */
+	public function testSecurePostLink() {
+		$this->Form->request->params['_Token'] = array('key' => 'testkey');
+
+		$result = $this->Form->postLink('Delete', '/posts/delete/1');
+		$expected = array(
+			'form' => array(
+				'method' => 'post', 'action' => '/posts/delete/1',
+				'name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;'
+			),
+			array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')),
+			array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/')),
+			'div' => array('style' => 'display:none;'),
+			array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/')),
+			array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/')),
+			'/div',
+			'/form',
+			'a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\); event\.returnValue = false; return false;/'),
+			'Delete',
+			'/a'
+		);
+		$this->assertTags($result, $expected);
 	}
 
 /**

+ 28 - 13
lib/Cake/View/Helper/FormHelper.php

@@ -439,18 +439,7 @@ class FormHelper extends AppHelper {
 		$htmlAttributes = array_merge($options, $htmlAttributes);
 
 		$this->fields = array();
-		if (!empty($this->request->params['_Token'])) {
-			$append .= $this->hidden('_Token.key', array(
-				'value' => $this->request->params['_Token']['key'], 'id' => 'Token' . mt_rand(),
-				'secure' => self::SECURE_SKIP
-			));
-
-			if (!empty($this->request['_Token']['unlockedFields'])) {
-				foreach ((array)$this->request['_Token']['unlockedFields'] as $unlocked) {
-					$this->_unlockedFields[] = $unlocked;
-				}
-			}
-		}
+		$append .= $this->_csrfField();
 
 		if (!empty($append)) {
 			$append = $this->Html->useTag('block', ' style="display:none;"', $append);
@@ -463,6 +452,27 @@ class FormHelper extends AppHelper {
 	}
 
 /**
+ * Return a CSRF input if the _Token is present.
+ * Used to secure forms in conjunction with SecurityComponent
+ *
+ * @return string
+ */
+	protected function _csrfField() {
+		if (empty($this->request->params['_Token'])) {
+			return '';
+		}
+		if (!empty($this->request['_Token']['unlockedFields'])) {
+			foreach ((array)$this->request['_Token']['unlockedFields'] as $unlocked) {
+				$this->_unlockedFields[] = $unlocked;
+			}
+		}
+		return $this->hidden('_Token.key', array(
+			'value' => $this->request->params['_Token']['key'], 'id' => 'Token' . mt_rand(),
+			'secure' => self::SECURE_SKIP
+		));
+	}
+
+/**
  * Closes an HTML form, cleans up values set by FormHelper::create(), and writes hidden
  * input fields where appropriate.
  *
@@ -1511,13 +1521,18 @@ class FormHelper extends AppHelper {
 		$formName = uniqid('post_');
 		$formUrl = $this->url($url);
 		$out = $this->Html->useTag('form', $formUrl, array('name' => $formName, 'id' => $formName, 'style' => 'display:none;', 'method' => 'post'));
-		$out .= $this->Html->useTag('block', ' style="display:none;"', $this->Html->useTag('hidden', '_method', ' value="POST"'));
+		$out .= $this->Html->useTag('hidden', '_method', ' value="POST"');
+		$out .= $this->_csrfField();
+
+		$fields = array();
 		if (isset($options['data']) && is_array($options['data'])) {
 			foreach ($options['data'] as $key => $value) {
+				$fields[$key] = $value;
 				$out .= $this->hidden($key, array('value' => $value, 'id' => false));
 			}
 			unset($options['data']);
 		}
+		$out .= $this->secure($fields);
 		$out .= $this->Html->useTag('formend');
 
 		$url = '#';