====== ShibbolethAuthenticatorComponent ======
===== Composant d'authentification Shibboleth =====
Ce composant permet de mettre en place facilement une authentification via le système [[http://shibboleth.internet2.edu|Shibboleth]] dans une application.
Il permet de définir facilement un **mapping entre les attributs fournis par Shibboleth et les propriétés d'un utilisateur**.
De plus, il est écrit de manière à ce que des besoins particuliers soient facilement mis en place, en écrivant son propre composant héritant du ShibbolethAuthenticatorComponent.
===== Exemple d'utilisation =====
class UsersController extends AppController {
(...)
var $components = array('Alaxos.ShibbolethAuthenticator');
function beforeFilter()
{
parent :: beforeFilter();
$this->ShibbolethAuthenticator->set_shibboleth_attribute_uid('Shib-SwissEP-UniqueID');
$this->AppShibbolethAuthenticator->add_attribute_mapping('Shib-InetOrgPerson-givenName', 'firstname', false); // do not update firstname when user logs in again
$this->AppShibbolethAuthenticator->add_attribute_mapping('Shib-Person-surname', 'lastname', false); // do not update lastname when user logs in again
$this->AppShibbolethAuthenticator->add_attribute_mapping('Shib-InetOrgPerson-mail', 'email'); // email is updated each time the user logs in
}
/*
* This URL must be protected by Shibboleth in Apache settings
*/
function shiblogin()
{
$authenticated = $this->AppShibbolethAuthenticator->authenticate();
if($this->AppShibbolethAuthenticator->is_new_user())
{
//do what you want here when a new user is created
}
else
{
//do what you want here when a user logs in again
}
}
}
===== Méthodes =====
**set_shibboleth_attribute_uid($shibboleth_attribute_uid)**
>Permet de spécifier le nom de l'attribut Shibboleth contenant l'identifiant unique de l'utilisateur.
**set_user_model_name($user_model_name)**
>Permet de spécifier le nom du Model utilisé pour stocker les utilisateurs. Par défaut: //User//
**set_external_uid_fieldname($external_uid_fieldname)**
>Permet de spécifier le nom du champ utilisé pour stocker l'identifiant unique Shibboleth. Par défaut: //external_uid//
**set_authentication_type_fieldname($authentication_type_fieldname)**
>Dans le cas où plusieurs systèmes de login existent dans l'application, permet d'indiquer le nom d'un champ contenant le type d'authentification de l'utilisateur. Par défaut: //authenticationtype_id//
**set_default_authentication_type_value($default_authentication_type_value)**
>Dans le cas où plusieurs systèmes de login existent dans l'application, permet d'indiquer la valeur du type d'authentification par défaut.
**set_create_new_user($create_new_user)**
>Permet d'indiquer si des utilisateurs qui n'existent pas dans l'application doivent être créés automatiquement. Defaut: //true//
**add_attribute_mapping($shibboleth_attribute_name, $user_property, $update_on_login = true)**
>Permet d'ajouter une correspondance entre un attribut Shibboleth et une propriété de l'utilisateur (le nom d'un champ dans la base de données).
Permet également d'indiquer si la valeur doit être mise à jour à chaque fois que l'utilisateur s'authentifie.
**add_callback_function($shibboleth_attribute_name, $callback_function)**
>Permet d'indiquer une fonction qui sera appelée lors de la récupération d'un attribut et qui doit retourner une valeur à utiliser pour l'attribut.
>Cela permet d'effectuer un traitement sur l'attribut lors de sa récupération.
Exemple:
class UsersController extends AppController {
(...)
/*
* uses a custom component inheriting from ShibbolethAuthenticatorComponent
*/
var $components = array('Alaxos.ShibbolethAuthenticator', 'AppShibbolethAuthenticator');
function beforeFilter()
{
$this->AppShibbolethAuthenticator->add_callback_function('Shib-Person-surname', array('AppShibbolethAuthenticatorComponent', 'upper_case'));
}
}
class AppShibbolethAuthenticatorComponent extends ShibbolethAuthenticatorComponent
{
public function upper_case($value)
{
return strtoupper($value);
}
}
**authenticate()**
>Méthode qui effectue l'authentification d'un utilisateur - déjà authentifié dans Shibboleth - dans l'application CakePHP
>En fonction des paramètres passés au préalable au composant, elle peut créer des nouveaux utilisateurs et mettre à jour les attributs des autres.
**is_new_user()**
>Retourne un boolean indiquant si l'utilisateur authentifié est un utilisateur qui vient d'être créé par le composant
**get_shibboleth_value($shibboleth_attribute)**
>Retourne la valeur d'un attribut Shibboleth d'un utilisateur authentifié
===== Créer son propre composant =====
Dans certains cas, une logique propre à l'application doit être mise en place lors du login Shibboleth.
Une manière simple est de créer son propre composant héritant de ShibbolethAuthenticatorComponent et de faire un override des méthodes nécessaires.
Certaines méthodes sont d'ailleurs écrites dans l'idée de pouvoir être overridées facilement.
**set_new_user_default_properties($user)**
>Un override de cette méthode permet d'écrire du code exécuté lors de la création d'un nouvel utilisateur
**log_user($user)**
>Un override de cette méthode permet d'écrire sa propre logique de login
class AppShibbolethAuthenticatorComponent extends ShibbolethAuthenticatorComponent
{
protected function set_new_user_default_properties($user)
{
$user = parent :: set_new_user_default_properties($user);
if(empty($user[$this->user_model_name]['prefered_language']))
{
$user[$this->user_model_name]['prefered_language'] = Configure :: read('language.default');
}
return $user;
}
protected function log_user($user)
{
/*
* Default code uses the Auth component to log users in
*
* Write your own login code here if for instance you don't use the Auth component
*/
$user_is_logged = false;
(...)
return $user_is_logged;
}
}
===== Remarque à propos de Shibboleth et la création de session CakePHP =====
CakePHP contient un élément de configuration qui concerne le niveau de sécurité global de l'application:
/*
* app/config/core.php
*/
Configure::write('Security.level', 'medium');
Un niveau de sécurité configuré à //medium// ou //high// a une influence sur la manière dont sont initialisées les sessions CakePHP.
En effet, dans ces deux cas, la directive PHP //[[http://www.php.net/manual/fr/session.configuration.php#ini.session.referer-check|session.referer_check]]// est configurée:
/*
* cake/libs/cake_session.php
*/
ini_set('session.referer_check', $this->host);
Cet appel implique que pour qu'un cookie de session soit reconnu, si le header //referer// est présent dans les requêtes HTTP,
celui-ci doit contenir la valeur du nom de domaine de l'application.
Or lors du processus d'authentification Shibboleth, il se peut que lors du retour vers l'URL utilisant le ShibbolethAuthenticatorComponent,
le header //referer// soit présent, mais contienne l'URL du serveur d'authentification (//Identity Provider//).
Dans ce cas, le cookie de session CakePHP n'est alors pas reconnu et les attributs de session initialisés par le Component sont alors perdus dès la requête HTTP suivante !
Heureusement, il existe un moyen de contourner le problème, tout en conservant le niveau de sécurité souhaité pour l'application.
La méthode //__initSession()// de la classe //CakeSession// est écrite de manière à supporter un éventuel fichier de configuration présent dans le dossier //app/config//.
Voici comment faire:
- Modifier le fichier //core.php//
//Configure::write('Session.save', 'php');
Configure::write('Session.save', 'session');
Dans le dossier //app/config//, créer le fichier //session.php// avec le contenu suivant:
// Revert value and get rid of the referrer check even when,
// Security.level is medium
ini_set('session.referer_check', ''); // -> no check of referer (which could be a problem with Shibboleth)
ini_set('session.use_trans_sid', 0);
ini_set('session.name', Configure :: read('Session.cookie'));
ini_set('session.cookie_lifetime', 0); // -> cookie destroyed when users close their browser
ini_set('session.cookie_path', $this->path);