diff --git a/application/forms/Account/ChangePasswordForm.php b/application/forms/Account/ChangePasswordForm.php index 419731843..42c5cbc72 100644 --- a/application/forms/Account/ChangePasswordForm.php +++ b/application/forms/Account/ChangePasswordForm.php @@ -5,6 +5,7 @@ namespace Icinga\Forms\Account; use Icinga\Application\Config; use Icinga\Application\Hook\PasswordPolicyHook; +use Icinga\Application\ProvidedHook\DefaultPasswordPolicy; use Icinga\Authentication\PasswordValidator; use Icinga\Authentication\User\DbUserBackend; use Icinga\Data\Filter\Filter; @@ -25,22 +26,12 @@ class ChangePasswordForm extends Form protected $backend; /** - * The password policy object + * The password policy object * - * @var PasswordPolicyHook|null + * @var PasswordPolicyHook */ - protected ?PasswordPolicyHook $passwordPolicyObject; + protected ?PasswordPolicyHook $passwordPolicyObject = null; - /** - * Constructor - * - * @param PasswordPolicyHook|null $passwordPolicyObject - */ - public function __construct(?PasswordPolicyHook $passwordPolicyObject = null) - { - $this->passwordPolicyObject = $passwordPolicyObject; - parent::__construct(); - } /** * {@inheritdoc} */ @@ -54,20 +45,15 @@ class ChangePasswordForm extends Form */ public function createElements(array $formData) { - if ($this->passwordPolicyObject === null) { - $passwordPolicy = Config::app()->get( - 'global', - 'password_policy' - ); - if (isset($passwordPolicy) && class_exists($passwordPolicy)) { - $this->passwordPolicyObject = new $passwordPolicy(); - } - } + $passwordPolicy = Config::app()->get( + 'global', + 'password_policy' + ); + $this->passwordPolicyObject = new $passwordPolicy(); + $passwordPolicyDescription = $this->passwordPolicyObject->displayPasswordPolicy(); - if ($this->passwordPolicyObject) { - $this->addDescription( - $this->passwordPolicyObject->displayPasswordPolicy() - ); + if ($passwordPolicyDescription != '') { + $this->addDescription($passwordPolicyDescription); } $this->addElement( @@ -84,7 +70,9 @@ class ChangePasswordForm extends Form array( 'label' => $this->translate('New Password'), 'required' => true, - 'validators' => [new PasswordValidator($this->passwordPolicyObject)] + 'validators' => + $this->passwordPolicyObject !== null ? + [new PasswordValidator($this->passwordPolicyObject)] : [], ) ); $this->addElement( diff --git a/application/forms/Config/General/PasswordPolicyConfigForm.php b/application/forms/Config/General/PasswordPolicyConfigForm.php index f8edcf592..d87f08588 100644 --- a/application/forms/Config/General/PasswordPolicyConfigForm.php +++ b/application/forms/Config/General/PasswordPolicyConfigForm.php @@ -4,6 +4,7 @@ namespace Icinga\Forms\Config\General; use Icinga\Application\Hook; +use Icinga\Application\ProvidedHook\DefaultPasswordPolicy; use Icinga\Web\Form; /** @@ -35,13 +36,12 @@ class PasswordPolicyConfigForm extends Form 'Enforce strong password requirements for new passwords' ), 'label' => $this->translate('Password Policy'), - 'multiOptions' => array_merge( - ['' => $this->translate('No Password Policy')], - $passwordPolicies - ), + 'value' => DefaultPasswordPolicy::class, + 'multiOptions' =>$passwordPolicies ] ); + return $this; } } diff --git a/application/forms/Config/User/UserForm.php b/application/forms/Config/User/UserForm.php index 9b490db64..be6ce1490 100644 --- a/application/forms/Config/User/UserForm.php +++ b/application/forms/Config/User/UserForm.php @@ -17,7 +17,6 @@ class UserForm extends RepositoryForm * * @param array $formData The data sent by the user */ - protected function createInsertElements(array $formData) { $passwordPolicy = Config::app()->get('global', 'password_policy'); diff --git a/library/Icinga/Application/ApplicationBootstrap.php b/library/Icinga/Application/ApplicationBootstrap.php index 1537917df..cbe04b09a 100644 --- a/library/Icinga/Application/ApplicationBootstrap.php +++ b/library/Icinga/Application/ApplicationBootstrap.php @@ -8,6 +8,7 @@ use ErrorException; use Exception; use Icinga\Application\ProvidedHook\DbMigration; use Icinga\Application\ProvidedHook\DefaultPasswordPolicy; +use Icinga\Application\ProvidedHook\NonePasswordPolicy; use ipl\I18n\GettextTranslator; use ipl\I18n\StaticTranslator; use LogicException; @@ -742,6 +743,7 @@ abstract class ApplicationBootstrap { Hook::register('DbMigration', DbMigration::class, DbMigration::class); Hook::register('passwordpolicy', DefaultPasswordPolicy::class, DefaultPasswordPolicy::class); + Hook::register('passwordpolicy', NonePasswordPolicy::class, NonePasswordPolicy::class); return $this; } diff --git a/library/Icinga/Application/Hook/PasswordPolicyHook.php b/library/Icinga/Application/Hook/PasswordPolicyHook.php index 25dbb215e..185422811 100644 --- a/library/Icinga/Application/Hook/PasswordPolicyHook.php +++ b/library/Icinga/Application/Hook/PasswordPolicyHook.php @@ -26,5 +26,5 @@ interface PasswordPolicyHook * @return string|null Returns null if the password is valid, * otherwise returns an error message describing the violations */ - public function validatePassword(string $password): ?string; + public function validatePassword(string $password): ?array; } diff --git a/library/Icinga/Application/ProvidedHook/DefaultPasswordPolicy.php b/library/Icinga/Application/ProvidedHook/DefaultPasswordPolicy.php index 7547f3d36..3b1ed3dc8 100644 --- a/library/Icinga/Application/ProvidedHook/DefaultPasswordPolicy.php +++ b/library/Icinga/Application/ProvidedHook/DefaultPasswordPolicy.php @@ -4,6 +4,7 @@ namespace Icinga\Application\ProvidedHook; use Icinga\Application\Hook\PasswordPolicyHook; +use ipl\I18n\Translation; /** * Default implementation of a password policy @@ -17,56 +18,64 @@ use Icinga\Application\Hook\PasswordPolicyHook; */ class DefaultPasswordPolicy implements PasswordPolicyHook { - /** - * @inheritdoc - */ + use Translation; + public function getName(): string { - return 'Default Password Policy'; + return 'Default'; } - /** - * @inheritdoc - */ public function displayPasswordPolicy(): string { - $message = ( - 'Password requirements: ' . 'minimum 12 characters, ' . - 'at least 1 number, ' . - '1 special character, ' . 'uppercase and lowercase letters' - ); + $message = + $this->translate( + 'Password requirements: minimum 12 characters, at least 1 number, ' . + '1 special character, uppercase and lowercase letters.' + ); return $message; } - /** - * @inheritdoc - */ - public function validatePassword(string $password): ?string + public function validatePassword(string $password): ?array { $violations = []; if (strlen($password) < 12) { - $violations[] = ('Password must be at least 12 characters long'); + $violations[] = + $this->translate( + 'Password must be at least 12 characters long' + ); } if (! preg_match('/[0-9]/', $password)) { - $violations[] = ('Password must contain at least one number'); + $violations[] = + $this->translate( + 'Password must contain at least one number' + ); } if (! preg_match('/[^a-zA-Z0-9]/', $password)) { - $violations[] = ('Password must contain at least one special character'); + $violations[] = + $this->translate( + 'Password must contain at least one special character' + ); } if (! preg_match('/[A-Z]/', $password)) { - $violations[] = ('Password must contain at least one uppercase letter'); + $violations[] = + $this->translate( + 'Password must contain at least one uppercase letter' + ); } if (! preg_match('/[a-z]/', $password)) { - $violations[] = ('Password must contain at least one lowercase letter'); + $violations[] = + $this->translate( + 'Password must contain at least one lowercase letter' + ); } if (! empty($violations)) { - return implode(", ", $violations); + return $violations; } return null; diff --git a/library/Icinga/Application/ProvidedHook/NonePasswordPolicy.php b/library/Icinga/Application/ProvidedHook/NonePasswordPolicy.php new file mode 100644 index 000000000..82f38a19f --- /dev/null +++ b/library/Icinga/Application/ProvidedHook/NonePasswordPolicy.php @@ -0,0 +1,28 @@ +passwordPolicyObject = $passwordPolicyObject; } @@ -27,28 +29,17 @@ class PasswordValidator extends Zend_Validate_Abstract * Checks if password matches with password policy * throws a message if not * - * If no password policy is set, all passwords are considered valid - * * @param mixed $value The password to validate * * @return bool - * */ public function isValid($value): bool { - $this->_messages = []; - - if ($this->passwordPolicyObject === null) { + if ($this->passwordPolicyObject->validatePassword($value) === null) { return true; } - $errorMessage = $this->passwordPolicyObject->validatePassword($value); - - if ($errorMessage !== null) { - $this->_messages[] = $errorMessage; - return false; - } - - return true; + $this->_messages = $this->passwordPolicyObject->validatePassword($value); + return false; } }