Ci-dessous, les différences entre deux révisions de la page.
Prochaine révision | Révision précédente | ||
tips_informatiques:programmation:php:plugin_alaxos:components:shibbolethauthenticatorcomponent [2010/08/24 21:45] nico créée |
tips_informatiques:programmation:php:plugin_alaxos:components:shibbolethauthenticatorcomponent [2010/08/24 00:00] (Version actuelle) |
||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
====== ShibbolethAuthenticatorComponent ====== | ====== 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 ===== | ||
+ | |||
+ | |||
+ | <code php> | ||
+ | |||
+ | 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 | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ===== 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: | ||
+ | |||
+ | <code php> | ||
+ | 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); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | |||
+ | **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 | ||
+ | |||
+ | |||
+ | <code php> | ||
+ | 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; | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ===== 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: | ||
+ | |||
+ | <code php> | ||
+ | /* | ||
+ | * app/config/core.php | ||
+ | */ | ||
+ | |||
+ | Configure::write('Security.level', 'medium'); | ||
+ | </code> | ||
+ | |||
+ | 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: | ||
+ | |||
+ | <code php> | ||
+ | /* | ||
+ | * cake/libs/cake_session.php | ||
+ | */ | ||
+ | ini_set('session.referer_check', $this->host); | ||
+ | </code> | ||
+ | |||
+ | 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// | ||
+ | |||
+ | <code php> | ||
+ | //Configure::write('Session.save', 'php'); | ||
+ | Configure::write('Session.save', 'session'); | ||
+ | </code> | ||
+ | |||
+ | Dans le dossier //app/config//, créer le fichier //session.php// avec le contenu suivant: | ||
+ | |||
+ | <code php> | ||
+ | // 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); | ||
+ | </code> | ||
+ | |||
+ | |||
+ | |||