====== Authentification externe ====== Dotclear 2 stocke par défaut les utilisateurs et leurs mots de passe dans sa propre base de données. Le processus d'authentification passe donc tout naturellement par là. Ceci dit, il peut être utile d'accéder à une autre source de données pour procéder à l'authentification. Nous allons voir que Dotclear 2 le permet assez facilement. ===== Préambule ===== Dotclear 2 permet de spécifier dans sa configuration un service définissant le nom de la classe qui sera utilisée pour le processus d'authentification. ===== Une nouvelle classe d'authentification ===== Au même niveau que notre fichier de configuration, nous allons créer un fichier nommé **MyAuth.php** qui contiendra tout simplement le code suivant : namespace Myself; use Dotclear\Core\Auth; class MyAuth extends Auth { } Enfin, dans le fichier de configuration de Dotclear, nous ajoutons ces lignes à la fin : Autoloader::me()->addNamespace('Myself', __DIR__); \Dotclear\Helper\Container\Factories::addService( 'core', Dotclear\Interface\Core\AuthInterface::class, Myself\MyAuth::class ); À partir de la version 2.32 de Dotclear il sera plus simple d'ajouter plutôt ces lignes (la 2e change) : Autoloader::me()->addNamespace('Myself', __DIR__); define('DC_AUTH_CLASS', Myself\MyAuth::class); À ce stade, notre installation de Dotclear doit continuer à fonctionner. Pour l'instant nous avons simplement changé la classe d'authentification et comme notre nouvelle classe ne fait rien, rien n'a changé. La classe d'authentification doit impérativement hériter de **Dotclear\Core\Auth** pour être utilisée. ===== Scénario ===== Dans le cadre de ces explications, nous allons partir du principe que nous disposons d'un service web XML-RPC qui permet de vérifier la validité d'un identifiant et de son mot de passe et d'obtenir des informations sur l'utilisateur. Voici les spécifications de notre service Web d'authentification fictif. L'URL du service est **%%http://example.com/auth%%** et il possède une seule méthode **auth.login**. Cette méthode prend deux paramètres : une chaîne **login** pour l'identifiant de l'utilisateur et une chaîne **password** pour le mot de passe. Elle renvoie un **tableau** contenant les informations sur l'utilisateur ou provoque une erreur XML-RPC en cas d'erreur d'identifiant et/ou de mot de passe. Enfin, nous allons partir du principe que notre installation ne contient qu'un seul blog dont l'identifiant est **default**. ===== Application ===== Dans le cadre de notre service d'authentification, nous devons nous intéresser à la méthode **checkUser** de Dotclear\Core\Auth puisque c'est là que tout se passe. Cette méthode est appelée de différente manière par Dotclear. Elle peut être appelée avec uniquement l'identifiant de l'utilisateur. Ceci permet d'initialiser les informations dans la classe. Elle peut être appelée avec l'identifiant et un mot de passe. Ceci permet de vérifier le mot de passe en plus d'initialiser l'utilisateur. Enfin, elle peut être appelée avec un identifiant, un mot de passe de valeur **null** et une clé de vérification. Ceci permet de valider la session de l'utilisateur et de l'initialiser à l'aide d'une clé. Voici comment nous allons procéder : * Si la méthode **checkUser** est appelée sans mot de passe, nous passons la main à la méthode parente. * Si la méthode **checkUser** est appelée avec un mot de passe, nous vérifions la validité de celui-ci puis créons ou mettons à jour l'utilisateur dans la base de données et enfin, passons la main à la méthode parent sans mot de passe. On notera que **l'utilisateur doit exister dans la base de données** pour des raisons d'intégrité référentielle. En effet, il est nécessaire de pouvoir associer des billets (entre autre) à tel ou tel utilisateur. Il est également nécessaire de stocker le mot de passe de l'utilisateur dans la base de données de Dotclear car certaines opérations en ont besoin. Ceci étant, il est possible d'interdire le changement de mot de passe par l'utilisateur. Voici donc maintenant le code commenté de notre nouvelle classe d'authentification : namespace Myself; class MyAuth extends Dotclear\Core\Auth { # L'utilisateur n'a pas le droit de changer son mot de passe protected $allow_pass_change = false; # La méthode de vérification du mot de passe public function checkUser($user_id, $pwd=null, $user_key=null) { # Pas de mot de passe, on appelle la méthode parente. if ($pwd == '') { return parent::checkUser($user_id,null,$user_key); } # Si un mot de passe a été donné, nous allons le vérifier avec la # méthode auth.login XML-RPC. try { # On démarre une transaction et on ouvre un curseur sur la # table utilisateur de Dotclear pour créer ou modifier # l'utilisateur. $this->con->begin(); $cur = $this->con->openCursor($this->user_table); # On appelle la méthode de vérification du mot de passe. # En cas d'erreur le processus s'arrête là et provoque # une exception. $client = new xmlrpcClient('http://example.com/auth'); $info = $client->query('auth.login',$user_id,$pwd); # On définit le mot de passe, il est inséré dans tous les cas. $cur->user_pwd = $pwd; # Si l'utilisateur existe, nous allons uniquement mettre à jour # son mot de passe dans la table utilisateur de Dotclear. if ($this->core->userExists($user_id)) { $this->sudo(array($this->core,'updUser'),$user_id,$cur); $this->con->commit(); } # Si l'utilisateur n'existe pas, nous allons le créer. # Afin qu'il puisse se connecter, il est nécessaire de lui donner # au moins une permission "usage" sur le blog "default". else { $cur->user_id = $info['login']; $cur->user_email = $info['email']; $cur->user_name = $info['name']; $cur->user_firstname = $info['firstname']; $cur->user_lang = $info['lang'] ? $info['lang'] : 'en'; $cur->user_tz = 'Europe/Paris'; $cur->user_default_blog = 'default'; $this->sudo(array($this->core,'addUser'),$cur); $this->sudo(array($this->core,'setUserBlogPermissions'), $user_id,'default',array('usage'=>true)); $this->con->commit(); } # Les opérations précédentes se sont déroulées sans erreur, nous # pouvons maintenant appeler la méthode parente afin d'initialiser # l'utilisateur dans l'object $core->auth return parent::checkUser($user_id,$pwd); } catch (Exception $e) { # En cas d'erreur on annule la transaction et on renvoie "false" $this->con->rollback(); return false; } } } On notera l'utilisation de la propriété **allow_pass_change** qui permet d'interdire le changement de mot de passe par l'utilisateur. Comme on peut le voir, le processus est assez simple à mettre en place. Quelques remarques maintenant. * Il est indispensable de stocker le mot de passe de l'utilisateur dans la table utilisateur de Dotclear car celui-ci peut en avoir besoin pour certaines opérations * Il est bien sûr possible de donner des paramètres à ce code, comme par exemple, le blog et les permissions qui seront assignés à l'utilisateur s'il n'existe pas encore. * Vous pouvez créer des méthodes **afterAddUser**, **afterUpdUser** et **afterDelUser** dans votre classe d'authentification. Ces méthodes sont appelées respectivement après la création, la mise à jour ou la suppression d'un utilisateur. Cet exemple simple d'authentification montre ce qu'il est possible de faire. Vous pouvez ainsi authentifier un utilisateur depuis n'importe quelle source telle qu'un serveur LDAP, la table utilisateur d'un forum, ou n'importe quoi acceptant un identifiant et un mot de passe. Enfin, la class Auth permet de réaliser une véritable authentification unique de type SSO par ces fonctions de vérification de session et de changement du formulaire d'authentification.