Chapitre: jAuth : système d'authentification
« jUrl : des URLs automatiques | ^ Composants de jelix | jAcl2 : système de droits » |
− Table des matières
Le système d'authentification de Jelix ne s'occupe que d'une seule chose : gérer des identifiants/mots de passe et des utilisateurs.
Il repose sur des pilotes (ou aussi appelés drivers) pour accéder aux données d'un utilisateur. C'est ainsi qu'il peut s'appuyer sur une base de données, un annuaire LDAP, etc. Pour le moment, il existe un pilote pour une base de données, un pilote pour un annuaire supportant LDAP et un pilote pouvant utiliser une classe quelconque.
Le système d'authentification repose sur plusieurs choses :
- Un plugin pour le coordinateur, nommé auth et livré en standard avec Jelix, vérifiant si l'authentification est effectuée pour les actions où elle est nécessaire.
- Une classe
jAuth
, permettant d'effectuer les différentes opérations sur l'authentification et la gestion des identifiants. Cette classe propose un système de plugin. - Un module, jauth, proposant un contrôleur et des templates par défaut. Il n'est, en principe, pas indispensable : vous pouvez tout à fait utiliser votre propre contrôleur, la mise en oeuvre étant relativement simple.
- Un objet stocké en session, contenant les informations sur l'utilisateur. Il est fourni par le pilote. Cela peut être un objet DAO, une simple classe, etc.
Pour utiliser l'authentification, vous devez installer au moins le plugin pour le coordinateur, et le configurer.
Le rôle du plugin auth :
- vérifier l'authentification ;
- gérer un timeout de session (optionnel) ;
- gérer la persistance de l'authentification via un cookie (optionnel) ;
- indiquer le driver à utiliser pour
jAuth
; - indiquer les paramètres pour le pilote (DAO pour jAuthDb, cn/sn/uid pour un pilote LDAP, etc.) ;
- indiquer ce qu'il faut faire en cas de non authentification.
Installer le plugin auth pour le coordinateur ¶
Pour l'activer, vous avez deux choix :
- soit vous voulez utiliser le module jauth qui propose zones et contrôleurs, dans ce cas, installez le et le plugin sera activé
- soit vous utilisez vos propres contrôleurs pour l'authentification, dans ce cas, il faut activer le plugin à la main.
En installant le module jauth ¶
Utilisez la commande module:configure
pour configurer le module :
$ cd myapp/
$ php dev.php module:configure jauth
Cela activera le module et le plugin, et creera un nouveau fichier
app/system/index/auth.coord.ini.php
, qui est la configuration du plugin et
du système d'authentification.
Puis lancer php install/installer.php
.
Installation à la main ¶
Copiez le fichier lib/jelix-modules/jauth/install/var/config/auth.coord.ini.php
dans le
repertoire de configuration du point d'entrée, par exemple, app/system/index/auth.coord.ini.php
.
Dans le fichier de configuration du point d'entrée, vous indiquerez alors dans
la section coordplugins
:
[coordplugins]
auth = "index/auth.coord.ini.php"
- *Note sur la déclaration du plugin :** Si vous utilisez plusieurs plugins de coordinateur, l'ordre de déclaration des plugins dans le fichier de configuration a une importance. Ainsi, si vous placez le plugin auth en premier, il faut savoir que les autres plugins ne seront pas exécutés dans le cas où le plugin auth demande une redirection (par exemple la page d'identification). En général, il convient donc de placer ce plugin après les plugins ne nécessitant pas d'authentification.
Pour en savoir plus sur les plugins : /plugins
Configurer le système d'authentification ¶
Vous devez ensuite éditer le fichier auth.coord.ini.php
, pour indiquer la
configuration du système d'authentification. Voici les différents paramètres.
Indiquer le driver ¶
Vous devez indiquer le nom du driver utilisé au niveau de l'option driver
.
Vous devez ensuite avoir une section portant ce même nom, pour les options
propres au driver.
driver=Db
Il est possible d'indiquer le driver dans la configuration générale, dans la section
coordplugin_auth
, dans le fichier mainconfig.ini.php
, localconfig.ini.php
ou le
fichier de configuration du point d'entrée.
[coordplugin_auth]
driver=Db
Les options dépendants des drivers, consultez la documentation sur les pilotes jauth pour activer l'un deux.
Fonction de hachage des mots de passe ¶
Depuis Jelix 1.4.1 (et 1.3.4, 1.2.10), il y a deux systèmes de hachage des mots de passe pour leur stockage. Jelix 1.4.1 et supérieur propose en effet une méthode plus sécurisée, utilisant l'API password de PHP 5.5.
Ancien système de hachage ¶
Par défaut la méthode utilisée pour le hachage des mots de passe est sha1
(dans jelix 1.1 et précedent, c'était md5
), mais il est possible
d'utiliser une autre fonction, qui accepte une chaine à hacher, et renvoi la
chaine hachée.
Notez que de nos jours, sha1
et md5
ne sont plus
considérés comme des méthodes de hashage sécurisées. Si possible utilisez
d'autres méthodes, comme le nouveau système de cryptage de Jelix 1.4.1.
Pour indiquer la fonction de hachage, indiquez son nom dans l'option
password_crypt_function
, dans la section de configuration du driver.
La fonction pourrait accepter d'autres paramètres, comme une valeur de "sel". Pour indiquer une telle fonction, vous devez faire précéder son nom par un nombre et ":" :
- "1:nomfunction": la fonction accepte en premier paramètre une valeur de
"sel", et en second la chaîne à encrypter. La valeur du sel doit être
indiquée dans l'option de configuration
password_salt
. - "2:nomfunction": la fonction a besoin de plus d'option ou d'autres options. Elle doit alors accepter en premier paramètre un tableau contenant toutes les options du drivers, et en second paramètre, la chaine à encrypter. Il est alors possible de mettre dans la configuration toutes les valeurs necessaires à cette fonction.
Pour créer votre propre fonction, stockez la dans un fichier php, et faites un
include dans le fichier application.init.php
de l'application par exemple.
Voici un exemple d'utilisation de la fonction PHP sha1
avec l'utilisation
d'une valeur de "sel". Il faut créer une fonction, (ici sha1WithSalt
qui est
déjà fournie par Jelix, vous n'avez pas à l'écrire):
function sha1WithSalt($salt, $password) {
return sha1($salt.':'.$password);
}
Et dans la configuration de l'authentification :
driver=Db
[Db]
dao = "mon_dao"
password_crypt_function = "1:sha1WithSalt"
password_salt = "votre_sel_ici"
Nouveau système de hachage ¶
Ce système proposé depuis Jelix 1.2.10/1.3.4/1.4.1 repose sur une nouvelle API
fournie par PHP 5.5, utilisant par défaut la méthode de hashage bcrypt. Un
équivalent pur PHP pour les versions antérieures existe et est fourni dans Jelix.
Il utilise la fonction crypt
.
La configuration est relativement simple, il faut deux paramètres dans la section
globale (en dehors des sections comme [Db]
) :
password_hash_method
: indique la méthode à utiliser. Une seule possible pour le moment, BCRYPT. Il faut donc mettre 1. Si vide ou 0, le nouveau système de hachage ne sera pas utilisépassword_hash_options
: une chaine contenant une suite de "cle=valeur;". Ces options dépendent du hachage utilisé. Pour BCRYPT, vous pouvez indiquer un "salt", et un nombre d'itération "cost".
Quelque soit la méthode utilisée, par défaut ce système génére un "salt" aléatoire à chaque fois que l'on veut stocker un nouveau mot de passe (ce qui est plus sécurisé que d'avoir le même salt pour tout les mots de passe), et ce salt est stocké en même temps que le mot de passe (d'où la nécessité d'avoir un champs de mot de passe d'une centaine de caractères).
Migration ¶
Si vous mettez à jour une application existante utilisant l'ancien système de hachage, et que vous voulez utiliser le nouveau système de hachage (ce qui est fortement recommandé !), vous devez :
- Lire l'avertissement un peu plus bas
- Agrandir le champs du mot de passe (
password
) en base de donnée à 120 caractères - Modifier le DAO correspondant (si vous n'utilisez pas le dao jelixuser de
jauthdb), pour indiquer cette nouvelle taille sur le champs
password
.
À chaque fois qu'un utilisateur s'identifiera ou changera son mot de passe, l'ancien hash généré avec l'ancien système de hachage sera remplacé par un nouveau hash. C'est pourquoi il faut, le temps de la transition, laisser la configuration de l'ancien système.
- *Attention : ne faites pas cette migration avec une base partagée** par différentes instances de votre application, qui n'ont pas encore migré vers cette nouvelle version. Les utilisateurs ne pourront plus s'identifier ! (le hash en base n'étant pas compréhensible par les versions précédentes). De ce fait, vous ne pourrez pas revenir en arrière à moins d'avoir fait une sauvegarde de la table des users.
Timeout ¶
L'option timeout
permet d'indiquer en minutes le temps d'inactivité au bout
duquel l'authentification ne sera plus valide. Si vous mettez 0
, il n'y a
pas de limite de temps. La session expirera à la fermeture du navigateur ou
à la limite indiquée dans le fichier php.ini.
Contrôler l'authentification pour chaque action ¶
Le plugin peut contrôler si l'action demandée a besoin d'une authentification ou
non. Avec l'option auth_required
dans le fichier INI, vous pouvez dire si
par défaut toutes les actions nécessitent une authentification (valeur « on »),
ou si par défaut, il n'y en a pas besoin (valeur « off »).
auth_required=on
Dans un cas comme dans l'autre, il faut pouvoir gérer les exceptions (par exemple, une action qui ne nécessite pas une authentification alors que par défaut toutes les actions le nécessitent). Les exceptions sont indiquées au niveau des contrôleurs, dans les paramètres de plugin.
class xxxCtrl extends jController {
public $pluginParams = array( ... );
}
Pour les actions concernées, vous indiquerez le paramètre auth.required
et
le mettrez à false
ou true
. Par exemple pour les actions index
et affiche
, il faut une authentification, alors que pour le reste des
actions du contrôleur (*
indique « toutes les actions »), ce n'est pas
utile :
class xxxCtrl extends jController {
public $pluginParams = array(
'*'=>array('auth.required'=>false),
'index'=>array('auth.required'=>true),
'affiche'=>array('auth.required'=>true),
);
}
Voir la page sur les plugins de coordinateurs pour mieux comprendre l'usage de $pluginParams.
Spécifier le comportement en cas d'echec d'authentification ¶
Si l'authentification n'est pas faite alors que l'action en nécessite une, le
plugin va alors agir en fonction de l'option on_error
.
Si vous mettez la valeur 1
, alors le plugin génèrera une erreur dont le
message (ou plutôt la clé de la locale du message) est dans l'option
error_message
.
Si par contre la valeur est 2
, alors le plugin exécutera l'action définie
dans l'option on_error_action
. Cela peut être une action d'un contrôleur du
module auth (comme c'est le cas par défaut), ou alors une action de votre propre
contrôleur dans un module tierce. Cette action en général affiche une page
demandant un login/mot de passe (mais cela peut être autre chose…)
Persistance de l'authentification ¶
jAuth propose un mécanisme de persistance d'authentification. C'est-à-dire la reconnaissance automatique de l'utilisateur quand il revient sur le site, même plusieurs jours après sa dernière visite (et donc après avoir perdu sa session PHP…). Cela se fait par le biais d'un cookie dans lequel sont stockées un certain nombre d'informations qui sont cryptées.
Vous avez pour cela deux paramètres important :
persistant_enable
: mettez le àon
pour activer la persistance de l'authentificationpersistant_encryption_key
: c'est un paramètre à renseigner obligatoirement. et qui l'est normalement par défaut depuis 1.6.8, généré de manière aléatoire lors de l'installation de l'application. Ce paramètre doit se trouver dans la sectioncoordplugin_auth
du fichier localconfig.ini.php ou liveconfig.ini.php (1.6.18+). La valeur de ce paramètre sert de clé de chiffrement pour les données stockées dans le cookie. Si vous changez de clé en cours de route, les cookies seront invalides et les utilisateurs ne sont pas reconnus. Ils devront s'authentifier à nouveau.
D'autres paramètres sont disponibles :
persistant_cookie_name
: indique le nom du cookie à utiliser. Par défaut :"jelixAuthentificationCookie"
.persistant_duration
: indique la durée en jour de la validité du cookie. Par défaut c'est une journée.persistant_cookie_path
: le chemin du cookie. Par défaut (vide), il vaut la valeur de « basePath » dans la config générale.
Utiliser le contrôleur par défaut, le module jauth ¶
Le module jauth propose des contrôleurs que vous pouvez utiliser pour gérer les
actions de connexion, de déconnexion, en faisant appel à la classe jAuth
.
Il propose aussi des zones et des templates.
Si vous voulez avoir des fonctionnalités de gestion de compte comme sur un portail, utilisez le module jCommunity, disponible en dehors de Jelix. Il propose des formulaires de changement de mot de passe, des formulaires de destruction de compte, de création de compte et de récupération de mot de passe.
Configuration classique ¶
Quand on utilise le module jauth, il est possible d'ajouter des options de
configuration propres au module. Par exemple, une configuration possible dans le
fichier auth.coord.ini.php
peut être celle-ci :
on_error_action = "jauth~login:out"
after_login = "myapp~default:index"
after_logout = "jauth~login:form"
on_error_sleep = 3
Le paramètre on_error_sleep
est le nombre de secondes d'attente quand
l'utilisateur a donné un mauvais mot de passe ou login (il n'est pas recommandé
de l'activer, car cela facilite les attaques de type DDOS). Pour
after_login
et after_logout
, voir plus bas.
À noter que vous pouvez surcharger les templates du module en créant vos propres
templates dans le dossier app/themes/default/jauth/
. Voir le système de thème.
Configuration de la redirection ¶
Dans la configuration du plugin, vous devez spécifier les paramètres
after_login
, after_logout
, et éventuellement les options
enable_after_login_override
et enable_after_logout_override
.
Les paramètres after_login
et after_logout
doivent contenir les
sélecteurs des actions vers lesquelles il faut rediriger une fois que
l'identification ou la déconnexion sont effectuées. Ils sont obligatoires.
Si vous ne les indiquez pas, vous allez avoir des redirections vers l'action
jauth~default:index
qui n'existe pas, donc une erreur…
Il est possible dans un formulaire d'authentification ou de déconnexion,
d'ajouter un paramètre caché contenant l'URL vers laquelle il faut rediriger.
Cela permet de rediriger vers une page différente en fonction de la page sur
laquelle on est quand on se connecte ou déconnecte. Dans ce cas, ce paramètre
caché doit se nommer « auth_url_return
», et doit contenir l'URL. Et vous
devez mettre les paramètres de configuration enable_after_login_override
et/ou enable_after_logout_override
à on
.
Configuration des URLS ¶
Le module jauth fourni un fichier d'urls. Si vous le souhaitez, vous pouvez
l'utiliser pour le mapping de vos urls, en le déclarant
dans votre fichier app/system/urls.xml
la ligne
<url pathinfo="/auth" module="jauth" include="urls.xml"/>
.
Utiliser son propre contrôleur ¶
Vous pouvez utiliser vos propres contrôleurs pour gérer l'authentification : formulaire d'identification, connexion, déconnexion. Vous ferez appel alors à la classe jAuth et ses méthodes statiques pour vérifier les identifiants/mots de passe, connecter et déconnecter un utilisateur.
Classe jAuth ¶
C'est la classe principale du système d'authentification. Toutes ses méthodes sont statiques. Elle permet de gérer un utilisateur, de « connecter » et « déconnecter » un utilisateur, etc. Vous appellerez ces méthodes quand bon vous semble, sachant que les contrôleurs du module jauth peuvent se charger pour vous d'une bonne partie du travail. Voir son descriptif dans la doc de référence.
l'objet "user" que vous passez à certaines méthodes vous est donné par
jAuth
lui même. C'est un objet contenant les données d'un utilisateur et
il n'a pas de classe précise : son type dépend du driver utilisé et
éventuellement de sa configuration (pour le driver Db, on peut fournir un DAO de
notre choix par exemple). Il doit par contre respecter l'interface attendue par
le driver, et doit avoir au moins un champ login
et un champ
password
.
jAuth n'a pas à être surchargée. Elle s'appuie sur des « pilotes » pour gérer les différents types d'authentification.
Connecter / Déconnecter un utilisateur ¶
Pour connecter et déconnecter un utilisateur, il faut utiliser les méthodes
login()
et logout()
:
// Connexion
$ok = jAuth::login('le_login', 'le_mot_de_passe_en_clair');
// deconnexion
jAuth::logout();
Vous pouvez aussi utiliser la méthode jAuth::setUserSession($login)
pour connecter
le user sans passer de mot de passe. Cela peut être utile si vous implémentez une
API web sans état, avec JWT par exemple.
À partir du moment où login()
a été appelé et a renvoyé true
, jAuth
stocke des informations sur l'utilisateur en session, qui peuvent être utilisées
par d'autres composants. Ces informations sont dans un objet, que vous récupérez
par getUserSession()
:
$user = jAuth::getUserSession();
La classe de cette objet dépend du driver utilisé. Pour le driver db, ça sera un record du dao indiqué dans la configuration de jAuth.
Vous pouvez à tout moment savoir si un utilisateur est identifié avec la méthode
isConnected()
:
if (jAuth::isConnected()) {
// ok, l'utilisateur est identifié
}
Pour authentifier l'utilisateur de manière persistante (il sera reconnu même
quand sa session sera détruite), ajoutez true
en troisième paramètre de
login()
.
Vous pouvez aussi simplement vérifier un login/mot de passe, sans connecter l'utilisateur qui correspond :
$ok = jAuth::verifyPassword('le_login', 'le_mot_de_passe_en_clair');
Créer un utilisateur ¶
Pour créer un utilisateur, il faut là aussi passer par jAuth. Vous devez d'abord lui demander de créer un objet qui contiendra les informations de l'utilisateur, et ensuite lui dire de l'enregistrer
// récupération d'un objet
$newUser = jAuth::createUserObject ('son_login', 'son_mot_de_passe_en_clair');
// ajout d'information si nécessaire, dépendant de l'application
$newUser->birthday = '1980-01-01';
// création de l'utilisateur par le driver
$ok = jAuth::saveNewUser($newUser);
Modifier un utilisateur ¶
Pour modifier les informations d'un utilisateur, vous devez récupérer l'objet qui correspond (cela peut être l'utilisateur courant), le modifier, et ensuite indiquer à jAuth de le sauver :
$user = jAuth::getUserSession()
// ou
$user = jAuth::getUser('son_login');
// exemple de modification
$user->birthday = '1980-01-02';
jAuth::updateUser($user);
Note : si l'utilisateur modifié est celui qui est actuellement connecté, les informations en sessions seront elles aussi modifiées.
N'utilisez pas ce processus pour modifier le mot de passe ! Car vous n'êtes pas
censé savoir comment le mot de passe est chiffré/stocké. Cela dépend de la
configuration de jAuth et du driver. Pour changer le mot de passe d'un
utilisateur, il faut utiliser les méthodes canChangePassword()
et changePassword()
.
La première permet de savoir si il est possible de changer le mot de passe. En
effet, certains moyens d'authentification ne le permettent pas, comme SAML, oAuth
etc, le mot de passe n'étant pas géré au sein de l'application.
if (jAuth::canChangePassword($login)) {
jAuth::changePassword($login, 'nouveau_mot_de_passe_en_clair');
}
else {
$reasonMessage = jAuth::getReasonToForbiddenPasswordChange();
}
La méthode getReasonToForbiddenPasswordChange
permet de récupérer la raison
de l'impossibilité de changer le mot de passe, afin d'en informer l'utilisateur (méthode existante depuis Jelix 1.7.11).
Vous pouvez utiliser jAuth::getRandomPassword()
pour générer un mot de
passe aléatoire.
Autres méthodes ¶
Pour supprimer un utilisateur, utilisez jAuth::removeUser()
:
jAuth::removeUser('son_login');
Pour récupérer la liste des utilisateurs, utilisez jAuth::getUserList()
:
$list = jAuth::getUserList();
Vous récupérez alors un iterateur que vous pouvez utiliser avec un foreach.
Chaque élément est un objet contenant les infos d'un utilisateur (comme avec
getUser()
)
Évènements ¶
Pour la plupart des méthodes de jAuth
, un évènement est émis. Cela permet
à des modules tiers d'être au courant des différentes actions
d'authentification, et donc de charger des données supplémentaires dans l'objet
user, ou de gérer les données dépendantes à l'utilisateur etc.
- AuthNewUser : indique qu'un utilisateur vient d'être ajouté
- AuthCanRemoveUser : demande si on peut supprimer l'utilisateur ou pas
- AuthRemoveUser : l'utilisateur a été supprimé
- AuthUpdateUser : l'utilisateur vient d'être mis à jour
- AuthCanLogin : demande si l'utilisateur peut se connecter
- AuthLogin : un utilisateur vient de se connecter
- AuthLogout : un utilisateur vient de se déconnecter
- AuthErrorLogin : indique une erreur d'authentification de l'utilisateur
- AuthBeforeLogin : permet d'effectuer des traitements spécifiques avant l'authentification de l'utilisateur
- AuthChangePassword (depuis Jelix 1.6.17): le mot de passe d'un utilisateur a changé.
Les réponses à certains évènements peuvent contenir les propriétés suivantes :
- AuthCanRemoveUser :
canremove
doit contenir true ou false - AuthCanLogin :
canlogin
doit contenir true ou false - AuthBeforeLogin :
processlogin
doit contenir true ou false (false pour annuler l'authentification)
function onAuthCanRemoveUser ($event)
{
$login = $event->getParam('login');
if($login == 'admin)
$ok = false;
else
$ok = true;
$event->Add(array('canremove'=>$ok));
}