:: Version 2.7.0 ::

How to implement Password expiration

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

learning:
Force local users to change their passwords when they are expired
level:
Advanced
domains:
PHP, twig
min version:
2.7.0

In this tutorial, we will describe a mean to force existing users to change their password to comply to a newly added complexity policy.

The administrator would set the expiration flag of all users to expired, then when a user will login, once the user is ok, we will ask him to change his password.

In order to do that, we need to plug a check on the Login Finite State Machine, in the state user ok. And if the password is expired, display a form to request a new password, then store it, before going on with the state machine.

Plug the check

class MyClass extend AbstractLoginFSMExtension
{
    public function ListSupportedLoginModes() { return array('form'); }
 
    protected function OnUsersOK(&$iErrorCode)
    {
        /* Enter the specific code here */
        return LoginWebPage::LOGIN_FSM_CONTINUE;
    }
}

Check if password is expired

  $oUser = UserRights::GetUserObject();
        if ($oUser->Get('expiration') == 'expired')
        {
           /* add more code here */
        }

Request a new password

This iTop code can be a source, to display a form to request a new password

public function DisplayChangePwdForm($bFailedLogin = false, $sIssue = null)
        {
                $oTwigContext = new LoginTwigRenderer();
                $aVars = $oTwigContext->GetDefaultVars();
                $aVars['bFailedLogin'] = $bFailedLogin;
                $aVars['sIssue'] = $sIssue;
                $oTwigContext->Render($this, 'changepwdform.html.twig', $aVars);
        }

This template can be reused, after removing the old_pwd part as at this state of the login, the user has already provided it and it has already been checked as valid, so no need to ask it again.

iTop/templates/login/password/changepwdform.html.twig

There is also a changepwdform.js.twig file which control the fact that the two entries are equal and that the password matches the policies. That one can be reuse as is.

FIXME pourquoi et comment est-il appelé, … ?

Save the new password

Get and save the new password

  $sNewPwd = utils::ReadPostedParam('new_pwd', '', 'raw_data');
        $oUser->Set('password', $sNewPwd);
        $oUser->Set('expiration', 'limited');
        $oUser->DB_Update();

Be ready for error

Because the password may not be provided correctly or not compliant to policy, we must protect the code with try and catch

try
{
        if (!UserRights::ChangePassword($sOldPwd, $sNewPwd))
        {
                $oPage = self::NewLoginWebPage();
                $oPage->DisplayChangePwdForm(true); // new pwd was not compliant ???
                $oPage->output();
                exit;
        }
}
catch (CoreCannotSaveObjectException $e)
{
        $oPage = self::NewLoginWebPage();
        $oPage->DisplayChangePwdForm(true, $e->getIssue()); // password policy was not met.
        $oPage->output();
        exit;
}

Notes

When an extension automate the expiration behavior, it should alter the translation UserLocal:password:expiration displayed within the edit“ page of the UserLocal in order to reflect this.

We have not implemented any password expiration by default, but the fields exists on the UserLocal class to handle it if an extension brings the behavior using the new login API.

A l'aide de l'extensibilité du login, l'extension devra :

  • calculer si c'est expiré

suggestion de Vincent qui découple bien le code: regarder juste le “force_expire” qui serait Set ailleurs, via une implémentation libre (via un cron, un import csv, ou juste en création)

  • bloquer le user et lui afficher une IHM le forçant a saisir un nouveau MDP afin de pouvoir continuer
  • attention : je ne sais pas si on pourra vérifier qu'il est different du précédent ⇒ c'est une autre extension.
  • si on est sympa, on pourra lui envoyer un mail un peu avant l'expiration du mdp afin qu'il le change.

Gestion des contraintes

  • Surcharge des méthodes CheckPasswordConstraints() et onChangePassword() pour faire les traitements nécessaires (vérifs expression régulière, vérifs historique du mot de passe, vérifs d'expiration, …)
  • Message d'erreur de CheckValues() a faire plus joli dans l'interface utilisateur. Peut etre faire un nouveau type d'Exception pour attraper celle ci et faire le traitement plus joli, ce qui permet de garder le comportement actuel pour le reste.

Interface utilisateur

  • emploi de la machine a état du login pour bloquer le user et lui faire saisir un nouveau mdp si celui ci est expiré. (Formulaire avec login, mdp actuel, nouveau mdp), essayer de se brancher sur la page de changement de mot de passe actuelle.
  • Afficher l'aide à la saisie du bug 524 - API pour le controle des passwords sur les pages suivantes :
  • Page de changement de mot de passe (non connecté)
2_7_0/customization/password-expiration.txt · Last modified: 2020/04/15 15:23 (external edit)
Back to top
Contact us