Raccourcis : Contenu - rubriques - sous rubriques
EN FR
La page correspondant à la dernière version stable est consultable dans le Manuel Jelix 1.6

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'authentification
  • persistant_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));
}