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 :

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.

Pour les flemmards vous pouvez appliquer ce fichier patch.



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
?>
Pour les flemmards vous pouvez appliquer ce fichier patch.

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;
}
Pour les flemmards vous pouvez appliquer ce fichier patch.



Normalement, c'est bon !!








Rédigé par Benjamin Bernard
Retour au sommaire principal : Central Authentification Service CAS