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> | ||
| + | |||
| + | |||
| + | |||