How to implement Password expiration
Prerequisite: You must be familiar with the Syntax used in Tutorials and have already created an extension.
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é)