source: spip-zone/_plugins_/authentification/openid/inc/openid.php @ 32340

Last change on this file since 32340 was 32340, checked in by cedric@…, 11 years ago

authentification openid fonctionnelle en 2.1
on change la signature de terminier_authentification_openid qui se contente de renvoyer une chaine d'erreur ou un tableau decrivant l'internaute identifie, charge a l'appelant d'en faire bon usage.
Cela casse le process en 2.0, reparation a suivre.

Une fonction verifier_openid permet de verifier qu'une url est valide en interrogeant le serveur.

File size: 14.7 KB
Line 
1<?php
2/**
3 * Plugin OpenID
4 * Licence GPL (c) 2007-2009 Edouard Lafargue, Mathieu Marcillaud, Cedric Morin, Fil
5 *
6 */
7
8@define('_OPENID_LOG', true);
9
10/**
11 * Ajout au formulaire de login
12 *
13 * @param string $texte
14 * @param array $contexte
15 * @return string
16 */
17function openid_login_form($texte,$contexte){
18        $scriptopenid = "";
19        if ($login = $contexte['var_login']
20        AND $openid = sql_getfetsel('openid','spip_auteurs','login='.sql_quote($login))
21        ) {
22                $openid = preg_replace(',^http://,i','',$openid);
23                $message = _T('openid:form_login_openid_ok')  // . $openid
24                . "<br />[<a href=\"#\" onclick=\"jQuery('.editer_login .explication').hide();jQuery('.editer_password').show();return false;\">"._T('openid:form_login_openid_pass')."</a>]";
25                $scriptopenid = "jQuery('#var_login').keyup(function(){
26                        if (jQuery(this).val()!='".addslashes($login)."') {
27                                jQuery('.editer_login .explication').hide();
28                                jQuery('.editer_password').show();
29                        } else {
30                                jQuery('.editer_login .explication').show();
31                        }
32                });";
33        }
34        else
35                $message = _T('openid:form_login_openid');
36
37        $texte .= "<style type='text/css'>"
38        ."input#var_login {width:10em;background-image : url(".find_in_path('images/login_auth_openid.gif').");background-repeat:no-repeat;background-position:center left;padding-left:18px;}\n"
39        ."input#password {width:10em;padding-right:18px;}\n"
40        .".explication {margin:5px 0;}"
41        ."</style>"
42        ."<script type='text/javascript'>"
43        ."jQuery(document).ready(function(){jQuery('input#var_login').after('<div class=\'explication\'>".addslashes($message)."</div>');"
44        .($scriptopenid?"if (!jQuery('.editer_password').is('.erreur')) jQuery('.editer_password').hide();":"")
45        ."$scriptopenid});"
46        ."</script>";
47        return $texte;
48}
49
50
51/**
52 * determine si un login est de type openid (une url avec http ou https)
53 * @param <type> $login
54 * @return <type>
55 */
56function is_openid($login){
57        // Detection s'il s'agit d'un URL à traiter comme un openID
58        // RFC3986 Regular expression for matching URIs
59        #if (preg_match('_^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?$_', $login, $uri_parts)
60        #       AND ($uri_parts[1] == "http" OR $uri_parts[1] == "https")) {
61
62        // s'il y a un point, c'est potentiellement un login openid
63        // ca permet d'eliminer un bon nombre de pseudos tout en
64        // autorisant les connexions openid sans avoir besoin de renseigner le http://
65        if (strpos($login, '.')!==false) {
66                return true;
67        } else {
68                return false;
69        }
70}
71
72/**
73 * Nettoyer et mettre en forme une url OpenID
74 *
75 * @param string $url_openid
76 * @return string
77 */
78function nettoyer_openid($url_openid){
79        include_spip('inc/filtres');
80        $url_openid = vider_url($url_openid, false);
81        $url_openid = rtrim($url_openid,'/');
82        // si pas de protocole et que ca ne semble pas un email style gmail,
83        // mettre http://
84        if ($url_openid  AND !preg_match(';^[a-z]{3,6}://;i',$url_openid ) AND strpos($url_openid,'@')===FALSE)
85                $url_openid = "http://".$url_openid;
86
87        // pas d'ancre dans une url openid !
88        // (Yahoo ajoute une ancre a l'url a son retour)
89        $url_openid = preg_replace(',#[^#]*$,','',$url_openid);
90
91        return $url_openid;
92}
93
94/**
95 * Verifier qu'une url OpenID est valide
96 *
97 * @param string $url_openid
98 */
99function verifier_openid($url_openid){
100        // Begin the OpenID authentication process.
101        $consumer = init_auth_openid();
102        openid_log("Initialisation faite", 3);
103        if ($auth_request = $consumer->begin($url_openid))
104                return true;
105        return false;
106}
107
108
109/**
110 * Logs pour openID, avec plusieurs niveaux pour le debug (1 a 3)
111 *
112 * @param mixed $data : contenu du log
113 * @param int(1) $niveau : niveau de complexite du log
114 * @return null
115**/
116function openid_log($data, $niveau=1){
117        if (!defined('_OPENID_LOG') OR _OPENID_LOG < $niveau) return;
118        spip_log('OpenID: '.$data, 'openid');
119}
120
121
122
123/**
124 * Initialisation de l'authent OpenID
125 *
126 * @return Auth_OpenID_Consumer
127 */
128function init_auth_openid() {
129        session_start();
130       
131        $cwd = getcwd();
132        //chdir(dirname(dirname(__FILE__)));
133        chdir(realpath(_DIR_OPENID_LIB));
134        require_once "Auth/OpenID/Consumer.php";
135        require_once "Auth/OpenID/FileStore.php";
136        require_once "Auth/OpenID/SReg.php"; // Require the Simple Registration extension API.
137        chdir($cwd);
138
139        /****
140         * Répertoire temporaire où auth_openid stocke ses données
141         * afin de suivre les sessions.
142         ****/
143
144        $store = new Auth_OpenID_FileStore(sous_repertoire(_DIR_TMP, 'auth_openid'));
145
146        /**
147         * Create a consumer object using the store object created earlier.
148         */
149        return new Auth_OpenID_Consumer($store);
150}
151
152
153/**
154 * Lancer une demande d'auth par OpenID
155 * consiste a verifier que l'url est legitime,
156 * et a rediriger vers le serveur OpenID,
157 * qui renverra sur l'url $retour apres identification
158 *
159 * Si tout se passe bien, la fonction quitte par une redirection+exit
160 * En cas d'echec, la fonction renvoie une erreur
161 *
162 * @param string $url_openid
163 * @param string $retour
164 * @return string
165 */
166function demander_authentification_openid($url_openid, $retour){
167        openid_log("Traitement login OpenID pour $url_openid",2);
168
169        // Begin the OpenID authentication process.
170        $consumer = init_auth_openid();
171        openid_log("Initialisation faite", 3);
172        $auth_request = $consumer->begin($url_openid);
173
174        // Handle failure status return values.
175        if (!$auth_request) {
176                // ici, on peut rentrer dire que l'openid n'est pas connu...
177                // plutot que de rediriger et passer la main a d'autres methodes d'auth
178                openid_log("Ce login ($url_openid) n'est pas connu", 2);
179                return _T('openid:erreur_openid');
180        } 
181       
182        // l'openid donne est connu. On va donc envoyer une redirection
183        // mais celle ci est differente selon la version de openid
184        //
185        // Dans les 2 cas, deux parametres doivent etre donnes
186        // - une url de confiance, ici l'adresse du site : url_de_base()
187        // - une url de redirection, sur laquelle OPENID reviendra une fois l'authentification faite (réussie ou non)
188        else {
189                openid_log("Le login $url_openid existe", 2);
190                // argument de redirection : cette url doit etre identique
191                // ici et au retour (au moins le premier parametre de l'url)
192                // sinon le script openid n'est pas content
193                // On peut neanmoins passer des informations supplementaires
194                // nous indiquons ici une autre redirection encore, celle de l'url
195                // vers laquelle le bonhomme souhaite aller (url=$cible)
196               
197                openid_log("Adresse de retour : $retour", 2);
198                // on demande quelques informations, dont le login obligatoire
199                if ($sreg_request = Auth_OpenID_SRegRequest::build(
200                                array('nickname'), // Required
201                                array('fullname', 'email')) // Optional
202                ) {
203                        openid_log("Ajout des extensions demandees", 3);
204                $auth_request->addExtension($sreg_request);
205                }
206
207                $erreur = "";
208               
209                // OPENID 1
210                if ($auth_request->shouldSendRedirect()) {
211                        openid_log("Redirection pour version 1 d'OpenID", 3);
212                        // Redirect the user to the OpenID server for authentication.  Store
213                        // the token for this authentication so we can verify the response.
214                        $redirect = $auth_request->redirectURL(url_de_base(), $retour);         
215                        openid_log("Redirection vers : $redirect", 3);
216                       
217                        // If the redirect URL can't be built, display an error message.
218                        if (Auth_OpenID::isFailure($redirect)) {
219                                openid_log("Erreur sur l'adresse de redirection : $redirect", 2);
220                                $erreur = openid_url_erreur(_L("Could not redirect to server: " . $redirect->message), $cible);
221                        }
222                        // pas d'erreur : redirection par entete
223                        else {
224                                openid_log("Redirection par entete", 3);
225                                include_spip('inc/headers');
226                                #redirige_par_entete($redirect);
227                                echo redirige_formulaire($redirect);
228                                exit;
229                        }
230                }
231               
232                // OPENID 2
233                // use a Javascript form to send a POST request to the server.
234                else {
235                        openid_log("Redirection pour version 2 d'OpenID", 3);
236                        // Generate form markup and render it.
237                        $form_id = 'openid_message';
238                        $form_html = $auth_request->formMarkup(url_de_base(), $retour, false, array('id' => $form_id));
239                        openid_log("Redirection par formulaire : $form_html", 3);
240                        // Display an error if the form markup couldn't be generated;
241                        // otherwise, render the HTML.
242                        if (Auth_OpenID::isFailure($form_html)) {
243                                openid_log("Erreur sur le formulaire de redirection : $form_html", 2);
244                                $erreur = openid_url_erreur(_L("Could not redirect to server: " . $form_html->message), $cible);
245                        } 
246                       
247                        // pas d'erreur : affichage du formulaire et arret du script
248                        else {
249                                openid_log("Affichage du formulaire de redirection", 3);
250                                $page_contents = array(
251                                   "<html><head><title>",
252                                   "OpenID transaction in progress",
253                                   "</title></head>",
254                                   "<body onload='document.getElementById(\"".$form_id."\").submit()'>",
255                                   $form_html,
256                                   "</body></html>");
257                                echo implode("\n", $page_contents);
258                                exit;
259                        }
260                }
261
262        }       
263       
264        if ($erreur) {
265                openid_log("Rentrer avec l'erreur", 3);
266                return $erreur;
267        }
268       
269}
270
271
272/**
273 * Finir l'authentification apres le retour depuis le serveur openID
274 * analyse le retour de la requete openID
275 * utilise l'url de retour pour verifier la demande
276 * renvoie une chaine d'erreur en cas d'erreur
277 * un tableau decrivant l'utilisateur en cas de succes
278 *
279 * @param string $retour
280 * @return mixed
281 */
282function terminer_authentification_openid($retour){
283        openid_log("Retour du fournisseur OpenId", 2);
284       
285        // Complete the authentication process using the server's response.
286        $consumer = init_auth_openid();
287        openid_log("Initialisation faite. analyse de la reponse rendue", 2);
288        $response = $consumer->complete($retour);
289
290        // Authentification annulee par l'utilisateur
291        if ($response->status == Auth_OpenID_CANCEL) {
292                openid_log("Processus annule par l'utilisateur", 2);
293                return _T('openid:verif_refusee');
294        } 
295       
296        // Authentification echouee
297        elseif ($response->status == Auth_OpenID_FAILURE) {
298                openid_log("Echec de l'authentification chez le fournisseur", 2);
299          return _L("Authentication failed: " . $response->message);
300        } 
301       
302        // Authentification reussie
303        elseif ($response->status == Auth_OpenID_SUCCESS) {
304               
305                $openid = nettoyer_openid($response->identity_url); // pas de / final dans l'openid
306               
307                openid_log("Succes de l'authentification $openid chez le fournisseur d'identification", 1);
308                // recuperer login, nom, email
309                $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
310                $sreg = $sreg_resp->contents();
311                $identite = array(
312                        'login' => isset($sreg['nickname']) ? $sreg['nickname'] : '',
313                        'email' => isset($sreg['email']) ? $sreg['email'] : '',
314                        // login a defaut du nom, sinon c'est 'Nouvel auteur' qui est enregistre
315                        'nom' => isset($sreg['fullname']) ? $sreg['fullname'] : $sreg['nickname'],
316                        'openid' => $openid
317                );
318                return $identite;
319        }
320        return false;
321}
322/*
323                        #openid_log("sreg ".var_export($sreg_resp,true), 2);
324
325                        // on ajoute un auteur uniquement si les inscriptions sont autorisees sur le site
326                        if ($GLOBALS['meta']['accepter_inscriptions']=='oui') {
327                               
328                                openid_log("Tenter d'ajouter '$openid' dans SPIP");
329                                // verifier qu'on a les infos necessaires
330                                if (!$ok = ($couples['login'] AND $couples['email'])) {
331                                        openid_log("Les informations transmises ne sont pas suffisantes : il manque le login et/ou l'email pour $openid.");
332                                        $redirect = openid_url_erreur(_L("Inscription impossible : login ou email non renvoy&eacute;"), $cible);
333                                }
334                                // ajouter l'auteur si le login propose n'existe pas deja
335                                elseif (!$ok = openid_ajouter_auteur($couples)) {
336                                        openid_log("Inscription impossible de '$openid' car un login ($couples[login]) existe deja dans SPIP");
337                                        $redirect = openid_url_erreur(_L("Inscription impossible : un login identique existe deja"), $cible);
338                                }
339                                // verifier que l'insertion s'est bien deroulee
340                                else {
341                                        if (($ok = $identifier_login($openid, "")) && $cible){                                 
342                                                openid_log("Inscription de '$openid' dans SPIP OK", 3);
343                                                $cible = parametre_url($cible,'message_ok',_L('openid:Vous &ecirc;tes maintenant inscrit et identifi&eacute; sur le site. Merci.'),'&');
344                                        } else {
345                                                openid_log("Echec de l'ajout de '$openid' dans SPIP", 3);
346                                        }
347                                }
348                        }
349                        // rediriger si pas inscrit
350                        if (!$ok && !$redirect) {
351                                $redirect = openid_url_erreur(_L("Utilisateur OpenID inconnu dans le site)"), $cible);
352                        }
353                }
354               
355                // sinon, c'est on est habilite ;)
356                if ($ok) {
357                        openid_log("Utilisateur '$openid' connu dans SPIP, on l'authentifie", 3);
358                       
359                        // creer la session
360                                $session = charger_fonction('session', 'inc');
361                                $session($auteur);
362                                $p = ($auteur['prefs']) ? unserialize($auteur['prefs']) : array();
363                                $p['cnx'] = ($session_remember == 'oui') ? 'perma' : '';
364                                $p = array('prefs' => serialize($p));
365                                sql_updateq('spip_auteurs', $p, "id_auteur=" . $auteur['id_auteur']);
366                                //  bloquer ici le visiteur qui tente d'abuser de ses droits
367                                verifier_visiteur();                   
368                       
369                        ## Cette partie est identique
370                        ## a formulaire_login_traiter
371                        #$auth = charger_fonction('auth','inc');
372                        #$auth();
373
374                        // Si on se connecte dans l'espace prive,
375                        // ajouter "bonjour" (repere a peu pres les cookies desactives)
376                        if (openid_is_url_prive($cible)) {
377                                $cible = parametre_url($cible, 'bonjour', 'oui', '&');
378                        }
379                        if ($cible) {
380                                $cible = parametre_url($cible, 'var_login', '', '&');
381                        }
382                       
383                        // transformer la cible absolue en cible relative
384                        // pour pas echouer quand la meta adresse_site est foireuse
385                        if (strncmp($cible,$u = url_de_base(),strlen($u))==0){
386                                $cible = "./".substr($cible,strlen($u));
387                        }
388               
389                        // Si on est admin, poser le cookie de correspondance
390                        if ($GLOBALS['auteur_session']['statut'] == '0minirezo') {
391                                include_spip('inc/cookie');
392                                spip_setcookie('spip_admin', '@'.$GLOBALS['auteur_session']['login'],
393                                time() + 7 * 24 * 3600);
394                        }
395                        ## /fin identique
396                }
397        }
398       
399        include_spip('inc/headers');
400        redirige_par_entete($redirect?$redirect:$cible);       
401}
402*/
403
404function openid_url_reception(){
405        include_spip('inc/filtres');
406        return url_absolue(generer_url_action("controler_openid"));
407}
408
409function openid_url_erreur($message, $cible=''){
410        openid_log($message);
411        if ($cible)
412                $ret = $cible;
413        else
414                $ret = generer_url_public("login","url=".$redirect,'&'); // $redirect pas defini ici ..
415        return parametre_url($ret, "var_erreur", urlencode($message),'&');
416}
417
418function openid_is_url_prive($cible){
419        $parse = parse_url($cible);
420        return strncmp(substr($parse['path'],-strlen(_DIR_RESTREINT_ABS)), _DIR_RESTREINT_ABS, strlen(_DIR_RESTREINT_ABS))==0; 
421}
422
423function openid_ajouter_auteur($couples){
424        $statut = ($GLOBALS['openid_statut_nouvel_auteur'] 
425                        ? $GLOBALS['openid_statut_nouvel_auteur'] 
426                        : '1comite');
427                       
428        include_spip('base/abstract_sql');
429        // si un utilisateur possede le meme login, on ne continue pas
430        // sinon on risque de perdre l'integrite de la table
431        // (pour le moment, on suppose dans la table spip_auteurs
432        // qu'un login ou qu'un opentid est unique)
433        if (sql_getfetsel('id_auteur','spip_auteurs','login='.sql_quote($couples['login']))) {
434                return false;
435        }
436        $id_auteur = sql_insertq("spip_auteurs", array('statut' => $statut));
437        openid_log("Creation de l'auteur '$id_auteur' pour $couples[login]", 3);
438        include_spip('inc/modifier');
439        revision_auteur($id_auteur, $couples);
440       
441        return true;
442}
443
444?>
Note: See TracBrowser for help on using the repository browser.