:: Version 2.7.0 ::

How to create your own password policy

Prerequisite: You must be familiar with the Syntax used in Tutorials and have already created an extension.

learning:
Add additional checks on local user passwords
level:
Medium
domains:
PHP
min version:
2.7.0

Possible policies

Here are some ideas, they are not available in iTop. But you can write an extension to implement the policy and have it controlled by iTop automatically.

Blacklist Policy

Some passwords are so easy to guess that they are not efficient. There exist lists of weak passwords, and you could write a policy which would check that a user defined password is not in that list.

It is quite easy to code, so we will use it as example in this tutorial

Password different from previous passwords

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.

Example: 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 has to be composed of 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/customization/password-policy.txt ยท Last modified: 2020/04/15 15:23 (external edit)
Back to top
Contact us