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 géré par un serveur LDS/MDS, 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 repose sur un système de pilote. - 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 installmodule de jelix pour installer le module :
$ cd myapp/
$ php cmd.php installmodule jauth
Cela activera le module et le plugin, et creera un nouveau fichier
var/config/index/auth.coord.ini.php
, qui est la configuration du plugin et
du système d'authentification.
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, var/config/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.
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.3.4 (et 1.2.10, 1.4.1), il y a deux systèmes de hachage des mots de passe pour leur stockage. Jelix 1.3.4 et supérieur propose en effet une méthode plus sécurisée, utilisant l'API password de PHP 5.5 (une implémentation pure PHP est fournie dans Jelix pour les versions antérieures de PHP).
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.3.4.
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
. Pour utiliser ce nouveau système de
hachage, il est toutefois nécessaire d'avoir au moins PHP 5.3.7 (ou PHP 5.3.3
sur les serveurs Debian Squeeze à jour).
La configuration est relativement simple, il faut deux paramètres dans la section
globale (en dehors des sections [Db]
ou autre) :
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 vers Jelix 1.2.10/1.3.4/1.4.1 ou supérieur, et que vous voulez utiliser le nouve système de hachage, 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 (genres dev, integration etc), 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.
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 dont une partie est cryptée.
Vous avez pour cela deux paramètres important :
persistant_enable
: mettez le àon
pour activer la persistance de l'authentificationpersistant_crypt_key
: c'est un paramètre à renseigner obligatoirement.- *Vous devez** remplacer la valeur par défaut ! Ce paramètre doit contenir une chaîne quelconque de votre choix (plus de 10 lettres de préférence). Elle servira de clé de cryptage 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 (http://bitbucket.org/laurentj/jcommunity(..)). 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. 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 var/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 significants ¶
si vous utilisez le moteur d'urls significant, il vous faudra également ajouté
dans votre fichier var/config/urls.xml
la ligne <url pathinfo="/auth" module="jauth" include="urls.xml"/>
afin d'obtenir des urls propres au module.
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 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();
À 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 la méthode changePassword()
jAuth::changePassword('son_login', 'nouveau_mot_de_passe_en_clair');
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
Les tests sont sur les propriétés suivantes :
- AuthCanRemoveUser : canremove
- AuthCanLogin : canlogin
- AuthBeforeLogin : processlogin
function onAuthCanRemoveUser ($event)
{
$login = $event->getParam('login');
if($login == 'admin)
$ok = false;
else
$ok = true;
$event->Add(array('canremove'=>$ok));
}