You are browsing the documentation for iTop 2.7 which is not the current version.

Consider browsing to iTop 3.1 documentation

User password policy

What's new

Regex by default for all iTops, (new and upgrade)

No password expiration by default (new and iTop upgrade, user creation and change user)

XML configuration, over-writtable in Configuration file, not in Configuration file by default

Default behavior

  • The UserLocal has a custom behaviour during the DoCheckToWrite preventing the object persistence if the password does not respect the configured policies.
  • The existing passwords are not affected.
  • The admin acount created during the setup is not affected
  • All UI are affected, even the webservices.
  • Admin can't bypass the configuration.

Configuration

$MyModuleSettings = array(
        'authent-local' => array (
                'password_validation.pattern' => '',
        ),
);

Configure the password value policy using

  • password_validation.pattern: this let you define a pattern used to validate new passwords

default ''password_validation.pattern''

the default password_validation.pattern is ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{8,}$. It means :

  • at least one lower cased letter
  • at least one upper cased letter
  • at least one digit
  • at least one special character
  • more than 8 characters long

translation

If you change the pattern, you MUST change also the “password does not match the password_validation.pattern” using this translation key: Error:UserLocalPasswordValidator:UserPasswordPolicyRegex/ValidationFailed

Example of configuration

The configuration can either be defined using the XML or conf/production/config-itop.php. The example will make use of conf/production/config-itop.php because they are simpler to write/read, but our customers should be encourage to use the XML because doing so let them be sure to have the same configuration across their instances.

No policy at all

if you want to disable the pattern matching policy, just set an empty string.

$MyModuleSettings = array(
    'authent-local' => array(
        'password_validation.pattern' => '',
    ),
);

custom regex

Just use the standard PHP syntax (without the delimiters). This example force the password to be between 6 and 15 chars long: you should use the excellent https://regex101.com/ to test your regex.

$MyModuleSettings = array(
    'authent-local' => array(
        'password_validation.pattern' => '.{6,15}', 
    ),
);

Tests

Unit test exists here : test/coreExtensions/UserLocalTest.php.

Possible extensions

Here are some ideas of possible extensions. They are not available by defaut, by may (or may not) have already been coded by combodo.

Blacklist

It is quite easy to code. so easy that an example implementation will be proposed as a cookbook in a next chapter.

Previous password

This one, is a little more complicated, because :

  • iTop store only passwords hash,
  • and the salt is both random and hard to extract
    • (it is stored alongside the hash, and how to separate the salt and the hash depends upon the hash algorithm used.

So we write here a summary on own to write this validator:

  • The validator must implements iApplicationObjectExtension::OnDBUpdate() in addition to the \UserLocalPasswordValidator interface
    • in order to store the previous passwords hashes into a custom classe dedicated to this role
  • The check must be performed using a clear text password against this list of previous hashes.
    • In other words, it cannot be done by comparing two hases.
  • it seem reasonable to limit the number of previous stored hashes.
    • it can be made configurable

How to write an extension

You can add as many validator as you want, by making them implements the UserLocalPasswordValidator interface.

class MyCustomPasswordValidator implements UserLocalPasswordValidator
{
   // your code here ...
}

To perform the validation, just return a \ValidatePassword instance.

  • if the password is valid return new \UserLocalPasswordValidity(true)
  • if the password is not valid, return new \UserLocalPasswordValidity(false, $sMessage).
    • $sMessage must be an already translated message that will be displayed to the end user. Per convention, please use this form 'Error:UserLocalPasswordValidator:<yourClassName>/ValidationFailed' replacing <yourClassName> with your class name.

Cookbook : write a Blacklist validator

Create an extension with this class:

class UserPasswordPolicyBlacklist implements UserLocalPasswordValidator
{
        public function __construct()
        {
        }
 
        /**
         * @param string $proposedValue
         * @param UserLocal $oUserLocal
         * @param Config $config
         *
         * @return UserLocalPasswordValidity
         */
        public function ValidatePassword($proposedValue, UserLocal $oUserLocal, $config)
        {
                $sBlacklistFile = APPROOT.$config->GetModuleSetting('password-validation.blacklist_file', 'password_validation.blacklist_file');
                $handle = @fopen($sBlacklistFile, "r");
                if (! $handle) {
                        return new UserLocalPasswordValidity(
                                false,
                                'Unknown error : Failed to read the password blacklist.'
                        );
                }
 
                try {
                        while (($sBlackListPwd = fgets($handle, 4096)) !== false) {
                                if (trim($sBlackListPwd) == trim($proposedValue))
                                {
                                        $sMessage = Dict::S('Error:UserLocalPasswordValidator:UserPasswordPolicyBlacklist/ValidationFailed');
 
                                        return new UserLocalPasswordValidity(
                                                false,
                                                $sMessage
                                        );
                                }
                        }
                        if (!feof($handle)) {
                                return new UserLocalPasswordValidity(
                                        false,
                                        'Unknown error : Failed to read the password blacklist until the end.'
                                );
                        }
                }
                finally
                {
                        fclose($handle);
                }
 
                return new UserLocalPasswordValidity(true);
        }
}

then, use this configuration to enable it :

$MyModuleSettings = array(
    'password_validation.classes' => array(
        'UserPasswordPolicyBlacklist ' => array(
            'blacklist_file' => 'data/passwordBlacklist.txt',
        ),
    ),
);

data/passwordBlacklist.txt have to be composed by one forbidden password per line. you may per example use this file : https://github.com/danielmiessler/SecLists/blob/master/Passwords/darkweb2017-top10000.txt it contains the 10.000 most frequent passwords.

2_7_0/feature/password-policy.txt · Last modified: 2023/03/15 11:31 (external edit)
Back to top
Contact us