Raccourcis : Contenu - rubriques - sous rubriques
EN FR

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