From e4c0f271b00765b46ce85e614d0c48aad4e72630 Mon Sep 17 00:00:00 2001 From: Aaron Carlino Date: Tue, 24 Apr 2018 15:51:58 +1200 Subject: [PATCH] [ss-2018-013] Ensure passwords do not get added to session on submission failure --- forms/PasswordField.php | 31 +++++++++++++++++ tests/forms/FormTest.php | 58 +++++++++++++++++++++++++++++++ tests/forms/PasswordFieldTest.php | 38 ++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 tests/forms/PasswordFieldTest.php diff --git a/forms/PasswordField.php b/forms/PasswordField.php index c230ee9bf..588c4c397 100644 --- a/forms/PasswordField.php +++ b/forms/PasswordField.php @@ -7,6 +7,7 @@ * @subpackage fields-formattedinput */ class PasswordField extends TextField { + /** * Controls the autocomplete attribute on the field. * @@ -15,6 +16,13 @@ class PasswordField extends TextField { */ private static $autocomplete; + /** + * If true, the field can accept a value attribute, e.g. from posted form data + * @var bool + */ + protected $allowValuePostback = false; + + /** * Returns an input field. * @@ -33,6 +41,24 @@ class PasswordField extends TextField { parent::__construct($name, $title, $value); } + /** + * @param bool $bool + * @return $this + */ + public function setAllowValuePostback($bool) { + $this->allowValuePostback = (bool) $bool; + + return $this; + } + + /** + * @return bool + */ + public function getAllowValuePostback() { + return $this->allowValuePostback; + } + + /** * {@inheritdoc} */ @@ -41,6 +67,11 @@ class PasswordField extends TextField { 'type' => 'password', ); + + if (!$this->getAllowValuePostback()) { + $attributes['value'] = null; + } + $autocomplete = Config::inst()->get('PasswordField', 'autocomplete'); if($autocomplete) { diff --git a/tests/forms/FormTest.php b/tests/forms/FormTest.php index 26e0288aa..e008cff8a 100644 --- a/tests/forms/FormTest.php +++ b/tests/forms/FormTest.php @@ -24,6 +24,13 @@ class FormTest extends FunctionalTest { Config::inst()->remove('SSViewer', 'theme'); } + public function boolDataProvider() { + return array( + array(false), + array(true), + ); + } + public function testLoadDataFromRequest() { $form = new Form( new Controller(), @@ -728,6 +735,57 @@ class FormTest extends FunctionalTest { $this->assertEmpty($formData['ExtraFieldCheckbox']); } + + /** + * @dataProvider boolDataProvider + * @param bool $allow + */ + public function testPasswordRemovedFromResponseData($allow) { + $form = $this->getStubForm(); + $form->enableSecurityToken(); + $form->Fields()->push( + new TextField('Username') + ); + $form->Fields()->push( + PasswordField::create('Password') + ->setAllowValuePostback($allow) + ); + $form->Actions()->push( + new FormAction('submit') + ); + $form->handleRequest( + new SS_HTTPRequest( + 'POST', + '/', + array(), + array( + 'Username' => 'uncle', + 'Password' => 'cheese', + 'SecurityID' => 'FAIL', + 'action_submit' => 1 + ) + ), + DataModel::inst() + ); + + $parser = new CSSContentParser($result = $form->forTemplate()); + $passwords = $parser->getBySelector('input#Password'); + $this->assertNotNull($passwords); + $this->assertCount(1, $passwords); + /* @var \SimpleXMLElement $password */ + $password = $passwords[0]; + $attrs = iterator_to_array($password->attributes()); + + if ($allow) { + $this->assertArrayHasKey('value', $attrs); + $this->assertEquals('cheese', $attrs['value']); + } else { + $this->assertArrayNotHasKey('value', $attrs); + } + + } + + protected function getStubForm() { return new Form( new FormTest_Controller(), diff --git a/tests/forms/PasswordFieldTest.php b/tests/forms/PasswordFieldTest.php new file mode 100644 index 000000000..487a62120 --- /dev/null +++ b/tests/forms/PasswordFieldTest.php @@ -0,0 +1,38 @@ +update('PasswordField', 'autocomplete', $bool); + $field = new PasswordField('test'); + $attrs = $field->getAttributes(); + + $this->assertArrayHasKey('autocomplete', $attrs); + $this->assertEquals($bool ? 'on' : 'off', $attrs['autocomplete']); + } + + /** + * @dataProvider boolDataProvider + * @param bool $bool + */ + public function testValuePostback($bool) { + $field = PasswordField::create('test', 'test', 'password') + ->setAllowValuePostback($bool); + $attrs = $field->getAttributes(); + + $this->assertArrayHasKey('value', $attrs); + $this->assertEquals($bool ? 'password' : '', $attrs['value']); + } +}