Skip to content

Implement password policy with hook#5419

Open
JolienTrog wants to merge 54 commits intomainfrom
password-policy
Open

Implement password policy with hook#5419
JolienTrog wants to merge 54 commits intomainfrom
password-policy

Conversation

@JolienTrog
Copy link
Copy Markdown
Contributor

Ref #4401

@JolienTrog JolienTrog requested a review from Al2Klimov August 26, 2025 09:22
@cla-bot cla-bot bot added the cla/signed label Aug 26, 2025
Al2Klimov

This comment was marked as resolved.

Al2Klimov

This comment was marked as resolved.

@JolienTrog JolienTrog requested a review from Al2Klimov August 26, 2025 15:21
@JolienTrog JolienTrog requested a review from Al2Klimov August 27, 2025 07:53
@JolienTrog JolienTrog requested a review from Al2Klimov August 28, 2025 08:35
@JolienTrog JolienTrog requested a review from Al2Klimov August 28, 2025 11:05
@JolienTrog JolienTrog requested a review from Al2Klimov August 28, 2025 13:15
@JolienTrog JolienTrog requested a review from Al2Klimov August 28, 2025 14:05
@JolienTrog JolienTrog requested a review from Al2Klimov August 28, 2025 15:26
Copy link
Copy Markdown
Member

@Al2Klimov Al2Klimov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During setup, the wizard prompts me for a username and password "to configure your first administrative account". This should enforce the chosen password policy.

@JolienTrog JolienTrog force-pushed the password-policy branch 2 times, most recently from 97e07ad to 39bbc53 Compare September 2, 2025 10:24

class PasswordPolicy extends PasswordPolicyHook
{
use Translation;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PHPDoc missing.

JolienTrog and others added 21 commits March 20, 2026 11:42
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
Co-authored-by: Eric Lippmann <eric.lippmann@icinga.com>
@JolienTrog JolienTrog requested a review from lippserd March 24, 2026 10:46
@lippserd lippserd added this to the 2.13 milestone Mar 24, 2026
@lippserd lippserd requested a review from Al2Klimov March 25, 2026 12:19
@lippserd lippserd removed this from the 2.13 milestone Mar 25, 2026
@Al2Klimov Al2Klimov requested a review from TheSyscall March 30, 2026 10:59
*/
abstract class PasswordPolicyHook implements PasswordPolicy
{
/** @var string Hook name *(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** @var string Hook name *(
/** @var string Hook name */

This will not parse correctly!

public static function all(): array
{
$passwordPolicies = [];
foreach (Hook::all('PasswordPolicy') as $class => $policy) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
foreach (Hook::all('PasswordPolicy') as $class => $policy) {
foreach (Hook::all(self::HOOK_NAME) as $class => $policy) {

We have the constant, why not use it?

) {
if ($oldPasswordElementName !== null && $form->getElement($oldPasswordElementName) === null) {
throw new LogicException(sprintf(
$this->translate('Form element "%s" was specified but does not exist in the form'),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using $this when not in object context. This will throw an exception if executed.

],
[['HtmlTag#div' => 'HtmlTag'], ['tag' => 'div', 'class' => 'form-notifications error']],
],
'value' => $this->translate(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using $this when not in object context. This will throw an exception if executed.


if (! class_exists($passwordPolicyClass)) {
throw new ConfigurationError(
$this->translate('Password policy class %s does not exist'),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using $this when not in object context. This will throw an exception if executed.

const DEFAULT_PASSWORD_POLICY = AnyPasswordPolicy::class;

/** @var string INI configuration section for password policy */
const CONFIG_SECTION = 'global';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider moving password policy to the security section.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you also made a separate permission for the CSP stuff, didn't you?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

'description' => $this->translate('Leave empty for not updating the user\'s password'),
'label' => $this->translate('Password'),
)
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there no check for the password policy here? We require admins to follow the policy when creating a user, why not during updates?

[
'description' => $this->translate('Enforce password requirements for new passwords'),
'label' => $this->translate('Password Policy'),
'value' => PasswordPolicyHelper::DEFAULT_PASSWORD_POLICY,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having an invalid value set in the config (class not found or not an instance of PasswordPolicy) causes IW2 to display Common.
I would expect some sort of error message here.


public function createElements(array $formData): static
{
$this->addElement(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to see the description of the password policy somewhere in this form.
We display it in every place where a password field exists, why not where we actually select the policy?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants