StoredPassword: new element type -> hidden strings

fixes #1872
This commit is contained in:
Thomas Gelf 2019-07-10 13:11:58 +02:00
parent 7ed1aff475
commit a97f31e657
3 changed files with 142 additions and 1 deletions

View File

@ -0,0 +1,60 @@
<?php
use dipl\Html\Html;
use dipl\Html\HtmlDocument;
/**
* Please see StoredPassword (the Form Element) for related documentation
*
* We're rendering the following fields:
*
* - ${name}[_value]:
* - ${name}[_sent]:
*
* Avoid complaints about class names:
* @codingStandardsIgnoreStart
*/
class Zend_View_Helper_FormStoredPassword extends Zend_View_Helper_FormElement
{
public function formStoredPassword($name, $value = null, $attribs = null)
{
// @codingStandardsIgnoreEnd
$info = $this->_getInfo($name, $value, $attribs);
\extract($info); // name, value, attribs, options, listsep, disable
$sentValue = $this->stripAttribute($attribs, 'sentValue');
$res = new HtmlDocument();
$el = Html::tag('input', [
'type' => 'password',
'name' => "${name}[_value]",
'id' => $id,
]);
$res->add($el);
$res->add(Html::tag('input', [
'type' => 'hidden',
'name' => "${name}[_sent]",
'value' => 'y'
]));
if (\strlen($sentValue)) {
$el->getAttributes()->set('value', $sentValue);
} elseif (\strlen($value) > 0) {
$el->getAttributes()->set('value', '__UNCHANGED_VALUE__');
}
return $res;
}
protected function stripAttribute(& $attribs, $name, $default = null)
{
if (\array_key_exists($name, $attribs)) {
if (\strlen($attribs[$name])) {
return $attribs[$name];
}
unset($attribs[$name]);
}
return $default;
}
}

View File

@ -9,8 +9,27 @@ class DataTypeString extends DataTypeHook
{
public function getFormElement($name, QuickForm $form)
{
if ($this->getSetting('visibility', 'visible') === 'visible') {
$element = $form->createElement('text', $name);
} else {
$element = $form->createElement('storedPassword', $name);
}
return $element;
}
public static function addSettingsFormFields(QuickForm $form)
{
$form->addElement('select', 'visibility', [
'label' => $form->translate('Visibility'),
'multiOptions' => $form->optionalEnum([
'visible' => $form->translate('Visible'),
'hidden' => $form->translate('Hidden'),
]),
'value' => 'visible',
'required' => true,
]);
return $form;
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace Icinga\Module\Director\Web\Form\Element;
use Zend_Form_Element_Text as ZfText;
/**
* StoredPassword
*
* This is a special form field and it might look a little bit weird at first
* sight. It's main use-case are stored cleartext passwords a user should be
* allowed to change.
*
* While this might sound simple, it's quite tricky if you try to fulfill the
* following requirements:
*
* - the current password should not be rendered to the HTML page (unless the
* user decides to change it)
* - it must be possible to visually distinct whether a password has been set
* - it should be impossible to "see" the length of the stored password
* - a changed password must be persisted
* - forms might be subject to multiple submissions in case other fields fail.
* If the user changed the password during the first submission attempt, the
* new string should not be lost.
* - all this must happen within the bounds of ZF1 form elements and related
* view helpers. This means that there is no related context available - and
* we do not know whether the form has been submitted and whether the current
* values have been populated from DB
*
* @package Icinga\Module\Director\Web\Form\Element
*/
class StoredPassword extends ZfText
{
const UNCHANGED = '__UNCHANGED_VALUE__';
public $helper = 'formStoredPassword';
public function setValue($value)
{
if (\is_array($value) && isset($value['_value'], $value['_sent'])
&& $value['_sent'] === 'y'
) {
$value = $sentValue = $value['_value'];
if ($sentValue !== self::UNCHANGED) {
$this->setAttrib('sentValue', $sentValue);
}
} else {
$sentValue = null;
}
if ($value === self::UNCHANGED) {
return $this;
} else {
// Workaround for issue with modified DataTypes. This is Director-specific
if (\is_array($value)) {
$value = \json_encode($value);
}
return parent::setValue((string) $value);
}
}
}