mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-09-25 18:59:04 +02:00
Implement 'None Password Policy'-class for consistency
This commit is contained in:
parent
caf29a127d
commit
b618b10ead
@ -5,6 +5,7 @@ namespace Icinga\Forms\Account;
|
|||||||
|
|
||||||
use Icinga\Application\Config;
|
use Icinga\Application\Config;
|
||||||
use Icinga\Application\Hook\PasswordPolicyHook;
|
use Icinga\Application\Hook\PasswordPolicyHook;
|
||||||
|
use Icinga\Application\ProvidedHook\DefaultPasswordPolicy;
|
||||||
use Icinga\Authentication\PasswordValidator;
|
use Icinga\Authentication\PasswordValidator;
|
||||||
use Icinga\Authentication\User\DbUserBackend;
|
use Icinga\Authentication\User\DbUserBackend;
|
||||||
use Icinga\Data\Filter\Filter;
|
use Icinga\Data\Filter\Filter;
|
||||||
@ -25,22 +26,12 @@ class ChangePasswordForm extends Form
|
|||||||
protected $backend;
|
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}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@ -54,20 +45,15 @@ class ChangePasswordForm extends Form
|
|||||||
*/
|
*/
|
||||||
public function createElements(array $formData)
|
public function createElements(array $formData)
|
||||||
{
|
{
|
||||||
if ($this->passwordPolicyObject === null) {
|
$passwordPolicy = Config::app()->get(
|
||||||
$passwordPolicy = Config::app()->get(
|
'global',
|
||||||
'global',
|
'password_policy'
|
||||||
'password_policy'
|
);
|
||||||
);
|
$this->passwordPolicyObject = new $passwordPolicy();
|
||||||
if (isset($passwordPolicy) && class_exists($passwordPolicy)) {
|
$passwordPolicyDescription = $this->passwordPolicyObject->displayPasswordPolicy();
|
||||||
$this->passwordPolicyObject = new $passwordPolicy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->passwordPolicyObject) {
|
if ($passwordPolicyDescription != '') {
|
||||||
$this->addDescription(
|
$this->addDescription($passwordPolicyDescription);
|
||||||
$this->passwordPolicyObject->displayPasswordPolicy()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addElement(
|
$this->addElement(
|
||||||
@ -84,7 +70,9 @@ class ChangePasswordForm extends Form
|
|||||||
array(
|
array(
|
||||||
'label' => $this->translate('New Password'),
|
'label' => $this->translate('New Password'),
|
||||||
'required' => true,
|
'required' => true,
|
||||||
'validators' => [new PasswordValidator($this->passwordPolicyObject)]
|
'validators' =>
|
||||||
|
$this->passwordPolicyObject !== null ?
|
||||||
|
[new PasswordValidator($this->passwordPolicyObject)] : [],
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$this->addElement(
|
$this->addElement(
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
namespace Icinga\Forms\Config\General;
|
namespace Icinga\Forms\Config\General;
|
||||||
|
|
||||||
use Icinga\Application\Hook;
|
use Icinga\Application\Hook;
|
||||||
|
use Icinga\Application\ProvidedHook\DefaultPasswordPolicy;
|
||||||
use Icinga\Web\Form;
|
use Icinga\Web\Form;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,13 +36,12 @@ class PasswordPolicyConfigForm extends Form
|
|||||||
'Enforce strong password requirements for new passwords'
|
'Enforce strong password requirements for new passwords'
|
||||||
),
|
),
|
||||||
'label' => $this->translate('Password Policy'),
|
'label' => $this->translate('Password Policy'),
|
||||||
'multiOptions' => array_merge(
|
'value' => DefaultPasswordPolicy::class,
|
||||||
['' => $this->translate('No Password Policy')],
|
'multiOptions' =>$passwordPolicies
|
||||||
$passwordPolicies
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ class UserForm extends RepositoryForm
|
|||||||
*
|
*
|
||||||
* @param array $formData The data sent by the user
|
* @param array $formData The data sent by the user
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected function createInsertElements(array $formData)
|
protected function createInsertElements(array $formData)
|
||||||
{
|
{
|
||||||
$passwordPolicy = Config::app()->get('global', 'password_policy');
|
$passwordPolicy = Config::app()->get('global', 'password_policy');
|
||||||
|
@ -8,6 +8,7 @@ use ErrorException;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use Icinga\Application\ProvidedHook\DbMigration;
|
use Icinga\Application\ProvidedHook\DbMigration;
|
||||||
use Icinga\Application\ProvidedHook\DefaultPasswordPolicy;
|
use Icinga\Application\ProvidedHook\DefaultPasswordPolicy;
|
||||||
|
use Icinga\Application\ProvidedHook\NonePasswordPolicy;
|
||||||
use ipl\I18n\GettextTranslator;
|
use ipl\I18n\GettextTranslator;
|
||||||
use ipl\I18n\StaticTranslator;
|
use ipl\I18n\StaticTranslator;
|
||||||
use LogicException;
|
use LogicException;
|
||||||
@ -742,6 +743,7 @@ abstract class ApplicationBootstrap
|
|||||||
{
|
{
|
||||||
Hook::register('DbMigration', DbMigration::class, DbMigration::class);
|
Hook::register('DbMigration', DbMigration::class, DbMigration::class);
|
||||||
Hook::register('passwordpolicy', DefaultPasswordPolicy::class, DefaultPasswordPolicy::class);
|
Hook::register('passwordpolicy', DefaultPasswordPolicy::class, DefaultPasswordPolicy::class);
|
||||||
|
Hook::register('passwordpolicy', NonePasswordPolicy::class, NonePasswordPolicy::class);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -26,5 +26,5 @@ interface PasswordPolicyHook
|
|||||||
* @return string|null Returns null if the password is valid,
|
* @return string|null Returns null if the password is valid,
|
||||||
* otherwise returns an error message describing the violations
|
* otherwise returns an error message describing the violations
|
||||||
*/
|
*/
|
||||||
public function validatePassword(string $password): ?string;
|
public function validatePassword(string $password): ?array;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
namespace Icinga\Application\ProvidedHook;
|
namespace Icinga\Application\ProvidedHook;
|
||||||
|
|
||||||
use Icinga\Application\Hook\PasswordPolicyHook;
|
use Icinga\Application\Hook\PasswordPolicyHook;
|
||||||
|
use ipl\I18n\Translation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of a password policy
|
* Default implementation of a password policy
|
||||||
@ -17,56 +18,64 @@ use Icinga\Application\Hook\PasswordPolicyHook;
|
|||||||
*/
|
*/
|
||||||
class DefaultPasswordPolicy implements PasswordPolicyHook
|
class DefaultPasswordPolicy implements PasswordPolicyHook
|
||||||
{
|
{
|
||||||
/**
|
use Translation;
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
public function getName(): string
|
public function getName(): string
|
||||||
{
|
{
|
||||||
return 'Default Password Policy';
|
return 'Default';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
public function displayPasswordPolicy(): string
|
public function displayPasswordPolicy(): string
|
||||||
{
|
{
|
||||||
$message = (
|
$message =
|
||||||
'Password requirements: ' . 'minimum 12 characters, ' .
|
$this->translate(
|
||||||
'at least 1 number, ' .
|
'Password requirements: minimum 12 characters, at least 1 number, ' .
|
||||||
'1 special character, ' . 'uppercase and lowercase letters'
|
'1 special character, uppercase and lowercase letters.'
|
||||||
);
|
);
|
||||||
return $message;
|
return $message;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function validatePassword(string $password): ?array
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
public function validatePassword(string $password): ?string
|
|
||||||
{
|
{
|
||||||
$violations = [];
|
$violations = [];
|
||||||
|
|
||||||
if (strlen($password) < 12) {
|
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)) {
|
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)) {
|
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)) {
|
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)) {
|
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)) {
|
if (! empty($violations)) {
|
||||||
return implode(", ", $violations);
|
return $violations;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2025 Icinga GmbH | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Application\ProvidedHook;
|
||||||
|
|
||||||
|
use Icinga\Application\Hook\PasswordPolicyHook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* None Password Policy to validate all passwords
|
||||||
|
*/
|
||||||
|
class NonePasswordPolicy implements PasswordPolicyHook
|
||||||
|
{
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return 'None';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function displayPasswordPolicy(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validatePassword(string $password): ?array
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -9,16 +9,18 @@ use Zend_Validate_Abstract;
|
|||||||
class PasswordValidator extends Zend_Validate_Abstract
|
class PasswordValidator extends Zend_Validate_Abstract
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var PasswordPolicyHook|null
|
* The password policy object
|
||||||
|
*
|
||||||
|
* @var PasswordPolicyHook
|
||||||
*/
|
*/
|
||||||
private ?PasswordPolicyHook $passwordPolicyObject;
|
private PasswordPolicyHook $passwordPolicyObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param PasswordPolicyHook|null $passwordPolicyObject
|
* @param PasswordPolicyHook $passwordPolicyObject
|
||||||
*/
|
*/
|
||||||
public function __construct(?PasswordPolicyHook $passwordPolicyObject = null)
|
public function __construct(PasswordPolicyHook $passwordPolicyObject)
|
||||||
{
|
{
|
||||||
$this->passwordPolicyObject = $passwordPolicyObject;
|
$this->passwordPolicyObject = $passwordPolicyObject;
|
||||||
}
|
}
|
||||||
@ -27,28 +29,17 @@ class PasswordValidator extends Zend_Validate_Abstract
|
|||||||
* Checks if password matches with password policy
|
* Checks if password matches with password policy
|
||||||
* throws a message if not
|
* throws a message if not
|
||||||
*
|
*
|
||||||
* If no password policy is set, all passwords are considered valid
|
|
||||||
*
|
|
||||||
* @param mixed $value The password to validate
|
* @param mixed $value The password to validate
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public function isValid($value): bool
|
public function isValid($value): bool
|
||||||
{
|
{
|
||||||
$this->_messages = [];
|
if ($this->passwordPolicyObject->validatePassword($value) === null) {
|
||||||
|
|
||||||
if ($this->passwordPolicyObject === null) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$errorMessage = $this->passwordPolicyObject->validatePassword($value);
|
$this->_messages = $this->passwordPolicyObject->validatePassword($value);
|
||||||
|
return false;
|
||||||
if ($errorMessage !== null) {
|
|
||||||
$this->_messages[] = $errorMessage;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user