Table des matières
CASsification de dotclear
Introduction
Ce micro-tuto à pour but de vous donnez les éléments clé qui m'ont permis de relier dotclear au serveur CAS.
Avant toute chose je vous signal que la version de dotclear que j'ai CASsifié est la 2.3.1, dont l'authentification était déjà basé sur un LDAP.
Une connexion en plusieurs temps
La connexion via un serveur CAS est dite en 'plusieurs temps' car il est question de plusieurs étapes (redirection vers le CAS, puis retour sur le service). C'est pourquoi il faut gardé en mémoire certaine informations durant ce processus, ce que phpCas fait à l'aide des sessions PHP.
Dotclear pas adapté
Dotclear n'est pas du tout adapté pour une connexion en plusieurs temps, car vous allez rencontrer des conflits de sessions entre la session initiée par phpCas et celle de dotclear, de plus dotclear va détruire la session d'une étape à un autre. Tout ceci résultant en des rédirections CAS ←—> dotclear infinies.
Nous allons mettre un place un système qui autorise la conservation de la session et utiliser les même sessions que dotclear pour éviter les conflits.
Comment fonctionnent les scripts de dotclear
Après pas mal de bidouille j'ai finis par comprendre comment fonctionnaient les scripts qui nous intéressent pour éviter les conflits de session et la destruction de session.
L'environnement d'exécution de dotclear est mis en place par les scripts preprend :
- /inc/preprend.php : utilisé sur toutes les pages, il lance $core qui va nous être utilise pour lancer une session de la même façon que dotclear.
- /inc/admin/prepend.php : utilisé sur les page d'admin, qui va donc vérifié si l'utilisateur est connecté, sinon il détruit la session et redirige vers la page de connexion auth.php
Nous allons donc modifier tout ces scripts.
Empêcher la destruction de la session
Durant la phase de login via le CAS il est nécessaire de conserver la session, nous allons donc modifier /inc/admin/preprend.php pour qu'il ne détruise pas la session si $_SESSION['keep'] vaut true. Pour se faire repérez la condition qui détruit la session (l 76 pour moi) :
elseif ($core->auth->sessionExists())
Pour y ajouter :
elseif ($core->auth->sessionExists() && $_SESSION['keep']!==true)
Nous utiliserons ensuite cette variable pour éviter la suppression de la session.
Ajout de CAS dans auth.php
Librairie phpCas
Vous devez bien-sûr télécharger la librairie phpCas : http://downloads.jasig.org/cas-clients/php/current/
Je l'ai ensuite mise dans le dossier /inc/libs/ de façon a avoir le dossier CAS et le fichier CAS.php dans ce dossier, pensez à adapter le require_once si vous avez choisis un autre dossier.
Principe de la modification
On va précéder à l'identification CAS en haut de script avant tout le reste en faisant attention à lancer la session comme dotclear via $core→session→start() disponible après un require de /inc/prepend.php.
Une fois l'utilisateur connecté, on va passer ses identifiants comme s'ils avaient étaient envoyé via le formulaire de connexion par la variable $_POST (ceci évitant de nombreux changement de variable). Vous noterez que nous n'avons pas le mot de passe en authentifiant via le CAS j'ai choisi de le remplacer par un simple 'casAuthenticated' car il vaut mieux avoir un mot de passe sinon dotclear risque de ne pas l'apprécier (encore une fois pas prévus pour du SSO !).
Puis on va modifier la class LDAP pour qu'elle accepte tout les utilisateur dont le mot de passe est bien 'casAuthenticated'. Je précise qu'une fois le CAS en place, on est obligé de se connecter via le CAS ceci ne crée donc pas une faille de sécurité.
Et enfin nous allons prendre en compte la déconnexion pour que quand l'utilisateur se déconnecte de dotclear il le soit aussi du CAS et revienne sur la page d'accueil de son blog, ceci est géré par /admin/index.php.
Le code !
On ajoute donc le blog suivant au début (à adapter en fonction de vos besoin et votre conf) :
<?php # -- BEGIN LICENSE BLOCK --------------------------------------- // .... blablabla .... # -- END LICENSE BLOCK ----------------------------------------- //##################### CAS - Authentication ############################################# require dirname(__FILE__).'/../inc/libs/CAS.php'; require dirname(__FILE__).'/../inc/prepend.php'; $core->session->start(); //Démarrage de la session de la même manière que dotclear //###################### Connexion via le CAS ############################# $_SESSION['keep']=true; phpCAS::client(CAS_VERSION_2_0,'cas.mdl29.net',443,'',false); //false indique que la session est déjà lancée phpCAS::setServerServiceValidateURL('https://cas.mdl29.net/serviceValidate'); phpCAS::setNoCasServerValidation(); phpCAS::forceAuthentication(); // On veux que l'utilisateur soit connecté //#################### Utilisateur est redirigé est forcément connecté ici # if(phpCAS::getUser()){ //Si réelement connecté, s'exécute tout le temps car forceAuthentication $_POST['user_id']=phpCAS::getUser(); $_POST['user_pwd']="casAuthenticated"; }else{ header("Location: auth.php");} //Ne doit en principe pas s'exécuter :) require dirname(__FILE__).'/../inc/admin/prepend.php'; //... la suite du code ?>
Enfin le dernier bout, la classe LDAP qui est normalement dans (cf tuto LDAP et dotclear) :
<?php class myDcAuth extends dcAuth { # L'utilisateur n'a pas le droit de changer son mot de passe protected $allow_pass_change = true; # 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); } # 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); # parmetre de configuration pour l'interface PHP pour administrer # notre annuaire LDAP $server = "ldap.mdl29"; $port = "389"; $racine = "dc=mdl29,dc=net"; #si ce n'est pas mdl29 alors athentification ldap #connection au serveur ldap $ds=@ldap_connect($server) or die("Could not connect to LDAP server."); ldap_set_option ($ds, LDAP_OPT_PROTOCOL_VERSION, 3); // @ devant ldap pour masquer les messages d'erreurs if ($pwd=="casAuthenticated" && @ldap_bind($ds)) { # 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 { $sr=ldap_search($ds,$racine,"cn=$user_id",array( "dn", "cn", "sn", "mail", "givenName")); $info = ldap_get_entries($ds, $sr); #on recherche l'utilisateur dans le ldap pour recuperer toutes les informations $sr=ldap_search($ds,$racine,"cn=$user_id",array( "dn", "cn", "sn", "mail", "givenName")); $info = ldap_get_entries($ds, $sr); #si le ldap ne ramene qu'un seul utilisateur if ($info["count"] ==1) { $cur->user_id = $info[0]['cn'][0]; $cur->user_email = $info[0]['mail'][0]; $cur->user_name = $info[0]['givenName'][0]; $cur->user_firstname = $info[0]['sn'][0]; $cur->user_lang = 'fr'; $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,$user_id,array('admin'=>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)); } # En cas d'erreur on annule la transaction et on renvoie "false" $this->con->rollback(); return false; } } ?>
J'ai utilisé un bind anonyme, plus simple
Plus que la déconnexion, dans admin/index.php remplacez la condition logout par la suivante :
# Logout if (!empty($_GET['logout'])) { $_SESSION['keep']=false; require dirname(__FILE__).'/../inc/libs/CAS.php'; phpCAS::client(CAS_VERSION_2_0,'cas.mdl29.net',443,'',false); $core->session->destroy(); if (isset($_COOKIE['dc_admin'])) { unset($_COOKIE['dc_admin']); setcookie('dc_admin',false,-600,'','',DC_ADMIN_SSL); } //http::redirect('auth.php'); phpCAS::logoutWithRedirectService((($_SERVER['HTTPS']=="on")? "https://" : "http://").$_SERVER['SERVER_NAME'].dirname($_SERVER['SCRIPT_NAME'])."/.."); exit; }
Normalement, c'est bon !!
Rédigé par Benjamin Bernard
Retour au sommaire principal : Central Authentification Service CAS