Implement password policy with hook#5419
Conversation
Al2Klimov
left a comment
There was a problem hiding this comment.
During setup, the wizard prompts me for a username and password "to configure your first administrative account". This should enforce the chosen password policy.
97e07ad to
39bbc53
Compare
| public static function register(): void | ||
| { | ||
| Hook::register(self::HOOK_NAME, static::class, static::class); | ||
| } |
There was a problem hiding this comment.
- Wait until Introduce
HookEssentials#5474 is merged - Use that trait
|
|
||
| class PasswordPolicy extends PasswordPolicyHook | ||
| { | ||
| use Translation; |
There was a problem hiding this comment.
You use the Translation trait only but never call $this->translate() on any of the strings.
| return $passwordPolicy; | ||
| } | ||
|
|
||
| public static function addPasswordPolicyDescription(Form $form, PasswordPolicy $passwordPolicy): void |
| const DEFAULT_PASSWORD_POLICY = AnyPasswordPolicy::class; | ||
|
|
||
| /** @var string INI configuration section for password policy */ | ||
| const CONFIG_SECTION = 'global'; |
There was a problem hiding this comment.
Consider moving password policy to the security section.
There was a problem hiding this comment.
Yeah, you also made a separate permission for the CSP stuff, didn't you?
There was a problem hiding this comment.
I was mostly talking about the [security] section of the config.ini file here.
But yes, I added 'config/security' in #5477 for all security related configuration.
The only thing that is currently in this section is CSP, but it seems password policy would fit well there.
| * | ||
| * This form is not used directly but as subform for the {@link GeneralConfigForm}. | ||
| */ | ||
| class PasswordPolicyConfigForm extends Form |
There was a problem hiding this comment.
There already was some discussion with @lippserd to move this form into a new Security section in IW2.
We should consider converting this form into an ipl-web based form instead during this process.
|
Since we now have the new callouts (Icinga/ipl-web#358) consider using them in the |
a3bc5d9 to
f18c593
Compare
|
Changed class loading to ask the hook by a canonical name instead of storing the class path and instantiating a class from that.
Used callouts |
fd2bca3 to
358a20d
Compare
`PasswordPolicy` defines the contract every implementation must fulfill. A display name, an optional description shown to users, and a `validate()` method that returns a list of violation strings. `PasswordPolicyHook` implements the interface and adds `loadConfigured()`, a static factory that reads the selected policy name from application configuration and returns the matching hook implementation, falling back to `AnyPasswordPolicy` when none is configured. `PasswordPolicyValidator` wraps a `PasswordPolicy` in a Zend form validator so it can be attached to a password element without additional glue. `PasswordPolicyHelper` handles form-level plumbing: attaching the validator, rendering an info callout with the policy description, and falling back to an error callout when loading the configured policy fails. Co-authored-by: Johannes Rauh <johannes.rauh@icinga.com> Co-authored-by: Alexander Rieß <alexander.riess@icinga.com>
`AnyPasswordPolicy` is the permissive default. It accepts every password without validation. It exists so the policy dropdown always has a valid selection when no enforcement is wanted. `CommonPasswordPolicy` enforces a baseline. A minimum of 12 characters, at least one digit, one special character, one uppercase letter, and one lowercase letter. Its `getDescription()` return value is rendered in an info callout before the password field so users know the requirements before submitting. Co-authored-by: Johannes Rauh <johannes.rauh@icinga.com> Co-authored-by: Alexander Rieß <alexander.riess@icinga.com>
Registers `CommonPasswordPolicy` and `AnyPasswordPolicy` so they are available when `PasswordPolicyHook::loadConfigured()` resolves the active policy at runtime. Co-authored-by: Johannes Rauh <johannes.rauh@icinga.com> Co-authored-by: Alexander Rieß <alexander.riess@icinga.com>
Adds a policy selector to Configuration > Application > General. The dropdown lists all registered `PasswordPolicyHook` implementations by their display name. The selected value is persisted under `[authentication]` in `config.ini` and read back by `PasswordPolicyHook::loadConfigured()` at runtime. Co-authored-by: Johannes Rauh <johannes.rauh@icinga.com> Co-authored-by: Alexander Rieß <alexander.riess@icinga.com>
`PasswordPolicyHelper::apply()` is wired into every form that sets or resets a database-backed password. The user account change-password form, the admin user create and edit form, and the setup wizard admin account page. `UserForm` previously shared element creation between insert and update by having `createUpdateElements` call `createInsertElements`. That gave the update path a password element identical to insert's, making it impossible for each path to attach the validator with the correct `$oldPasswordElementName` argument. Extracting the shared fields into `createCommonElements` gives each path independent control over its own password element. Co-authored-by: Johannes Rauh <johannes.rauh@icinga.com> Co-authored-by: Alexander Rieß <alexander.riess@icinga.com>
Adds a new section to the authentication chapter covering the built-in policies and their configuration under Configuration > Application > General, and a worked example of a custom policy module with the full hook implementation, `module.info`, and `run.php` registration. Co-authored-by: Johannes Rauh <johannes.rauh@icinga.com> Co-authored-by: Alexander Rieß <alexander.riess@icinga.com>
Add password policy support for database-backed user accounts. Administrators can select a policy under Configuration > Application > General. It is then enforced on every form that sets or resets a password. The account change-password form, the admin user create and edit form, and the setup wizard admin account page.
Two built-in policies ship with this change. None (the default) accepts any password without validation. Common enforces a baseline: minimum 12 characters, at least one digit, one special character, one lowercase letter, and one uppercase letter. The active policy's requirements are shown as an info callout below the password field so users know what to enter before submitting. A configuration error falls back to an error callout rather than breaking the form.
Third-party modules can provide additional policies by implementing
PasswordPolicyHook. The new section indoc/05-Authentication.mdcovers the configuration UI and a worked example of a custom policy module.resolve #4401