[SPIP] ~2.1.12 -->2.1.25
[velocampus/web/www.git] / www / ecrire / inc / auth.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2014 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 if (!defined('_ECRIRE_INC_VERSION')) return;
14
15 include_spip('base/abstract_sql');
16 //
17 // Fonctions de gestion de l'acces restreint aux rubriques
18 //
19
20 // http://doc.spip.org/@acces_restreint_rubrique
21 function acces_restreint_rubrique($id_rubrique) {
22 global $connect_id_rubrique;
23
24 return (isset($connect_id_rubrique[$id_rubrique]));
25 }
26
27 // http://doc.spip.org/@auteurs_article
28 function auteurs_article($id_article, $cond='')
29 {
30 return sql_allfetsel("id_auteur", "spip_auteurs_articles", "id_article=$id_article". ($cond ? " AND $cond" : ''));
31 }
32
33 // http://doc.spip.org/@auteurs_autorises
34 function auteurs_autorises($in, $cond='')
35 {
36 return sql_in("statut", array('0minirezo','1comite'))
37 . (!$cond ? '' : " AND $cond")
38 . (!$in ? '' : (" AND ". sql_in("id_auteur", $in, 'NOT')));
39 }
40
41 // Un nouvel inscrit prend son statut definitif a la 1ere connexion.
42 // Le statut a ete memorise dans bio (cf formulaire_inscription).
43 // On le verifie, car la config a peut-etre change depuis,
44 // et pour compatibilite avec les anciennes versions n'utilisait pas "bio".
45
46 // http://doc.spip.org/@acces_statut
47 function acces_statut($id_auteur, $statut, $bio)
48 {
49 if ($statut != 'nouveau') return $statut;
50 include_spip('inc/filtres');
51 include_spip('inc/autoriser');
52 if (!autoriser('inscrireauteur', $bio)) return $statut; //i.e. "nouveau"
53 include_spip('action/editer_auteur');
54 instituer_auteur($id_auteur,array('statut'=> $bio));
55 include_spip('inc/modifier');
56 revision_auteur($id_auteur, array('bio'=>''));
57 include_spip('inc/session');
58 session_set('statut',$bio);
59 return $bio;
60 }
61
62 // Fonction d'authentification. Retourne:
63 // - URL de connexion si on ne sait rien (pas de cookie, pas Auth_user);
64 // - un tableau si visiteur sans droit (tableau = sa ligne SQL)
65 // - code numerique d'erreur SQL
66 // - une chaine vide si autorisation a penetrer dans l'espace prive.
67
68 // http://doc.spip.org/@inc_auth_dist
69 function inc_auth_dist() {
70
71 global $connect_login ;
72
73 $row = auth_mode();
74
75 if ($row) return auth_init_droits($row);
76
77 if (!$connect_login) return auth_a_loger();
78
79 // Cas ou l'auteur a ete identifie mais on n'a pas d'info sur lui
80 // C'est soit parce que la base est inutilisable,
81 // soit parce que la table des auteurs a changee (restauration etc)
82 // Pas la peine d'insister.
83 // Renvoyer le nom fautif et une URL de remise a zero
84
85 if (spip_connect())
86 return array('login' => $connect_login,
87 'site' => generer_url_public('', "action=logout&amp;logout=prive"));
88
89 $n = intval(sql_errno());
90 spip_log("Erreur base de donnees $n " . sql_error());
91 return $n ? $n : 1;
92 }
93
94 // fonction appliquee par ecrire/index sur le resultat de la precedente
95 // en cas de refus de connexion.
96 // Retourne un message a afficher ou redirige illico.
97
98 function auth_echec($raison)
99 {
100 include_spip('inc/minipres');
101 include_spip('inc/headers');
102 // pas authentifie. Pourquoi ?
103 if (is_string($raison)) {
104 // redirection vers une page d'authentification
105 // on ne revient pas de cette fonction
106 // sauf si pb de header
107 $raison = redirige_formulaire($raison);
108 } elseif (is_int($raison)) {
109 // erreur SQL a afficher
110 $raison = minipres(_T('info_travaux_titre'), _T('titre_probleme_technique'). "<p><tt>".sql_errno()." ".sql_error()."</tt></p>");
111 } elseif (@$raison['statut']) {
112 // un simple visiteur n'a pas acces a l'espace prive
113 spip_log("connexion refusee a " . @$raison['id_auteur']);
114 $raison = minipres(_T('avis_erreur_connexion'),_T('avis_erreur_visiteur'));
115 } else {
116 // auteur en fin de droits ...
117 $h = $raison['site'];
118 $raison = minipres(_T('avis_erreur_connexion'),
119 "<br /><br /><p>"
120 . _T('texte_inc_auth_1',
121 array('auth_login' => $raison['login']))
122 . " <a href='$h'>"
123 . _T('texte_inc_auth_2')
124 . "</a>"
125 . _T('texte_inc_auth_3'));
126 }
127 return $raison;
128 }
129
130 // Retourne la description d'un authentifie par cookie ou http_auth
131 // Et affecte la globale $connect_login
132
133 function auth_mode()
134 {
135 global $auth_can_disconnect, $ignore_auth_http, $ignore_remote_user;
136 global $connect_login ;
137
138 //
139 // Initialiser variables (eviter hacks par URL)
140 //
141
142 $connect_login = '';
143 $id_auteur = NULL;
144 $auth_can_disconnect = false;
145
146 //
147 // Recuperer les donnees d'identification
148 //
149
150 // Session valide en cours ?
151 if (isset($_COOKIE['spip_session'])) {
152 $session = charger_fonction('session', 'inc');
153 if ($id_auteur = $session()
154 OR $id_auteur===0 // reprise sur restauration
155 ) {
156 $auth_can_disconnect = true;
157 $connect_login = $GLOBALS['visiteur_session']['login'];
158 } else unset($_COOKIE['spip_session']);
159 }
160
161 // Essayer auth http si significatif
162 // (ignorer les login d'intranet independants de spip)
163 if (!$ignore_auth_http) {
164 if (
165 (isset($_SERVER['PHP_AUTH_USER']) AND isset($_SERVER['PHP_AUTH_PW'])
166 AND $r = lire_php_auth($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']))
167 OR
168 // Si auth http differtente de basic, PHP_AUTH_PW
169 // est indisponible mais tentons quand meme pour
170 // autocreation via LDAP
171 (isset($_SERVER['REMOTE_USER'])
172 AND $r = lire_php_auth($_SERVER['PHP_AUTH_USER'] = $_SERVER['REMOTE_USER'], ''))
173 ) {
174 if (!$id_auteur) {
175 $_SERVER['PHP_AUTH_PW'] = '';
176 $auth_can_disconnect = true;
177 $GLOBALS['visiteur_session'] = $r;
178 $connect_login = $GLOBALS['visiteur_session']['login'];
179 } else {
180 // cas de la session en plus de PHP_AUTH
181 /* if ($id_auteur != $r['id_auteur']){
182 spip_log("vol de session $id_auteur" . join(', ', $r));
183 unset($_COOKIE['spip_session']);
184 $id_auteur = '';
185 } */
186 }
187 }
188 // Authentification .htaccess old style, car .htaccess semble
189 // souvent definir *aussi* PHP_AUTH_USER et PHP_AUTH_PW
190 else if (isset($_SERVER['REMOTE_USER']))
191 $connect_login = $_SERVER['REMOTE_USER'];
192 }
193
194 $where = (is_numeric($id_auteur)
195 /*AND $id_auteur>0*/ // reprise lors des restaurations
196 ) ?
197 "id_auteur=$id_auteur" :
198 (!strlen($connect_login) ? '' : "login=" . sql_quote($connect_login));
199
200 if (!$where) return '';
201
202 // Trouver les autres infos dans la table auteurs.
203 // le champ 'quand' est utilise par l'agenda
204
205 return sql_fetsel("*, en_ligne AS quand", "spip_auteurs", "$where AND statut!='5poubelle'");
206 }
207
208 //
209 // Init des globales pour tout l'espace prive si visiteur connu
210 // Le tableau global visiteur_session contient toutes les infos pertinentes et
211 // a jour (tandis que $visiteur_session peut avoir des valeurs un peu datees
212 // s'il est pris dans le fichier de session)
213 // Les plus utiles sont aussi dans les variables simples ci-dessus
214 // si la globale est vide ce n'est pas un tableau, on la force pour empecher un warning
215
216 function auth_init_droits($row)
217 {
218 global $connect_statut, $connect_toutes_rubriques, $connect_id_rubrique, $connect_login, $connect_id_auteur;
219
220 $connect_id_auteur = $row['id_auteur'];
221 $connect_login = $row['login'];
222 $connect_statut = acces_statut($connect_id_auteur, $row['statut'], $row['bio']);
223
224 // on force l'Ă©criture de cette info dans le fichier de session
225 // pour pouvoir récupérer #SESSION{en_ligne} dans les squelettes
226 session_set('en_ligne', $row['en_ligne']);
227
228 $GLOBALS['visiteur_session'] = array_merge((array)$GLOBALS['visiteur_session'], $row);
229 $r = @unserialize($row['prefs']);
230 $GLOBALS['visiteur_session']['prefs'] =
231 (@isset($r['couleur'])) ? $r : array('couleur' =>1, 'display'=>0);
232
233 // au cas ou : ne pas memoriser les champs sensibles
234 unset($GLOBALS['visiteur_session']['pass']);
235 unset($GLOBALS['visiteur_session']['htpass']);
236 unset($GLOBALS['visiteur_session']['alea_actuel']);
237 unset($GLOBALS['visiteur_session']['alea_futur']);
238
239 // rajouter les sessions meme en mode auth_http
240 // pour permettre les connexions multiples et identifier les visiteurs
241 if (!isset($_COOKIE['spip_session'])) {
242 $session = charger_fonction('session', 'inc');
243 if ($spip_session = $session($row)) {
244 include_spip('inc/cookie');
245 spip_setcookie(
246 'spip_session',
247 $_COOKIE['spip_session'] = $spip_session,
248 time() + 3600 * 24 * 14
249 );
250 }
251 }
252
253 // Etablir les droits selon le codage attendu
254 // dans ecrire/index.php ecrire/prive.php
255
256 // Pas autorise a acceder a ecrire ? renvoyer le tableau
257 // A noter : le premier appel a autoriser() a le bon gout
258 // d'initialiser $GLOBALS['visiteur_session']['restreint'],
259 // qui ne figure pas dans le fichier de session
260 include_spip('inc/autoriser');
261
262 if (!autoriser('ecrire'))
263 return $row;
264
265 // autoriser('ecrire') ne laisse passer que les Admin et les Redac
266
267 auth_trace($row);
268
269 // Administrateurs
270 if ($connect_statut == '0minirezo') {
271 if (is_array($GLOBALS['visiteur_session']['restreint']))
272 $connect_id_rubrique = $GLOBALS['visiteur_session']['restreint'];
273 $connect_toutes_rubriques = !$connect_id_rubrique;
274 }
275 // Pour les redacteurs, inc_version a fait l'initialisation minimale
276
277 return ''; // i.e. pas de pb.
278 }
279
280 function auth_a_loger()
281 {
282 $redirect = generer_url_public('login',
283 "url=" . rawurlencode(self('&',true)), '&');
284
285 // un echec au "bonjour" (login initial) quand le statut est
286 // inconnu signale sans doute un probleme de cookies
287 if (isset($_GET['bonjour']))
288 $redirect = parametre_url($redirect,
289 'var_erreur',
290 (!isset($GLOBALS['visiteur_session']['statut'])
291 ? 'cookie'
292 : 'statut'
293 ),
294 '&'
295 );
296 return $redirect;
297 }
298
299 // http://doc.spip.org/@auth_trace
300 function auth_trace($row, $date=null)
301 {
302 // Indiquer la connexion. A la minute pres ca suffit.
303 if (!is_numeric($connect_quand = $row['quand']))
304 $connect_quand = strtotime($connect_quand);
305
306 if (is_null($date))
307 $date = date('Y-m-d H:i:s');
308
309 if (abs(strtotime($date) - $connect_quand) >= 60) {
310 sql_updateq("spip_auteurs", array("en_ligne" => $date), "id_auteur=" .$row['id_auteur']);
311 }
312 }
313
314
315 /** ----------------------------------------------------------------------------
316 * API Authentification, gestion des identites centralisees
317 */
318
319 /**
320 * Fonction aiguillage, privee
321 * @param string $fonction
322 * @param array $args
323 * @param mixed $defaut
324 * @return mixed
325 */
326 function auth_administrer($fonction,$args,$defaut=false){
327 $auth_methode = array_shift($args);
328 $auth_methode = $auth_methode ? $auth_methode : 'spip'; // valeur par defaut au cas ou
329 if ($auth = charger_fonction($auth_methode,'auth',true)
330 AND function_exists($f="auth_{$auth_methode}_$fonction")
331 )
332 return call_user_func_array($f, $args);
333 else
334 return $defaut;
335 }
336
337 /**
338 * Pipeline pour inserer du contenu dans le formulaire de login
339 *
340 * @param array $flux
341 * @return array
342 */
343 function auth_formulaire_login($flux){
344 foreach ($GLOBALS['liste_des_authentifications'] as $methode)
345 $flux = auth_administrer('formulaire_login',array($methode,$flux),$flux);
346 return $flux;
347 }
348
349
350
351 /**
352 * Retrouver le login interne lie a une info login saisie
353 * la saisie peut correspondre a un login delegue
354 * qui sera alors converti en login interne apres verification
355 *
356 * @param string $login
357 * @param string $serveur
358 * @return string/bool
359 */
360 function auth_retrouver_login($login, $serveur=''){
361 if (!spip_connect($serveur)) {
362 include_spip('inc/minipres');
363 echo minipres(_T('info_travaux_titre'),
364 _T('titre_probleme_technique'));
365 exit;
366 }
367
368 foreach ($GLOBALS['liste_des_authentifications'] as $methode) {
369 if ($auteur = auth_administrer('retrouver_login',array($methode, $login, $serveur))) {
370 return $auteur;
371 }
372 }
373 return false;
374 }
375
376
377 /**
378 * informer sur un login
379 * Ce dernier transmet le tableau ci-dessous a la fonction JS informer_auteur
380 * Il est invoque par la fonction JS actualise_auteur via la globale JS
381 * page_auteur=#URL_PAGE{informer_auteur} dans le squelette login
382 * N'y aurait-il pas plus simple ?
383 *
384 * @param string $login
385 * @param string $serveur
386 * @return array
387 */
388 function auth_informer_login($login, $serveur=''){
389 if (!$login
390 OR !$login = auth_retrouver_login($login, $serveur)
391 OR !$row = sql_fetsel('*','spip_auteurs','login='.sql_quote($login),'','','','',$serveur)
392 )
393 return array();
394
395 $prefs = unserialize($row['prefs']);
396 $infos = array(
397 'id_auteur'=>$row['id_auteur'],
398 'login'=>$row['login'],
399 'cnx' => ($prefs['cnx'] == 'perma') ? '1' : '0',
400 'logo' => recuperer_fond('formulaires/inc-logo_auteur', $row),
401 );
402
403 // desactiver le hash md5 si pas auteur spip ?
404 if ($row['source']!=='spip'){
405 $row['alea_actuel']= '';
406 $row['alea_futur']= '';
407 }
408 verifier_visiteur();
409
410 return auth_administrer('informer_login',array($row['source'],$infos, $row, $serveur),$infos);
411 }
412
413
414 /**
415 * Essayer les differentes sources d'authenfication dans l'ordre specifie.
416 * S'en souvenir dans visiteur_session['auth']
417 *
418 * @param string $login
419 * @param string $password
420 * @param string $serveur
421 * @return mixed
422 */
423 function auth_identifier_login($login, $password, $serveur=''){
424 $erreur = "";
425 foreach ($GLOBALS['liste_des_authentifications'] as $methode) {
426 if ($auth = charger_fonction($methode, 'auth',true)){
427 $auteur = $auth($login, $password, $serveur);
428 if (is_array($auteur) AND count($auteur)) {
429 spip_log("connexion de $login par methode $methode");
430 $auteur['auth'] = $methode;
431 return $auteur;
432 }
433 elseif (is_string($auteur))
434 $erreur .= "$auteur ";
435 }
436 }
437 return $erreur;
438 }
439
440 /**
441 * Fournir une url de retour apres login par un SSO
442 * pour finir l'authentification
443 *
444 * @param string $auth_methode
445 * @param string $login
446 * @param string $serveur
447 * @return string
448 */
449 function auth_url_retour_login($auth_methode, $login, $redirect='', $serveur=''){
450 $securiser_action = charger_fonction('securiser_action','inc');
451 return $securiser_action('auth', "$auth_methode/$login", $redirect, true);
452 }
453
454 function auth_terminer_identifier_login($auth_methode, $login, $serveur=''){
455 $args = func_get_args();
456 $auteur = auth_administrer('terminer_identifier_login',$args);
457 return $auteur;
458 }
459
460 /**
461 * Loger un auteur suite a son identification
462 *
463 * @param array $auteur
464 */
465 function auth_loger($auteur, $refuse_cookie_admin=false){
466 if (!is_array($auteur) OR !count($auteur))
467 return false;
468
469 $session = charger_fonction('session', 'inc');
470 $session($auteur);
471 $p = ($auteur['prefs']) ? unserialize($auteur['prefs']) : array();
472 $p['cnx'] = ($auteur['cookie'] == 'oui') ? 'perma' : '';
473 $p = array('prefs' => serialize($p));
474 sql_updateq('spip_auteurs', $p, "id_auteur=" . $auteur['id_auteur']);
475
476 if ($auteur['statut'] == 'nouveau') {
477 $session(); // charger la session car on va la modifier
478 $auteur['statut'] = acces_statut($auteur['id_auteur'], $auteur['statut'], $auteur['bio']);
479 }
480
481 // Si on est admin, poser le cookie de correspondance
482 include_spip('inc/cookie');
483 if (!$refuse_cookie_admin AND $auteur['statut'] == '0minirezo') {
484 spip_setcookie('spip_admin', '@'.$auteur['login'],
485 time() + 7 * 24 * 3600);
486 }
487 // sinon le supprimer ...
488 else {
489 spip_setcookie('spip_admin', '',1);
490 }
491
492 // bloquer ici le visiteur qui tente d'abuser de ses droits
493 verifier_visiteur();
494 return true;
495 }
496
497
498 function auth_deloger(){
499 $logout = charger_fonction('logout','action');
500 $logout();
501 }
502
503 /**
504 * Tester la possibilite de modifier le login d'authentification
505 * pour la methode donnee
506 *
507 * @param string $auth_methode
508 * @param string $serveur
509 * @return bool
510 */
511 function auth_autoriser_modifier_login($auth_methode, $serveur=''){
512 $args = func_get_args();
513 return auth_administrer('autoriser_modifier_login',$args);
514 }
515
516 /**
517 * Verifier la validite d'un nouveau login pour modification
518 * pour la methode donnee
519 *
520 * @param string $auth_methode
521 * @param string $new_login
522 * @param int $id_auteur
523 * @param string $serveur
524 * @return string
525 * message d'erreur ou chaine vide si pas d'erreur
526 */
527 function auth_verifier_login($auth_methode, $new_login, $id_auteur=0, $serveur=''){
528 $args = func_get_args();
529 return auth_administrer('verifier_login',$args,'');
530 }
531
532 /**
533 * Modifier le login d'un auteur pour la methode donnee
534 *
535 * @param string $auth_methode
536 * @param string $new_login
537 * @param int $id_auteur
538 * @param string $serveur
539 * @return bool
540 */
541 function auth_modifier_login($auth_methode, $new_login, $id_auteur, $serveur=''){
542 $args = func_get_args();
543 return auth_administrer('modifier_login',$args);
544 }
545
546 /**
547 * Tester la possibilite de modifier le pass
548 * pour la methode donnee
549 *
550 * @param string $auth_methode
551 * @param string $serveur
552 * @return bool
553 * succes ou echec
554 */
555 function auth_autoriser_modifier_pass($auth_methode, $serveur=''){
556 $args = func_get_args();
557 return auth_administrer('autoriser_modifier_pass',$args);
558 }
559
560 /**
561 * Verifier la validite d'un pass propose pour modification
562 * pour la methode donnee
563 *
564 * @param string $auth_methode
565 * @param string $login
566 * @param string $new_pass
567 * @param int $id_auteur
568 * @param string $serveur
569 * @return string
570 * message d'erreur ou chaine vide si pas d'erreur
571 */
572 function auth_verifier_pass($auth_methode, $login, $new_pass, $id_auteur=0, $serveur=''){
573 $args = func_get_args();
574 return auth_administrer('verifier_pass',$args,'');
575 }
576
577 /**
578 * Modifier le mot de passe d'un auteur
579 * pour la methode donnee
580 *
581 * @param string $auth_methode
582 * @param string $login
583 * @param string $new_pass
584 * @param int $id_auteur
585 * @param string $serveur
586 * @return bool
587 * succes ou echec
588 */
589 function auth_modifier_pass($auth_methode, $login, $new_pass, $id_auteur, $serveur=''){
590 $args = func_get_args();
591 return auth_administrer('modifier_pass',$args);
592 }
593
594 /**
595 * Synchroniser un compte sur une base distante pour la methode
596 * donnee lorsque des modifications sont faites dans la base auteur
597 *
598 * @param string $auth_methode
599 * ici true permet de forcer la synchronisation de tous les acces pour toutes les methodes
600 * @param int $id_auteur
601 * @param array $champs
602 * @param array $options
603 * @param string $serveur
604 * @return void
605 */
606 function auth_synchroniser_distant($auth_methode=true, $id_auteur=0, $champs=array(), $options = array(), $serveur=''){
607 $args = func_get_args();
608 if ($auth_methode===true OR (isset($options['all']) AND $options['all']==true)){
609 $options['all'] = true; // ajouter une option all=>true pour chaque auth
610 $args = array(true, $id_auteur, $champs, $options, $serveur);
611 foreach ($GLOBALS['liste_des_authentifications'] as $methode) {
612 array_shift($args);
613 array_unshift($args,$methode);
614 auth_administrer('synchroniser_distant',$args);
615 }
616 }
617 else
618 auth_administrer('synchroniser_distant',$args);
619 }
620
621
622 /**
623 *
624 * @param string $login
625 * @param string $pw
626 * @param string $serveur
627 * @return array
628 */
629 function lire_php_auth($login, $pw, $serveur=''){
630
631 $row = sql_fetsel('*', 'spip_auteurs', 'login=' . sql_quote($login),'','','','',$serveur);
632
633 if (!$row) {
634 if (spip_connect_ldap($serveur)
635 AND $auth_ldap = charger_fonction('ldap', 'auth', true))
636 return $auth_ldap($login, $pw, $serveur);
637 return false;
638 }
639 // su pas de source definie
640 // ou auth/xxx introuvable, utiliser 'spip'
641 if (!$auth_methode = $row['source']
642 OR !$auth = charger_fonction($auth_methode, 'auth', true))
643 $auth = charger_fonction('spip', 'auth', true);
644
645 $auteur='';
646 if ($auth)
647 $auteur = $auth($login, $pw, $serveur);
648 // verifier que ce n'est pas un message d'erreur
649 if (is_array($auteur) AND count($auteur))
650 return $auteur;
651 return false;
652 }
653
654 /**
655 * entete php_auth (est-encore utilise ?)
656 *
657 * @param <type> $pb
658 * @param <type> $raison
659 * @param <type> $retour
660 * @param <type> $url
661 * @param <type> $re
662 * @param <type> $lien
663 */
664 function ask_php_auth($pb, $raison, $retour='', $url='', $re='', $lien='') {
665 @Header("WWW-Authenticate: Basic realm=\"espace prive\"");
666 @Header("HTTP/1.0 401 Unauthorized");
667 $ici = generer_url_ecrire();
668 $retour = $retour?$retour:_T('icone_retour');
669 echo "<b>$pb</b><p>$raison</p>[<a href='$ici'>$retour</a>] ";
670 if ($url) {
671 echo "[<a href='", generer_url_action('cookie',"essai_auth_http=oui&$url"), "'>$re</a>]";
672 }
673
674 if ($lien)
675 echo " [<a href='$ici'>"._T('login_espace_prive')."</a>]";
676 exit;
677 }
678 ?>