From d14b50fc929755a75e27076fc7d0086730a6acd7 Mon Sep 17 00:00:00 2001 From: phpnut Date: Thu, 3 Apr 2008 06:48:56 +0000 Subject: [PATCH] "References #4394, additional fixes to multi record forms. Added additional test cases" git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@6629 3807eeeb-6ff5-0310-8944-8be069107fe0 --- cake/libs/controller/components/security.php | 7 +- cake/libs/view/helpers/form.php | 50 ++++--- .../controller/components/security.test.php | 22 +-- .../cases/libs/view/helpers/form.test.php | 126 +++++++++++++++++- 4 files changed, 177 insertions(+), 28 deletions(-) diff --git a/cake/libs/controller/components/security.php b/cake/libs/controller/components/security.php index 635d2f1d2..87f073ca7 100644 --- a/cake/libs/controller/components/security.php +++ b/cake/libs/controller/components/security.php @@ -519,6 +519,7 @@ class SecurityComponent extends Object { } } } + ksort($check); foreach ($check as $key => $value) { $merge = array(); if ($key === '__Token') { @@ -545,7 +546,11 @@ class SecurityComponent extends Object { if (is_numeric($k[0])) { for ($i = 0; $count > $i; $i++) { - $field[$newKey][$i] = array_merge($field[$newKey][$i], array_keys($values[$i])); + foreach ($values[$i] as $key2 => $value1) { + if ($value1 === '0') { + $field[$newKey][$i] = array_merge($field[$newKey][$i], array($key2)); + } + } } $controller->data[$newKey] = Set::pushDiff($controller->data[$key], $controller->data[$newKey]); } diff --git a/cake/libs/view/helpers/form.php b/cake/libs/view/helpers/form.php index 1fead6294..0bc6723bd 100644 --- a/cake/libs/view/helpers/form.php +++ b/cake/libs/view/helpers/form.php @@ -295,47 +295,65 @@ class FormHelper extends AppHelper { return null; } /** - * Generates a field list + * Determine which fields of a form should be used for hash * * @param string $model Model name - * @param array $options Options + * @param mixed $options Options * @access private */ function __secure($model = null, $options = null) { if (!$model) { $model = $this->model(); } + $view =& ClassRegistry::getObject('view'); + $field = $view->field; + $fieldSuffix = $view->fieldSuffix; if (isset($this->params['_Token']) && !empty($this->params['_Token'])) { if (!empty($this->params['_Token']['disabledFields'])) { foreach ($this->params['_Token']['disabledFields'] as $value) { $parts = preg_split('/\/|\./', $value); if (count($parts) == 1) { - if ($parts[0] === $this->field()) { + if ($parts[0] === $field || $parts[0] === $fieldSuffix) { return; } } elseif (count($parts) == 2) { - if ($parts[0] === $this->model() && $parts[1] === $this->field()) { + if ($parts[0] === $model && ($parts[1] === $field || $parts[1] === $fieldSuffix)) { return; } } } - if (!is_null($options)) { - $this->fields[$model][$this->field()] = $options; - return; - } - $this->fields[$model][] = $this->field(); - return; } - if (!is_null($options)) { - $this->fields[$model][$this->field()] = $options; - return; - } - if ((isset($this->fields[$model]) && !in_array($this->field(), $this->fields[$model], true)) || !isset($this->fields[$model])) { - $this->fields[$model][] = $this->field(); + $this->__fields($model, $field, $fieldSuffix, $options); + return; + } + } +/** + * Generates a field list used to secure forms + * + * @param string $model + * @param string $field + * @param string $fieldSuffix + * @param mixed $options + * @access private + */ + function __fields($model, $field, $fieldSuffix, $options) { + if (!is_null($options)) { + if (is_numeric($field)) { + $this->fields[$model][$field][$fieldSuffix] = $options; + } else { + $this->fields[$model][$field] = $options; } return; } + if ((isset($this->fields[$model]) && !in_array($field, $this->fields[$model], true)) || !isset($this->fields[$model])) { + if (is_numeric($field)) { + $this->fields[$model][$field][] = $fieldSuffix; + } else { + $this->fields[$model][] = $field; + } + } + return; } /** * Returns true if there is an error for the given field, otherwise false diff --git a/cake/tests/cases/libs/controller/components/security.test.php b/cake/tests/cases/libs/controller/components/security.test.php index e32684f5b..b25bf1ed9 100644 --- a/cake/tests/cases/libs/controller/components/security.test.php +++ b/cake/tests/cases/libs/controller/components/security.test.php @@ -180,24 +180,27 @@ class SecurityComponentTest extends CakeTestCase { $this->Controller->Security->startup($this->Controller); $key = $this->Controller->params['_Token']['key']; - $data['Model'][0]['username'] = ''; - $data['Model'][0]['password'] = ''; - $data['Model'][1]['username'] = ''; - $data['Model'][1]['password'] = ''; + $data['Model'][0]['username'] = 'username'; + $data['Model'][0]['password'] = 'password'; + $data['Model'][1]['username'] = 'username'; + $data['Model'][1]['password'] = 'password'; $data['_Model'][0]['hidden'] = 'value'; $data['_Model'][1]['hidden'] = 'value'; + $data['_Model'][0]['valid'] = '0'; + $data['_Model'][1]['valid'] = '0'; $data['__Token']['key'] = $key; $fields = array( 'Model' => array( - 0 => array('username', 'password', 'hidden'), - 1 => array('username', 'password', 'hidden')), + 0 => array('username', 'password', 'valid'), + 1 => array('username', 'password', 'valid')), '_Model' => array( - 0 => array('hidden' => 'value'), - 1 => array('hidden' => 'value')), + 0 => array('hidden' => 'value', 'valid' => '0'), + 1 => array('hidden' => 'value', 'valid' => '0')), '__Token' => array('key' => $key)); $fields = $this->__sortFields($fields); + $fields = urlencode(Security::hash(serialize($fields) . Configure::read('Security.salt'))); $data['__Token']['fields'] = $fields; @@ -208,6 +211,9 @@ class SecurityComponentTest extends CakeTestCase { unset($data['_Model']); $data['Model'][0]['hidden'] = 'value'; $data['Model'][1]['hidden'] = 'value'; + $data['Model'][0]['valid'] = '0'; + $data['Model'][1]['valid'] = '0'; + $this->assertTrue($this->Controller->data == $data); } diff --git a/cake/tests/cases/libs/view/helpers/form.test.php b/cake/tests/cases/libs/view/helpers/form.test.php index 79daf4427..b4e82c826 100644 --- a/cake/tests/cases/libs/view/helpers/form.test.php +++ b/cake/tests/cases/libs/view/helpers/form.test.php @@ -258,6 +258,126 @@ class FormHelperTest extends CakeTestCase { ); $this->Form->params['_Token']['key'] = $key; $result = $this->Form->secure($fields); + + $fields = $this->__sortFields($fields); + $expected = urlencode(Security::hash(serialize($fields) . Configure::read('Security.salt'))); + $this->assertPattern('/'.$expected.'/', $result); + $this->assertPattern('/input type="hidden" name="data\[__Token\]\[fields\]" value="'.$expected.'"/', $result); + } + + function testFormSecurityMultipleFields() { + $key = 'testKey'; + $fields = array( + 'Model' => array( + 0 => array('username', 'password', 'valid'), + 1 => array('username', 'password', 'valid')), + '_Model' => array( + 0 => array('hidden' => 'value', 'valid' => '0'), + 1 => array('hidden' => 'value', 'valid' => '0')), + '__Token' => array('key' => $key)); + $this->Form->params['_Token']['key'] = $key; + $result = $this->Form->secure($fields); + + $fields = $this->__sortFields($fields); + $expected = urlencode(Security::hash(serialize($fields) . Configure::read('Security.salt'))); + $this->assertPattern('/'.$expected.'/', $result); + $this->assertPattern('/input type="hidden" name="data\[__Token\]\[fields\]" value="'.$expected.'"/', $result); + } + + function testFormSecurityMultipleInputFields() { + $key = 'testKey'; + $this->Form->params['_Token']['key'] = $key; + $this->Form->create(); + + $this->Form->hidden('Addresses.0.id', array('value' => '123456')); + $this->Form->input('Addresses.0.title'); + $this->Form->input('Addresses.0.first_name'); + $this->Form->input('Addresses.0.last_name'); + $this->Form->input('Addresses.0.address'); + $this->Form->input('Addresses.0.city'); + $this->Form->input('Addresses.0.phone'); + $this->Form->hidden('Addresses.1.id', array('value' => '654321')); + $this->Form->input('Addresses.1.title'); + $this->Form->input('Addresses.1.first_name'); + $this->Form->input('Addresses.1.last_name'); + $this->Form->input('Addresses.1.address'); + $this->Form->input('Addresses.1.city'); + $this->Form->input('Addresses.1.phone'); + + $fields = array( + 'Addresses' => array( + 0 => array('title', 'first_name', 'last_name', 'address', 'city', 'phone'), + 1 => array('title', 'first_name', 'last_name', 'address', 'city', 'phone')), + '_Addresses' => array( + 0 => array('id' => '123456'), + 1 => array('id' => '654321')), + '__Token' => array('key' => $key)); + + $fields = $this->__sortFields($fields); + $result = $this->Form->secure($this->Form->fields); + $expected = urlencode(Security::hash(serialize($fields) . Configure::read('Security.salt'))); + $this->assertPattern('/'.$expected.'/', $result); + $this->assertPattern('/input type="hidden" name="data\[__Token\]\[fields\]" value="'.$expected.'"/', $result); + } + + function testFormSecurityMultipleInputDisabledFields() { + $key = 'testKey'; + $this->Form->params['_Token']['key'] = $key; + $this->Form->params['_Token']['disabledFields'] = array('first_name', 'address'); + $this->Form->create(); + + $this->Form->hidden('Addresses.0.id', array('value' => '123456')); + $this->Form->input('Addresses.0.title'); + $this->Form->input('Addresses.0.first_name'); + $this->Form->input('Addresses.0.last_name'); + $this->Form->input('Addresses.0.address'); + $this->Form->input('Addresses.0.city'); + $this->Form->input('Addresses.0.phone'); + $this->Form->hidden('Addresses.1.id', array('value' => '654321')); + $this->Form->input('Addresses.1.title'); + $this->Form->input('Addresses.1.first_name'); + $this->Form->input('Addresses.1.last_name'); + $this->Form->input('Addresses.1.address'); + $this->Form->input('Addresses.1.city'); + $this->Form->input('Addresses.1.phone'); + + $fields = array( + 'Addresses' => array( + 0 => array('title', 'last_name', 'city', 'phone'), + 1 => array('title', 'last_name', 'city', 'phone')), + '_Addresses' => array( + 0 => array('id' => '123456'), + 1 => array('id' => '654321')), + '__Token' => array('key' => $key)); + + $fields = $this->__sortFields($fields); + $result = $this->Form->secure($this->Form->fields); + $expected = urlencode(Security::hash(serialize($fields) . Configure::read('Security.salt'))); + $this->assertPattern('/'.$expected.'/', $result); + $this->assertPattern('/input type="hidden" name="data\[__Token\]\[fields\]" value="'.$expected.'"/', $result); + } + + function testFormSecurityInputDisabledFields() { + $key = 'testKey'; + $this->Form->params['_Token']['key'] = $key; + $this->Form->params['_Token']['disabledFields'] = array('first_name', 'address'); + $this->Form->create(); + + $this->Form->hidden('Addresses.id', array('value' => '123456')); + $this->Form->input('Addresses.title'); + $this->Form->input('Addresses.first_name'); + $this->Form->input('Addresses.last_name'); + $this->Form->input('Addresses.address'); + $this->Form->input('Addresses.city'); + $this->Form->input('Addresses.phone'); + + $fields = array( + 'Addresses' => array('title', 'last_name', 'city', 'phone'), + '_Addresses' => array('id' => '123456'), + '__Token' => array('key' => $key)); + + $fields = $this->__sortFields($fields); + $result = $this->Form->secure($this->Form->fields); $expected = urlencode(Security::hash(serialize($fields) . Configure::read('Security.salt'))); $this->assertPattern('/'.$expected.'/', $result); $this->assertPattern('/input type="hidden" name="data\[__Token\]\[fields\]" value="'.$expected.'"/', $result); @@ -707,15 +827,15 @@ class FormHelperTest extends CakeTestCase { $this->assertPattern('/id="ModelField1"/', $result); $this->assertPattern('/id="ModelField0".*checked="checked"/', $result); $this->assertPattern('/(]+name="data\[Model\]\[field\]"[^<>]+>.+){2}/', $result); - + $result = $this->Form->radio('Model.field', array('1' => 'Yes', '0' => 'No'), array('value' => null)); $this->assertPattern('/id="ModelField1"/', $result); $this->assertPattern('/id="ModelField0"\svalue="0"\s(?!checked="checked")/', $result); - + $result = $this->Form->radio('Model.field', array('1' => 'Yes', '0' => 'No')); $this->assertPattern('/id="ModelField1"/', $result); $this->assertPattern('/id="ModelField0"\svalue="0"\s(?!checked="checked")/', $result); - + $result = $this->Form->input('Newsletter.subscribe', array('legend' => 'Legend title', 'type' => 'radio', 'options' => array('0' => 'Unsubscribe', '1' => 'Subscribe'))); $expected = '
Legend title
'; $this->assertEqual($result, $expected);