- Ajout d'un fichier core.php s'occupant des inclusions minimum pour le lancement...
[ldapsaisie.git] / trunk / includes / class / class.LSsession.php
1 <?php
2 /*******************************************************************************
3  * Copyright (C) 2007 Easter-eggs
4  * http://ldapsaisie.labs.libre-entreprise.org
5  *
6  * Author: See AUTHORS file in top-level directory.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version 2
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 ******************************************************************************/
22
23 /**
24  * Gestion des sessions
25  *
26  * Cette classe gère les sessions d'utilisateurs.
27  *
28  * @author Benjamin Renard <brenard@easter-eggs.com>
29  */
30 class LSsession {
31
32   // La configuration du serveur Ldap utilisé
33   public static $ldapServer = NULL;
34   
35   // L'id du serveur Ldap utilisé
36   private static $ldapServerId = NULL;
37   
38   // Le topDn courant
39   private static $topDn = NULL;
40   
41   // Le DN de l'utilisateur connecté
42   private static $dn = NULL;
43   
44   // Le RDN de l'utilisateur connecté (son identifiant)
45   private static $rdn = NULL;
46   
47   // Les LSprofiles de l'utilisateur
48   private static $LSprofiles = array();
49   
50   // Les droits d'accès de l'utilisateur
51   private static $LSaccess = array();
52   
53   // Les fichiers temporaires
54   private static $tmp_file = array();
55   
56   // Langue et encodage actuel
57   private static $lang = NULL;
58   private static $encoding = NULL;
59   
60   /*
61    * Constante de classe non stockée en session
62    */
63   // Le template à afficher
64   private static $template = NULL;
65   
66   // Les subDn des serveurs Ldap
67   private static $_subDnLdapServer = array();
68   
69   // Affichage Ajax
70   private static $ajaxDisplay = false;
71
72   // Les fichiers JS à charger dans la page
73   private static $JSscripts = array();
74   
75   // Les paramètres JS à communiquer dans la page
76   private static $_JSconfigParams = array();
77   
78   // Les fichiers CSS à charger dans la page
79   private static $CssFiles = array();
80
81   // L'objet de l'utilisateur connecté
82   private static $LSuserObject = NULL;
83
84  /**
85   * Include un fichier PHP
86   *
87   * @author Benjamin Renard <brenard@easter-eggs.com>
88   *
89   * @retval true si tout c'est bien passé, false sinon
90   */
91   public static function includeFile($file) {
92     if (!file_exists($file)) {
93       return;
94     }
95     if (LSdebug) {
96       return include_once($file);
97     }
98     else {
99       return @include_once($file);
100     }
101     return;
102   }
103
104  /**
105   * Lancement de LSconfig
106   *
107   * @author Benjamin Renard <brenard@easter-eggs.com>
108   *
109   * @retval true si tout c'est bien passé, false sinon
110   */
111   private static function startLSconfig() {
112     if (self :: loadLSclass('LSconfig')) {
113       if (LSconfig :: start()) {
114         return true;
115       }
116     }
117     die("ERROR : Can't load configuration files.");
118     return;
119   }
120
121  /**
122   * Lancement et initialisation de Smarty
123   *
124   * @author Benjamin Renard <brenard@easter-eggs.com>
125   *
126   * @retval true si tout c'est bien passé, false sinon
127   */  
128   private static function startLStemplate() {
129     if ( self :: includeFile(LSconfig :: get('Smarty')) ) {
130       $GLOBALS['Smarty'] = new Smarty();
131       $GLOBALS['Smarty'] -> template_dir = LS_TEMPLATES_DIR;
132       $GLOBALS['Smarty'] -> compile_dir = LS_TMP_DIR;
133       
134       if (LSdebug) {
135         $GLOBALS['Smarty'] -> caching = 0;
136         // cache files are always regenerated
137         $GLOBALS['Smarty'] -> force_compile = TRUE;
138         // recompile template if it is changed
139         $GLOBALS['Smarty'] -> compile_check = TRUE;
140       }
141       
142       $GLOBALS['Smarty'] -> assign('LS_CSS_DIR',LS_CSS_DIR);
143       $GLOBALS['Smarty'] -> assign('LS_IMAGES_DIR',LS_IMAGES_DIR);
144       
145       self :: addJSconfigParam('LS_IMAGES_DIR',LS_IMAGES_DIR);
146       return true;
147     }
148     die("ERROR : Can't load Smarty.");
149     return;
150   }
151   
152  /**
153   * Retourne le topDn de la session
154   *
155   * @author Benjamin Renard <brenard@easter-eggs.com>
156   *
157   * @retval string le topDn de la session
158   */
159   public static function getTopDn() {
160     return self :: $topDn;
161   }
162
163  /**
164   * Initialisation de la gestion des erreurs
165   *
166   * Création de l'objet LSerror
167   *
168   * @author Benjamin Renard <brenard@easter-eggs.com
169   *
170   * @retval boolean true si l'initialisation a réussi, false sinon.
171   */
172   private static function startLSerror() {
173     if(!self :: loadLSclass('LSerror')) {
174       return;
175     }
176     self :: defineLSerrors();
177     return true;
178   }
179
180  /**
181   * Chargement d'une classe d'LdapSaisie
182   *
183   * @param[in] $class Nom de la classe Ã  charger (Exemple : LSeepeople)
184   * @param[in] $type (Optionnel) Type de classe Ã  charger (Exemple : LSobjects)
185   *
186   * @author Benjamin Renard <brenard@easter-eggs.com
187   * 
188   * @retval boolean true si le chargement a réussi, false sinon.
189   */
190   public static function loadLSclass($class,$type='') {
191     if (class_exists($class))
192       return true;
193     if($type!='')
194       $type=$type.'.';
195     return self :: includeFile(LS_CLASS_DIR .'class.'.$type.$class.'.php');
196   }
197
198  /**
199   * Chargement d'un object LdapSaisie
200   *
201   * @param[in] $object Nom de l'objet Ã  charger
202   *
203   * @retval boolean true si le chargement a réussi, false sinon.
204   */
205   public static function loadLSobject($object) {
206     if(class_exists($object)) {
207       return true;
208     }
209     $error = 0;
210     self :: loadLSclass('LSldapObject');
211     if (!self :: loadLSclass($object,'LSobjects')) {
212       $error = 1;
213     }
214     if (!self :: includeFile( LS_OBJECTS_DIR . 'config.LSobjects.'.$object.'.php' )) {
215       $error = 1;
216     }
217     else {
218       if (!LSconfig :: set("LSobjects.$object",$GLOBALS['LSobjects'][$object])) {
219         $error = 1;
220       }
221     }
222     if ($error) {
223       LSerror :: addErrorCode('LSsession_04',$object);
224       return;
225     }
226     return true;
227   }
228
229  /**
230   * Chargement d'un addons d'LdapSaisie
231   *
232   * @param[in] $addon Nom de l'addon Ã  charger (Exemple : samba)
233   *
234   * @author Benjamin Renard <brenard@easter-eggs.com
235   * 
236   * @retval boolean true si le chargement a réussi, false sinon.
237   */
238   public static function loadLSaddon($addon) {
239     if(self :: includeFile(LS_ADDONS_DIR .'LSaddons.'.$addon.'.php')) {
240       self :: includeFile(LS_CONF_DIR."LSaddons/config.LSaddons.".$addon.".php");
241       if (!call_user_func('LSaddon_'. $addon .'_support')) {
242         LSerror :: addErrorCode('LSsession_02',$addon);
243         return;
244       }
245       return true;
246     }
247     return;
248   }
249
250  /**
251   * Chargement des addons LdapSaisie
252   *
253   * Chargement des LSaddons contenue dans la variable
254   * $GLOBALS['LSaddons']['loads']
255   *
256   * @retval boolean true si le chargement a réussi, false sinon.
257   */
258   public static function loadLSaddons() {
259     $conf=LSconfig :: get('LSaddons.loads');
260     if(!is_array($conf)) {
261       LSerror :: addErrorCode('LSsession_01',"LSaddons['loads']");
262       return;
263     }
264
265     foreach ($conf as $addon) {
266       self :: loadLSaddon($addon);
267     }
268     return true;
269   }
270
271  /**
272   * Défini la locale
273   * 
274   * @retval void
275   */
276   public static function setLocale() {
277     if (isset($_REQUEST['lang'])) {
278       $lang = $_REQUEST['lang'];
279     }
280     elseif (isset($_SESSION['LSlang'])) {
281       $lang = $_SESSION['LSlang'];
282     }
283     elseif (isset(self :: $ldapServer['lang'])) {
284       $lang = self :: $ldapServer['lang'];
285     }
286     else {
287       $lang = LSconfig :: get('lang');
288     }
289     
290     if (isset($_REQUEST['encoding'])) {
291       $encoding = $_REQUEST['encoding'];
292     }
293     elseif (isset($_SESSION['LSencoding'])) {
294       $encoding = $_SESSION['LSencoding'];
295     }
296     elseif (isset(self :: $ldapServer['encoding'])) {
297       $encoding = self :: $ldapServer['encoding'];
298     }
299     else {
300       $encoding = LSconfig :: get('encoding');
301     }
302     
303     $_SESSION['LSlang']=$lang;
304     self :: $lang=$lang;
305     $_SESSION['LSencoding']=$encoding;
306     self :: $encoding=$encoding;
307     
308
309     if (self :: localeExist($lang,$encoding)) {
310       if ($encoding) {
311         $lang.='.'.$encoding;
312       }
313       setlocale(LC_ALL, $lang);
314       bindtextdomain(LS_TEXT_DOMAIN, LS_I18N_DIR);
315       textdomain(LS_TEXT_DOMAIN);
316       
317       if (is_file(LS_I18N_DIR.'/'.$lang.'/lang.php')) {
318         include(LS_I18N_DIR.'/'.$lang.'/lang.php');
319       }
320     }
321     else {
322       if ($encoding && $lang) {
323         $lang.='.'.$encoding;
324       }
325       LSdebug('La locale "'.$lang.'" n\'existe pas, utilisation de la locale par défaut.');
326     }
327   }
328   
329  /**
330   * Retourne la liste des langues disponibles
331   * 
332   * @retval array Tableau/Liste des langues disponibles
333   **/ 
334   public static function getLangList() {
335     $list=array('en_US');
336     if (self :: $encoding) {
337       $regex = '^([a-zA-Z_]*)\.'.self :: $encoding.'$';
338     }
339     else {
340       $regex = '^([a-zA-Z_]*)$';
341     }
342     if ($handle = opendir(LS_I18N_DIR)) {
343       while (false !== ($file = readdir($handle))) {
344         if(is_dir(LS_I18N_DIR.'/'.$file)) {
345           if (ereg($regex,$file,$regs)) {
346             if (!in_array($regs[1],$list)) {
347               $list[]=$regs[1];
348             }
349           }
350         }
351       }
352     }
353     return $list;
354   }
355   
356  /**
357   * Vérifie si une locale est disponible
358   * 
359   * @param[in] $lang string La langue (Ex : fr_FR)
360   * @param[in] $encoding string L'encodage de caractère (Ex : UTF8)
361   * 
362   * @retval boolean True si la locale est disponible, False sinon
363   **/
364   public static function localeExist($lang,$encoding) {
365     if ( !$lang && !$encoding ) {
366       return;
367     }
368     $locale=$lang.(($encoding)?'.'.$encoding:'');
369     if ($locale=='en_US.UTF8') {
370       return true;
371     }
372     return (is_dir(LS_I18N_DIR.'/'.$locale));
373   }
374
375  /**
376   * Initialisation LdapSaisie
377   *
378   * @retval boolean True si l'initialisation à réussi, false sinon.
379   */
380   public static function initialize() {
381     if (!self :: startLSconfig()) {
382       return;
383     }
384     
385     self :: startLStemplate();
386     
387     session_start();
388     
389     self :: setLocale();
390     
391     self :: startLSerror();
392     self :: loadLSaddons();
393     return true;
394   }
395
396  /**
397   * Initialisation de la session LdapSaisie
398   *
399   * Initialisation d'une LSsession :
400   * - Authentification et activation du mécanisme de session de LdapSaisie
401   * - ou Chargement des paramètres de la session Ã  partir de la variable 
402   *   $_SESSION['LSsession'].
403   * - ou Destruction de la session en cas de $_GET['LSsession_logout'].
404   *
405   * @retval boolean True si l'initialisation Ã  réussi (utilisateur authentifié), false sinon.
406   */
407   public static function startLSsession() {
408     if (!self :: initialize()) {
409       return;
410     }   
411
412     // Déconnexion
413     if (isset($_GET['LSsession_logout'])||isset($_GET['LSsession_recoverPassword'])) {
414       session_destroy();
415       
416       if (is_array($_SESSION['LSsession']['tmp_file'])) {
417         self :: $tmp_file = $_SESSION['LSsession']['tmp_file'];
418       }
419       self :: deleteTmpFile();
420       unset($_SESSION['LSsession']);
421     }
422     
423     // Récupération de mot de passe
424     if (isset($_GET['recoveryHash'])) {
425       $_POST['LSsession_user'] = 'a determiner plus tard';
426     }
427     
428     if(isset($_SESSION['LSsession'])) {
429       // Session existante
430       self :: $topDn        = $_SESSION['LSsession']['topDn'];
431       self :: $dn           = $_SESSION['LSsession']['dn'];
432       self :: $rdn          = $_SESSION['LSsession']['rdn'];
433       self :: $ldapServerId = $_SESSION['LSsession']['ldapServerId'];
434       self :: $tmp_file     = $_SESSION['LSsession']['tmp_file'];
435       
436       if ( self :: cacheLSprofiles() && !isset($_REQUEST['LSsession_refresh']) ) {
437         self :: setLdapServer(self :: $ldapServerId);
438         self :: $LSprofiles   = $_SESSION['LSsession']['LSprofiles'];
439         self :: $LSaccess   = $_SESSION['LSsession']['LSaccess'];
440         if (!self :: LSldapConnect())
441           return;
442       }
443       else {
444         self :: setLdapServer(self :: $ldapServerId);
445         if (!self :: LSldapConnect())
446           return;
447         self :: loadLSprofiles();
448       }
449       
450       if ( self :: cacheSudDn() && (!isset($_REQUEST['LSsession_refresh'])) ) {
451         self :: $_subDnLdapServer = $_SESSION['LSsession_subDnLdapServer'];
452       }
453       
454       if (!self :: loadLSobject(self :: $ldapServer['authObjectType'])) {
455         return;
456       }
457       
458       self :: getLSuserObject();
459       
460       if ( !self :: cacheLSprofiles() || isset($_REQUEST['LSsession_refresh']) ) {
461         self :: loadLSaccess();
462       }
463       
464       $GLOBALS['Smarty'] -> assign('LSsession_username',self :: getLSuserObject() -> getDisplayName());
465       
466       if ($_POST['LSsession_topDn']) {
467         if (self :: validSubDnLdapServer($_POST['LSsession_topDn'])) {
468           self :: $topDn = $_POST['LSsession_topDn'];
469           $_SESSION['LSsession']['topDn'] = $_POST['LSsession_topDn'];
470         } // end if
471       } // end if
472       
473       return true;
474       
475     }
476     else {
477       // Session inexistante
478       $recoveryPasswordInfos=array();
479
480       if (isset($_POST['LSsession_user'])) {
481         if (isset($_POST['LSsession_ldapserver'])) {
482           self :: setLdapServer($_POST['LSsession_ldapserver']);
483         }
484         else {
485           self :: setLdapServer(0);
486         }
487         
488         // Connexion au serveur LDAP
489         if (self :: LSldapConnect()) {
490
491           // topDn
492           if ( $_POST['LSsession_topDn'] != '' ){
493             self :: $topDn = $_POST['LSsession_topDn'];
494           }
495           else {
496             self :: $topDn = self :: $ldapServer['ldap_config']['basedn'];
497           }
498           $_SESSION['LSsession_topDn']=self :: $topDn;
499
500           if ( self :: loadLSobject(self :: $ldapServer['authObjectType']) ) {
501             $authobject = new self :: $ldapServer['authObjectType']();
502             $find=true;
503             if (isset($_GET['recoveryHash'])) {
504               $filter=self :: $ldapServer['recoverPassword']['recoveryHashAttr']."=".$_GET['recoveryHash'];
505               $result = $authobject -> listObjects($filter,self :: $topDn);
506               $nbresult=count($result);
507               if ($nbresult==1) {
508                 $rdn = $result[0] -> getValue('rdn');
509                 $rdn = $rdn[0];
510                 $_POST['LSsession_user'] = $rdn;
511                 $find=false;
512               }
513             }
514             if ($find) {
515               $result = $authobject -> searchObject($_POST['LSsession_user'],self :: $topDn,self :: $ldapServer['authObjectFilter']);
516               $nbresult=count($result);
517             }
518             if ($nbresult==0) {
519               // identifiant incorrect
520               LSdebug('identifiant incorrect');
521               LSerror :: addErrorCode('LSsession_06');
522             }
523             else if ($nbresult>1) {
524               // duplication d'authentité
525               LSerror :: addErrorCode('LSsession_07');
526             }
527             else {
528               if (isset($_GET['LSsession_recoverPassword'])) {
529                 LSdebug('Recover : Id trouvé');
530                 if (self :: $ldapServer['recoverPassword']) {
531                   if (self :: loadLSaddon('mail')) {
532                     LSdebug('Récupération active');
533                     $user=$result[0];
534                     $emailAddress = $user -> getValue(self :: $ldapServer['recoverPassword']['mailAttr']);
535                     $emailAddress = $emailAddress[0];
536                     
537                     // Header des mails
538                     $sendParams=array();
539                     if (self :: $ldapServer['recoverPassword']['recoveryEmailSender']) {
540                       $sendParams['From']=self :: $ldapServer['recoverPassword']['recoveryEmailSender'];
541                     }
542                     
543                     if (checkEmail($emailAddress)) {
544                       LSdebug('Email : '.$emailAddress);
545                       self :: $dn = $user -> getDn();
546                       // 1ère étape : envoie du recoveryHash
547                       if (!isset($_GET['recoveryHash'])) {
548                         // Generer un hash
549                         $rdn=$user -> getValue('rdn');
550                         $rdn = $rdn[0];
551                         $recovery_hash = md5($rdn . strval(time()) . strval(rand()));
552                         
553                         $lostPasswdForm = $user -> getForm('lostPassword');
554                         $lostPasswdForm -> setPostData(
555                           array(
556                             self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => $recovery_hash
557                           )
558                           ,true
559                         );
560                         
561                         if($lostPasswdForm -> validate()) {
562                           if ($user -> updateData('lostPassword')) {
563                             // recoveryHash de l'utilisateur mis à jour
564                             if ($_SERVER['HTTPS']=='on') {
565                               $recovery_url='https://';
566                             }
567                             else {
568                               $recovery_url='http://';
569                             }
570                             $recovery_url .= $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].'&recoveryHash='.$recovery_hash;
571
572                             if (
573                               sendMail(
574                                 $emailAddress,
575                                 self :: $ldapServer['recoverPassword']['recoveryHashMail']['subject'],
576                                 getFData(self :: $ldapServer['recoverPassword']['recoveryHashMail']['msg'],$recovery_url),
577                                 $sendParams
578                               )
579                             ){
580                               // Mail a bien été envoyé
581                               $recoveryPasswordInfos['recoveryHashMail']=$emailAddress;
582                             }
583                             else {
584                               // Problème durant l'envoie du mail
585                               LSdebug("Problème durant l'envoie du mail");
586                               LSerror :: addErrorCode('LSsession_20',7);
587                             }
588                           }
589                           else {
590                             // Erreur durant la mise à jour de l'objet
591                             LSdebug("Erreur durant la mise à jour de l'objet");
592                             LSerror :: addErrorCode('LSsession_20',6);
593                           }
594                         }
595                         else {
596                           // Erreur durant la validation du formulaire de modification de perte de password
597                           LSdebug("Erreur durant la validation du formulaire de modification de perte de password");
598                           LSerror :: addErrorCode('LSsession_20',5);
599                         }
600                       }
601                       // 2nd étape : génération du mot de passe + envoie par mail
602                       else {
603                         $attr=$user -> attrs[self :: $ldapServer['authObjectTypeAttrPwd']];
604                         if ($attr instanceof LSattribute) {
605                           $mdp = generatePassword($attr -> config['html_options']['chars'],$attr -> config['html_options']['lenght']);
606                           LSdebug('Nvx mpd : '.$mdp);
607                           $lostPasswdForm = $user -> getForm('lostPassword');
608                           $lostPasswdForm -> setPostData(
609                             array(
610                               self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => array(''),
611                               self :: $ldapServer['authObjectTypeAttrPwd'] => array($mdp)
612                             )
613                             ,true
614                           );
615                           if($lostPasswdForm -> validate()) {
616                             if ($user -> updateData('lostPassword')) {
617                               if (
618                                 sendMail(
619                                   $emailAddress,
620                                   self :: $ldapServer['recoverPassword']['newPasswordMail']['subject'],
621                                   getFData(self :: $ldapServer['recoverPassword']['newPasswordMail']['msg'],$mdp),
622                                   $sendParams
623                                 )
624                               ){
625                                 // Mail a bien été envoyé
626                                 $recoveryPasswordInfos['newPasswordMail']=$emailAddress;
627                               }
628                               else {
629                                 // Problème durant l'envoie du mail
630                                 LSdebug("Problème durant l'envoie du mail");
631                                 LSerror :: addErrorCode('LSsession_20',4);
632                               }
633                             }
634                             else {
635                               // Erreur durant la mise à jour de l'objet
636                               LSdebug("Erreur durant la mise à jour de l'objet");
637                               LSerror :: addErrorCode('LSsession_20',3);
638                             }
639                           }
640                           else {
641                             // Erreur durant la validation du formulaire de modification de perte de password
642                             LSdebug("Erreur durant la validation du formulaire de modification de perte de password");
643                             LSerror :: addErrorCode('LSsession_20',2);
644                           }
645                         }
646                         else {
647                           // l'attribut password n'existe pas
648                           LSdebug("L'attribut password n'existe pas");
649                           LSerror :: addErrorCode('LSsession_20',1);
650                         }
651                       }
652                     }
653                     else {
654                       LSerror :: addErrorCode('LSsession_19');
655                     }
656                   }
657                 }
658                 else {
659                   LSerror :: addErrorCode('LSsession_18');
660                 }
661               }
662               else {
663                 if ( self :: checkUserPwd($result[0],$_POST['LSsession_pwd']) ) {
664                   // Authentification réussi
665                   self :: $LSuserObject = $result[0];
666                   self :: $dn = $result[0]->getValue('dn');
667                   self :: $rdn = $result[0]->getValue('rdn');
668                   self :: loadLSprofiles();
669                   self :: loadLSaccess();
670                   $GLOBALS['Smarty'] -> assign('LSsession_username',self :: getLSuserObject() -> getDisplayName());
671                   $_SESSION['LSsession']=self :: getContextInfos();
672                   return true;
673                 }
674                 else {
675                   LSerror :: addErrorCode('LSsession_06');
676                   LSdebug('mdp incorrect');
677                 }
678               }
679             }
680           }
681           else {
682             LSerror :: addErrorCode('LSsession_10');
683           }
684         }
685         else {
686           LSerror :: addErrorCode('LSsession_09');
687         }
688       }
689       if (self :: $ldapServerId) {
690         $GLOBALS['Smarty'] -> assign('ldapServerId',self :: $ldapServerId);
691       }
692       $GLOBALS['Smarty'] -> assign('topDn',self :: $topDn);
693       if (isset($_GET['LSsession_recoverPassword'])) {
694         self :: displayRecoverPasswordForm($recoveryPasswordInfos);
695       }
696       else {
697         self :: displayLoginForm();
698       }
699       return;
700     }
701   }
702   
703  /**
704   * Retourne les informations du contexte
705   *
706   * @author Benjamin Renard <brenard@easter-eggs.com
707   * 
708   * @retval array Tableau associatif des informations du contexte
709   */
710   private static function getContextInfos() {
711     return array(
712       'tmp_file' => self :: $tmp_file,
713       'topDn' => self :: $topDn,
714       'dn' => self :: $dn,
715       'rdn' => self :: $rdn,
716       'ldapServerId' => self :: $ldapServerId,
717       'ldapServer' => self :: $ldapServer,
718       'LSprofiles' => self :: $LSprofiles,
719       'LSaccess' => self :: $LSaccess
720     );
721   }
722   
723   /**
724   * Retourne l'objet de l'utilisateur connecté
725   *
726   * @author Benjamin Renard <brenard@easter-eggs.com
727   * 
728   * @retval mixed L'objet de l'utilisateur connecté ou false si il n'a pas put
729   *               être créé
730   */
731   public static function getLSuserObject($dn=null) {
732     if ($dn) {
733       self :: $dn = $dn;
734     }
735     if (!self :: $LSuserObject) {
736       if (self :: loadLSobject(self :: $ldapServer['authObjectType'])) {
737         self :: $LSuserObject = new self :: $ldapServer['authObjectType']();
738         self :: $LSuserObject -> loadData(self :: $dn);
739       }
740       else {
741         return;
742       }
743     }
744     return self :: $LSuserObject;
745   }
746   
747  /**
748   * Retourne le DN de l'utilisateur connecté
749   *
750   * @author Benjamin Renard <brenard@easter-eggs.com
751   * 
752   * @retval string Le DN de l'utilisateur connecté
753   */
754   public static function getLSuserObjectDn() {
755     return self :: $dn;
756   }
757
758  /**
759   * Modifie l'utilisateur connecté à la volé
760   * 
761   * @param[in] $object Mixed  L'objet Ldap du nouvel utilisateur
762   *                           le type doit correspondre à
763   *                           self :: $ldapServer['authObjectType']
764   * 
765   * @retval boolean True en cas de succès, false sinon
766   */
767  public static function changeAuthUser($object) {
768   if ($object instanceof self :: $ldapServer['authObjectType']) {
769     self :: $dn = $object -> getDn();
770     $rdn = $object -> getValue('rdn');
771     if(is_array($rdn)) {
772       $rdn = $rdn[0];
773     }
774     self :: $rdn = $rdn;
775     self :: $LSuserObject = $object;
776     
777     if(self :: loadLSprofiles()) {
778       self :: loadLSaccess();
779       $_SESSION['LSsession']=self :: getContextInfos();
780       return true;
781     }
782   }
783   return;
784  }
785
786  /**
787   * Définition du serveur Ldap de la session
788   *
789   * Définition du serveur Ldap de la session Ã  partir de son ID dans 
790   * le tableau $GLOBALS['LSconfig']['ldap_servers'].
791   *
792   * @param[in] integer Index du serveur Ldap
793   *
794   * @retval boolean True sinon false.
795   */
796   public static function setLdapServer($id) {
797     $conf = LSconfig :: get("ldap_servers.$id");
798     if ( is_array($conf) ) {
799       self :: $ldapServerId = $id;
800       self :: $ldapServer = $conf;
801       self :: setLocale();
802       return true;
803     }
804     else {
805       return;
806     }
807   }
808
809  /**
810   * Connexion au serveur Ldap
811   *
812   * @retval boolean True sinon false.
813   */
814   public static function LSldapConnect() {
815     if (self :: $ldapServer) {
816       self :: includeFile(LSconfig :: get('NetLDAP2'));
817       if (!self :: loadLSclass('LSldap')) {
818         return;
819       }
820       LSldap :: connect(self :: $ldapServer['ldap_config']);
821       if (LSldap :: isConnected()) {
822         return true;
823       }
824       else {
825         return;
826       }
827     }
828     else {
829       LSerror :: addErrorCode('LSsession_03');
830       return;
831     }
832   }
833
834  /**
835   * Retourne les sous-dns du serveur Ldap courant
836   *
837   * @retval mixed Tableau des subDn, false si une erreur est survenue.
838   */
839   public static function getSubDnLdapServer() {
840     if (self :: cacheSudDn() && isset(self :: $_subDnLdapServer[self :: $ldapServerId])) {
841       return self :: $_subDnLdapServer[self :: $ldapServerId];
842     }
843     if (!isset(self :: $ldapServer['subDn'])) {
844       return;
845     }
846     if ( !is_array(self :: $ldapServer['subDn']) ) {
847       return;
848     }
849     $return=array();
850     foreach(self :: $ldapServer['subDn'] as $subDn_name => $subDn_config) {
851       if ($subDn_name == 'LSobject') {
852         if (is_array($subDn_config)) {
853           foreach($subDn_config as $LSobject_name => $LSoject_config) {
854             if ($LSoject_config['basedn']) {
855               $basedn = $LSoject_config['basedn'];
856             }
857             else {
858               $basedn = NULL;
859             }
860             if ($LSoject_config['displayName']) {
861               $displayName = $LSoject_config['displayName'];
862             }
863             else {
864               $displayName = NULL;
865             }
866             if( self :: loadLSobject($LSobject_name) ) {
867               if ($subdnobject = new $LSobject_name()) {
868                 $tbl_return = $subdnobject -> getSelectArray(NULL,$basedn,$displayName);
869                 if (is_array($tbl_return)) {
870                   $return=array_merge($return,$tbl_return);
871                 }
872                 else {
873                   LSerror :: addErrorCode('LSsession_17',3);
874                 }
875               }
876               else {
877                 LSerror :: addErrorCode('LSsession_17',2);
878               }
879             }
880           }
881         }
882         else {
883           LSerror :: addErrorCode('LSsession_17',1);
884         }
885       }
886       else {
887         if ((isCompatibleDNs($subDn_config['dn'],self :: $ldapServer['ldap_config']['basedn']))&&($subDn_config['dn']!="")) {
888           $return[$subDn_config['dn']] = __($subDn_name);
889         }
890       }
891     }
892     if (self :: cacheSudDn()) {
893       self :: $_subDnLdapServer[self :: $ldapServerId]=$return;
894       $_SESSION['LSsession_subDnLdapServer'] = self :: $_subDnLdapServer;
895     }
896     return $return;
897   }
898   
899   /**
900    * Retourne la liste de subDn du serveur Ldap utilise
901    * trié par la profondeur dans l'arboressence (ordre décroissant)
902    * 
903    * @return array() Tableau des subDn trié
904    */  
905   public static function getSortSubDnLdapServer() {
906     $subDnLdapServer = self :: getSubDnLdapServer();
907     if (!$subDnLdapServer) {
908       return array();
909     }
910     uksort($subDnLdapServer,"compareDn");
911     return $subDnLdapServer;
912   }
913
914  /**
915   * Retourne les options d'une liste déroulante pour le choix du topDn
916   * de connexion au serveur Ldap
917   *
918   * Liste les subdn (self :: $ldapServer['subDn'])
919   *
920   * @retval string Les options (<option>) pour la sélection du topDn.
921   */
922   public static function getSubDnLdapServerOptions($selected=NULL) {
923     $list = self :: getSubDnLdapServer();
924     if ($list) {
925       asort($list);
926       $display='';
927       foreach($list as $dn => $txt) {
928         if ($selected && ($selected==$dn)) {
929           $selected_txt = ' selected';
930         }
931         else {
932           $selected_txt = '';
933         }
934         $display.="<option value=\"".$dn."\"$selected_txt>".$txt."</option>\n"; 
935       }
936       return $display;
937     }
938     return;
939   }
940
941  /**
942   * Vérifie qu'un subDn est déclaré
943   *
944   * @param[in] string Un subDn
945   * 
946   * @retval boolean True si le subDn existe, False sinon
947   */
948   public static function validSubDnLdapServer($subDn) {
949     $listTopDn = self :: getSubDnLdapServer();
950     if(is_array($listTopDn)) {
951       foreach($listTopDn as $dn => $txt) {
952         if ($subDn==$dn) {
953           return true;
954         } // end if
955       } // end foreach
956     } // end if
957     return;
958   }
959
960  /**
961   * Test un couple LSobject/pwd
962   *
963   * Test un bind sur le serveur avec le dn de l'objet et le mot de passe fourni.
964   *
965   * @param[in] LSobject L'object "user" pour l'authentification
966   * @param[in] string Le mot de passe Ã  tester
967   *
968   * @retval boolean True si l'authentification Ã  réussi, false sinon.
969   */
970   public static function checkUserPwd($object,$pwd) {
971     return LSldap :: checkBind($object -> getValue('dn'),$pwd);
972   }
973
974  /**
975   * Affiche le formulaire de login
976   *
977   * Défini les informations pour le template Smarty du formulaire de login.
978   *
979   * @retval void
980   */
981   public static function displayLoginForm() {
982     $GLOBALS['Smarty'] -> assign('pagetitle',_('Connection'));
983     if (isset($_GET['LSsession_logout'])) {
984       $GLOBALS['Smarty'] -> assign('loginform_action','index.php');
985     }
986     else {
987       $GLOBALS['Smarty'] -> assign('loginform_action',$_SERVER['REQUEST_URI']);
988     }
989     if (count(LSconfig :: get('ldap_servers'))==1) {
990       $GLOBALS['Smarty'] -> assign('loginform_ldapserver_style','style="display: none"');
991     }
992     $GLOBALS['Smarty'] -> assign('loginform_label_ldapserver',_('LDAP server'));
993     $ldapservers_name=array();
994     $ldapservers_index=array();
995     foreach(LSconfig :: get('ldap_servers') as $id => $infos) {
996       $ldapservers_index[]=$id;
997       $ldapservers_name[]=__($infos['name']);
998     }
999     $GLOBALS['Smarty'] -> assign('loginform_ldapservers_name',$ldapservers_name);
1000     $GLOBALS['Smarty'] -> assign('loginform_ldapservers_index',$ldapservers_index);
1001
1002     $GLOBALS['Smarty'] -> assign('loginform_label_level',_('Level'));
1003     $GLOBALS['Smarty'] -> assign('loginform_label_user',_('Identifier'));
1004     $GLOBALS['Smarty'] -> assign('loginform_label_pwd',_('Password'));
1005     $GLOBALS['Smarty'] -> assign('loginform_label_submit',_('Connect'));
1006     $GLOBALS['Smarty'] -> assign('loginform_label_recoverPassword',_('Forgot your password ?'));
1007     
1008     self :: setTemplate('login.tpl');
1009     self :: addJSscript('LSsession_login.js');
1010   }
1011
1012  /**
1013   * Affiche le formulaire de récupération de mot de passe
1014   *
1015   * Défini les informations pour le template Smarty du formulaire de 
1016   * récupération de mot de passe
1017   * 
1018   * @param[in] $infos array() Information sur le status du processus de 
1019   *                           recouvrement de mot de passe
1020   *
1021   * @retval void
1022   */
1023   public static function displayRecoverPasswordForm($recoveryPasswordInfos) {
1024     $GLOBALS['Smarty'] -> assign('pagetitle',_('Recovery of your credentials'));
1025     $GLOBALS['Smarty'] -> assign('recoverpasswordform_action','index.php?LSsession_recoverPassword');
1026     
1027     if (count(LSconfig :: get('ldap_servers'))==1) {
1028       $GLOBALS['Smarty'] -> assign('recoverpasswordform_ldapserver_style','style="display: none"');
1029     }
1030     
1031     $GLOBALS['Smarty'] -> assign('recoverpasswordform_label_ldapserver',_('LDAP server'));
1032     $ldapservers_name=array();
1033     $ldapservers_index=array();
1034     foreach(LSconfig :: get('ldap_servers') as $id => $infos) {
1035       $ldapservers_index[]=$id;
1036       $ldapservers_name[]=$infos['name'];
1037     }
1038     $GLOBALS['Smarty'] -> assign('recoverpasswordform_ldapservers_name',$ldapservers_name);
1039     $GLOBALS['Smarty'] -> assign('recoverpasswordform_ldapservers_index',$ldapservers_index);
1040
1041     $GLOBALS['Smarty'] -> assign('recoverpasswordform_label_user',_('Identifier'));
1042     $GLOBALS['Smarty'] -> assign('recoverpasswordform_label_submit',_('Validate'));
1043     $GLOBALS['Smarty'] -> assign('recoverpasswordform_label_back',_('Back'));
1044     
1045     $recoverpassword_msg = _('Please fill the identifier field to proceed recovery procedure');
1046     
1047     if (isset($recoveryPasswordInfos['recoveryHashMail'])) {
1048       $recoverpassword_msg = getFData(
1049         _("An email has been sent to  %{mail}. " .
1050         "Please follow the instructions on it."),
1051         $recoveryPasswordInfos['recoveryHashMail']
1052       );
1053     }
1054     
1055     if (isset($recoveryPasswordInfos['newPasswordMail'])) {
1056       $recoverpassword_msg = getFData(
1057         _("Your new password has been sent to %{mail}. "),
1058         $recoveryPasswordInfos['newPasswordMail']
1059       );
1060     }
1061     
1062     $GLOBALS['Smarty'] -> assign('recoverpassword_msg',$recoverpassword_msg);
1063     
1064     self :: setTemplate('recoverpassword.tpl');
1065     self :: addJSscript('LSsession_recoverPassword.js');
1066   }
1067
1068  /**
1069   * Défini le template Smarty Ã  utiliser
1070   *
1071   * Remarque : les fichiers de templates doivent se trouver dans le dossier 
1072   * templates/.
1073   *
1074   * @param[in] string Le nom du fichier de template
1075   *
1076   * @retval void
1077   */
1078   public static function setTemplate($template) {
1079     self :: $template = $template;
1080   }
1081
1082  /**
1083   * Ajoute un script JS au chargement de la page
1084   *
1085   * Remarque : les scripts doivents Ãªtre dans le dossier LS_JS_DIR.
1086   *
1087   * @param[in] $script Le nom du fichier de script Ã  charger.
1088   *
1089   * @retval void
1090   */
1091   public static function addJSscript($file,$path=NULL) {
1092     $script=array(
1093       'file' => $file,
1094       'path' => $path
1095     );
1096     self :: $JSscripts[$path.$file]=$script;
1097   }
1098
1099  /**
1100   * Ajouter un paramètre de configuration Javascript
1101   * 
1102   * @param[in] $name string Nom de la variable de configuration
1103   * @param[in] $val mixed Valeur de la variable de configuration
1104   *
1105   * @retval void
1106   */
1107   public static function addJSconfigParam($name,$val) {
1108     self :: $_JSconfigParams[$name]=$val;
1109   }
1110
1111  /**
1112   * Ajoute une feuille de style au chargement de la page
1113   *
1114   * Remarque : les scripts doivents Ãªtre dans le dossier LS_CSS_DIR.
1115   *
1116   * @param[in] $script Le nom du fichier css Ã  charger.
1117   *
1118   * @retval void
1119   */
1120   public static function addCssFile($file,$path=NULL) {
1121     $cssFile=array(
1122       'file' => $file,
1123       'path' => $path
1124     );
1125     self :: $CssFiles[$path.$file]=$cssFile;
1126   }
1127
1128  /**
1129   * Affiche le template Smarty
1130   *
1131   * Charge les dépendances et affiche le template Smarty
1132   *
1133   * @retval void
1134   */
1135   public static function displayTemplate() {
1136     // JS
1137     $JSscript_txt='';
1138     foreach ($GLOBALS['defaultJSscipts'] as $script) {
1139       $JSscript_txt.="<script src='".LS_JS_DIR.$script."' type='text/javascript'></script>\n";
1140     }
1141
1142     foreach (self :: $JSscripts as $script) {
1143       if (!$script['path']) {
1144         $script['path']=LS_JS_DIR;
1145       }
1146       else {
1147         $script['path'].='/';
1148       }
1149       $JSscript_txt.="<script src='".$script['path'].$script['file']."' type='text/javascript'></script>\n";
1150     }
1151
1152     $KAconf = LSconfig :: get('keepLSsessionActive');
1153     if ( 
1154           (
1155             (!isset(self :: $ldapServer['keepLSsessionActive']))
1156             &&
1157             (!($KAconf === false))
1158           )
1159           ||
1160           (self :: $ldapServer['keepLSsessionActive'])
1161         ) {
1162       self :: addJSconfigParam('keepLSsessionActive',ini_get('session.gc_maxlifetime'));
1163     }
1164
1165     $GLOBALS['Smarty'] -> assign('LSjsConfig',json_encode(self :: $_JSconfigParams));
1166     
1167     if (LSdebug) {
1168       $JSscript_txt.="<script type='text/javascript'>LSdebug_active = 1;</script>\n";
1169     }
1170     else {
1171       $JSscript_txt.="<script type='text/javascript'>LSdebug_active = 0;</script>\n";
1172     }
1173     
1174     $GLOBALS['Smarty'] -> assign('LSsession_js',$JSscript_txt);
1175
1176     // Css
1177     self :: addCssFile("LSdefault.css");
1178     $Css_txt='';
1179     foreach (self :: $CssFiles as $file) {
1180       if (!$file['path']) {
1181         $file['path']=LS_CSS_DIR.'/';
1182       }
1183       $Css_txt.="<link rel='stylesheet' type='text/css' href='".$file['path'].$file['file']."' />\n";
1184     }
1185     $GLOBALS['Smarty'] -> assign('LSsession_css',$Css_txt);
1186   
1187     if (isset(self :: $LSaccess[self :: $topDn])) {
1188       $GLOBALS['Smarty'] -> assign('LSaccess',self :: $LSaccess[self :: $topDn]);
1189     }
1190     
1191     // Niveau
1192     $listTopDn = self :: getSubDnLdapServer();
1193     if (is_array($listTopDn)) {
1194       asort($listTopDn);
1195       $GLOBALS['Smarty'] -> assign('label_level',self :: getSubDnLabel());
1196       $GLOBALS['Smarty'] -> assign('_refresh',_('Refresh'));
1197       $LSsession_topDn_index = array();
1198       $LSsession_topDn_name = array();
1199       foreach($listTopDn as $index => $name) {
1200         $LSsession_topDn_index[]  = $index;
1201         $LSsession_topDn_name[]   = $name;
1202       }
1203       $GLOBALS['Smarty'] -> assign('LSsession_subDn_indexes',$LSsession_topDn_index);
1204       $GLOBALS['Smarty'] -> assign('LSsession_subDn_names',$LSsession_topDn_name);
1205       $GLOBALS['Smarty'] -> assign('LSsession_subDn',self :: $topDn);
1206       $GLOBALS['Smarty'] -> assign('LSsession_subDnName',self :: getSubDnName());
1207     }
1208     
1209     $GLOBALS['Smarty'] -> assign('LSlanguages',self :: getLangList());
1210     $GLOBALS['Smarty'] -> assign('LSlang',self :: $lang);
1211     $GLOBALS['Smarty'] -> assign('LSencoding',self :: $encoding);
1212     $GLOBALS['Smarty'] -> assign('lang_label',_('Language'));
1213
1214     // Infos
1215     if((!empty($_SESSION['LSsession_infos']))&&(is_array($_SESSION['LSsession_infos']))) {
1216       $txt_infos="<ul>\n";
1217       foreach($_SESSION['LSsession_infos'] as $info) {
1218         $txt_infos.="<li>$info</li>\n";
1219       }
1220       $txt_infos.="</ul>\n";
1221       $GLOBALS['Smarty'] -> assign('LSinfos',$txt_infos);
1222       $_SESSION['LSsession_infos']=array();
1223     }
1224     
1225     if (self :: $ajaxDisplay) {
1226       $GLOBALS['Smarty'] -> assign('LSerror_txt',LSerror :: getErrors());
1227       $GLOBALS['Smarty'] -> assign('LSdebug_txt',LSdebug_print(true));
1228     }
1229     else {
1230       LSerror :: display();
1231       LSdebug_print();
1232     }
1233     if (!self :: $template)
1234       self :: setTemplate('empty.tpl');
1235       
1236     $GLOBALS['Smarty'] -> assign('connected_as',_("Connected as"));
1237     
1238     $GLOBALS['Smarty'] -> display(self :: $template);
1239   }
1240   
1241  /**
1242   * Défini que l'affichage se fera ou non via un retour Ajax
1243   * 
1244   * @param[in] $val boolean True pour que l'affichage se fasse par un retour
1245   *                         Ajax, false sinon
1246   * @retval void
1247   */
1248   public static function setAjaxDisplay($val=true) {
1249     self :: $ajaxDisplay = (boolean)$val;
1250   }
1251   
1252  /**
1253   * Affiche un retour Ajax
1254   *
1255   * @retval void
1256   */
1257   public static function displayAjaxReturn($data=array()) {
1258     if (isset($data['LSredirect']) && (!LSdebugDefined()) ) {
1259       echo json_encode($data);
1260       return;
1261     }
1262     
1263     $data['LSjsConfig'] = self :: $_JSconfigParams;
1264     
1265     // Infos
1266     if((!empty($_SESSION['LSsession_infos']))&&(is_array($_SESSION['LSsession_infos']))) {
1267       $txt_infos="<ul>\n";
1268       foreach($_SESSION['LSsession_infos'] as $info) {
1269         $txt_infos.="<li>$info</li>\n";
1270       }
1271       $txt_infos.="</ul>\n";
1272       $data['LSinfos'] = $txt_infos;
1273       $_SESSION['LSsession_infos']=array();
1274     }
1275     
1276     if (LSerror :: errorsDefined()) {
1277       $data['LSerror'] = LSerror :: getErrors();
1278     }
1279
1280     if (isset($_REQUEST['imgload'])) {
1281       $data['imgload'] = $_REQUEST['imgload'];
1282     }
1283
1284     if (LSdebugDefined()) {
1285       $data['LSdebug'] = LSdebug_print(true);
1286     }
1287
1288     echo json_encode($data);  
1289   }
1290  
1291  /**
1292   * Retournne un template Smarty compilé
1293   *
1294   * @param[in] string $template Le template à retourner
1295   * @param[in] array $variables Variables Smarty à assigner avant l'affichage
1296   * 
1297   * @retval string Le HTML compilé du template
1298   */
1299   public static function fetchTemplate($template,$variables=array()) {
1300     foreach($variables as $name => $val) {
1301       $GLOBALS['Smarty'] -> assign($name,$val);
1302     }
1303     return $GLOBALS['Smarty'] -> fetch($template);
1304   }
1305   
1306   /**
1307    * Charge les droits LS de l'utilisateur
1308    * 
1309    * @retval boolean True si le chargement Ã  réussi, false sinon.
1310    **/
1311   private static function loadLSprofiles() {
1312     if (is_array(self :: $ldapServer['LSprofiles'])) {
1313       foreach (self :: $ldapServer['LSprofiles'] as $profile => $profileInfos) {
1314         if (is_array($profileInfos)) {
1315           foreach ($profileInfos as $topDn => $rightsInfos) {
1316             /*
1317              * If $topDn == 'LSobject', we search for each LSobject type to find
1318              * all items on witch the user will have powers.
1319              */
1320             if ($topDn == 'LSobjects') {
1321               if (is_array($rightsInfos)) {
1322                 foreach ($rightsInfos as $LSobject => $listInfos) {
1323                   if (self :: loadLSobject($LSobject)) {
1324                     if ($object = new $LSobject()) {
1325                       if ($listInfos['filter']) {
1326                         $filter = self :: getLSuserObject() -> getFData($listInfos['filter']);
1327                       }
1328                       else {
1329                         $filter = $listInfos['attr'].'='.self :: getLSuserObject() -> getFData($listInfos['attr_value']);
1330                       }
1331                       $list = $object -> search($filter,$listInfos['basedn'],$listInfos['params']);
1332                       foreach($list as $obj) {
1333                         self :: $LSprofiles[$profile][] = $obj['dn'];
1334                       }
1335                     }
1336                     else {
1337                       LSdebug('Impossible de créer l\'objet de type : '.$LSobject);
1338                     }
1339                   }
1340                 }
1341               }
1342               else {
1343                 LSdebug('LSobjects => [] doit etre un tableau');
1344               }
1345             }
1346             else {
1347               if (is_array($rightsInfos)) {
1348                 foreach($rightsInfos as $dn => $conf) {
1349                   if ((isset($conf['attr'])) && (isset($conf['LSobject']))) {
1350                     if( self :: loadLSobject($conf['LSobject']) ) {
1351                       if ($object = new $conf['LSobject']()) {
1352                         if ($object -> loadData($dn)) {
1353                           $listDns=$object -> getValue($conf['attr']);
1354                           $valKey = (isset($conf['attr_value']))?$conf['attr_value']:'%{dn}';
1355                           $val = self :: getLSuserObject() -> getFData($valKey);
1356                           if (is_array($listDns)) {
1357                             if (in_array($val,$listDns)) {
1358                               self :: $LSprofiles[$profile][] = $topDn;
1359                             }
1360                           }
1361                         }
1362                         else {
1363                           LSdebug('Impossible de chargé le dn : '.$dn);
1364                         }
1365                       }
1366                       else {
1367                         LSdebug('Impossible de créer l\'objet de type : '.$conf['LSobject']);
1368                       }
1369                     }
1370                   }
1371                   else {
1372                     if (self :: $dn == $dn) {
1373                       self :: $LSprofiles[$profile][] = $topDn;
1374                     }
1375                   }
1376                 }
1377               }
1378               else {
1379                 if ( self :: $dn == $rightsInfos ) {
1380                   self :: $LSprofiles[$profile][] = $topDn;
1381                 }
1382               }
1383             } // fin else ($topDn == 'LSobjects')
1384           } // fin foreach($profileInfos)
1385         } // fin is_array($profileInfos)
1386       } // fin foreach LSprofiles
1387       LSdebug(self :: $LSprofiles);
1388       return true;
1389     }
1390     else {
1391       return;
1392     }
1393   }
1394   
1395   /**
1396    * Charge les droits d'accès de l'utilisateur pour construire le menu de l'interface
1397    *
1398    * @retval void
1399    */
1400   private static function loadLSaccess() {
1401     $LSaccess=array();
1402     if (is_array(self :: $ldapServer['subDn'])) {
1403       foreach(self :: $ldapServer['subDn'] as $name => $config) {
1404         if ($name=='LSobject') {
1405           if (is_array($config)) {
1406
1407             // Définition des subDns 
1408             foreach($config as $objectType => $objectConf) {
1409               if (self :: loadLSobject($objectType)) {
1410                 if ($subdnobject = new $objectType()) {
1411                   $tbl = $subdnobject -> getSelectArray();
1412                   if (is_array($tbl)) {
1413                     // Définition des accès
1414                     $access=array();
1415                     if (is_array($objectConf['LSobjects'])) {
1416                       foreach($objectConf['LSobjects'] as $type) {
1417                         if (self :: loadLSobject($type)) {
1418                           if (self :: canAccess($type)) {
1419                             $access[$type] = LSconfig :: get('LSobjects.'.$type.'.label');
1420                           }
1421                         }
1422                       }
1423                     }
1424                     foreach($tbl as $dn => $dn_name) {
1425                       $LSaccess[$dn]=$access;
1426                     }
1427                   }
1428                 }
1429               }
1430             }
1431           }
1432         }
1433         else {
1434           if ((isCompatibleDNs(self :: $ldapServer['ldap_config']['basedn'],$config['dn']))&&($config['dn']!='')) {
1435             $access=array();
1436             if (is_array($config['LSobjects'])) {
1437               foreach($config['LSobjects'] as $objectType) {
1438                 if (self :: loadLSobject($objectType)) {
1439                   if (self :: canAccess($objectType)) {
1440                     $access[$objectType] = LSconfig :: get('LSobjects.'.$objectType.'.label');
1441                   }
1442                 }
1443               }
1444             }
1445             $LSaccess[$config['dn']]=$access;
1446           }
1447         }
1448       }
1449     }
1450     else {
1451       if(is_array(self :: $ldapServer['LSaccess'])) {
1452         $access=array();
1453         foreach(self :: $ldapServer['LSaccess'] as $objectType) {
1454           if (self :: loadLSobject($objectType)) {
1455             if (self :: canAccess($objectType)) {
1456                 $access[$objectType] = LSconfig :: get('LSobjects.'.$objectType.'.label');
1457             }
1458           }
1459         }
1460         $LSaccess[self :: $topDn] = $access;
1461       }
1462     }
1463     foreach($LSaccess as $dn => $access) {
1464       $LSaccess[$dn] = array_merge(
1465         array(
1466           'SELF' => 'My account'
1467         ),
1468         $access
1469       );
1470     }
1471     
1472     self :: $LSaccess = $LSaccess;
1473     $_SESSION['LSsession']['LSaccess'] = $LSaccess;
1474   }
1475   
1476   /**
1477    * Dit si l'utilisateur est du profil pour le DN spécifié
1478    *
1479    * @param[in] string $profile de l'objet
1480    * @param[in] string $dn DN de l'objet
1481    * 
1482    * @retval boolean True si l'utilisateur est du profil sur l'objet, false sinon.
1483    */
1484   public static function isLSprofile($dn,$profile) {
1485     if (is_array(self :: $LSprofiles[$profile])) {
1486       foreach(self :: $LSprofiles[$profile] as $topDn) {
1487         if($dn == $topDn) {
1488           return true;
1489         }
1490         else if ( isCompatibleDNs($dn,$topDn) ) {
1491           return true;
1492         }
1493       }
1494     }
1495     return;
1496   }
1497   
1498   /**
1499    * Retourne qui est l'utilisateur par rapport Ã  l'object
1500    *
1501    * @param[in] string Le DN de l'objet
1502    * 
1503    * @retval string 'admin'/'self'/'user' pour Admin , l'utilisateur lui même ou un simple utilisateur
1504    */
1505   public static function whoami($dn) {
1506     $retval = array('user');
1507     
1508     foreach(self :: $LSprofiles as $profile => $infos) {
1509       if(self :: isLSprofile($dn,$profile)) {
1510        $retval[]=$profile;
1511       }
1512     }
1513     
1514     if (self :: $dn == $dn) {
1515       $retval[]='self';
1516     }
1517     
1518     return $retval;
1519   }
1520   
1521   /**
1522    * Retourne le droit de l'utilisateur Ã  accèder Ã  un objet
1523    * 
1524    * @param[in] string $LSobject Le type de l'objet
1525    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1526    * @param[in] string $right Le type de droit d'accès Ã  tester ('r'/'w')
1527    * @param[in] string $attr Le nom de l'attribut auquel on test l'accès
1528    *
1529    * @retval boolean True si l'utilisateur a accès, false sinon
1530    */
1531   public static function canAccess($LSobject,$dn=NULL,$right=NULL,$attr=NULL) {
1532     if (!self :: loadLSobject($LSobject)) {
1533       return;
1534     }
1535     if ($dn) {
1536       $whoami = self :: whoami($dn);
1537       if ($dn==self :: getLSuserObject() -> getValue('dn')) {
1538         if (!self :: in_menu('SELF')) {
1539           return;
1540         }
1541       }
1542       else {
1543         $obj = new $LSobject();
1544         $obj -> dn = $dn;
1545         if (!self :: in_menu($LSobject,$obj -> getSubDnValue())) {
1546           return;
1547         }
1548       }
1549     }
1550     else {
1551       $objectdn=LSconfig :: get('LSobjects.'.$LSobject.'.container_dn').','.self :: $topDn;
1552       $whoami = self :: whoami($objectdn);
1553     }
1554     
1555     // Pour un attribut particulier
1556     if ($attr) {
1557       if ($attr=='rdn') {
1558         $attr=LSconfig :: get('LSobjects.'.$LSobject.'.rdn');
1559       }
1560       if (!is_array(LSconfig :: get('LSobjects.'.$LSobject.'.attrs.'.$attr))) {
1561         return;
1562       }
1563
1564       $r = 'n';
1565       foreach($whoami as $who) {
1566         $nr = LSconfig :: get('LSobjects.'.$LSobject.'.attrs.'.$attr.'.rights.'.$who);
1567         if($nr == 'w') {
1568           $r = 'w';
1569         }
1570         else if($nr == 'r') {
1571           if ($r=='n') {
1572             $r='r';
1573           }
1574         }
1575       }
1576       
1577       if (($right=='r')||($right=='w')) {
1578         if ($r==$right) {
1579           return true;
1580         }
1581         return;
1582       }
1583       else {
1584         if ( ($r=='r') || ($r=='w') ) {
1585           return true;
1586         }
1587         return;
1588       }
1589     }
1590     
1591     // Pour un attribut quelconque
1592     $attrs_conf=LSconfig :: get('LSobjects.'.$LSobject.'.attrs');
1593     if (is_array($attrs_conf)) {
1594       if (($right=='r')||($right=='w')) {
1595         foreach($whoami as $who) {
1596           foreach ($attrs_conf as $attr_name => $attr_config) {
1597             if ($attr_config['rights'][$who]==$right) {
1598               return true;
1599             }
1600           }
1601         }
1602       }
1603       else {
1604         foreach($whoami as $who) {
1605           foreach ($attrs_conf as $attr_name => $attr_config) {
1606             if ( ($attr_config['rights'][$who]=='r') || ($attr_config['rights'][$who]=='w') ) {
1607               return true;
1608             }
1609           }
1610         }
1611       }
1612     }
1613     return;
1614   }
1615   
1616   /**
1617    * Retourne le droit de l'utilisateur Ã  editer Ã  un objet
1618    * 
1619    * @param[in] string $LSobject Le type de l'objet
1620    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1621    * @param[in] string $attr Le nom de l'attribut auquel on test l'accès
1622    *
1623    * @retval boolean True si l'utilisateur a accès, false sinon
1624    */
1625   public static function canEdit($LSobject,$dn=NULL,$attr=NULL) {
1626     return self :: canAccess($LSobject,$dn,'w',$attr);
1627   }
1628
1629   /**
1630    * Retourne le droit de l'utilisateur Ã  supprimer un objet
1631    * 
1632    * @param[in] string $LSobject Le type de l'objet
1633    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1634    *
1635    * @retval boolean True si l'utilisateur a accès, false sinon
1636    */  
1637   public static function canRemove($LSobject,$dn) {
1638     return self :: canAccess($LSobject,$dn,'w','rdn');
1639   }
1640   
1641   /**
1642    * Retourne le droit de l'utilisateur Ã  créer un objet
1643    * 
1644    * @param[in] string $LSobject Le type de l'objet
1645    *
1646    * @retval boolean True si l'utilisateur a accès, false sinon
1647    */    
1648   public static function canCreate($LSobject) {
1649     return self :: canAccess($LSobject,NULL,'w','rdn');
1650   }
1651   
1652   /**
1653    * Retourne le droit de l'utilisateur Ã  gérer la relation d'objet
1654    * 
1655    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1656    * @param[in] string $LSobject Le type de l'objet
1657    * @param[in] string $relationName Le nom de la relation avec l'objet
1658    * @param[in] string $right Le type de droit a vérifier ('r' ou 'w')
1659    *
1660    * @retval boolean True si l'utilisateur a accès, false sinon
1661    */
1662   public static function relationCanAccess($dn,$LSobject,$relationName,$right=NULL) {
1663     $relConf=LSconfig :: get('LSobjects.'.$LSobject.'.LSrelation.'.$relationName);
1664     if (!is_array($relConf))
1665       return;
1666     $whoami = self :: whoami($dn);
1667
1668     if (($right=='w') || ($right=='r')) {
1669       $r = 'n';
1670       foreach($whoami as $who) {
1671         $nr = $relConf['rights'][$who];
1672         if($nr == 'w') {
1673           $r = 'w';
1674         }
1675         else if($nr == 'r') {
1676           if ($r=='n') {
1677             $r='r';
1678           }
1679         }
1680       }
1681       
1682       if ($r == $right) {
1683         return true;
1684       }
1685     }
1686     else {
1687       foreach($whoami as $who) {
1688         if (($relConf['rights'][$who] == 'w') || ($relConf['rights'][$who] == 'r')) {
1689           return true;
1690         }
1691       }
1692     }
1693     return;
1694   }
1695
1696   /**
1697    * Retourne le droit de l'utilisateur Ã  modifier la relation d'objet
1698    * 
1699    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1700    * @param[in] string $LSobject Le type de l'objet
1701    * @param[in] string $relationName Le nom de la relation avec l'objet
1702    *
1703    * @retval boolean True si l'utilisateur a accès, false sinon
1704    */  
1705   public static function relationCanEdit($dn,$LSobject,$relationName) {
1706     return self :: relationCanAccess($dn,$LSobject,$relationName,'w');
1707   }
1708
1709   /**
1710    * Ajoute un fichier temporaire
1711    * 
1712    * @author Benjamin Renard <brenard@easter-eggs.com>
1713    * 
1714    * @retval void
1715    **/
1716   public static function addTmpFile($value,$filePath) {
1717     $hash = mhash(MHASH_MD5,$value);
1718     self :: $tmp_file[$filePath] = $hash;
1719     $_SESSION['LSsession']['tmp_file'][$filePath] = $hash;
1720   }
1721   
1722   /**
1723    * Retourne le chemin du fichier temporaire si l'existe
1724    * 
1725    * @author Benjamin Renard <brenard@easter-eggs.com>
1726    * 
1727    * @param[in] $value La valeur du fichier
1728    * 
1729    * @retval mixed 
1730    **/
1731   public static function tmpFileExist($value) {
1732     $hash = mhash(MHASH_MD5,$value);
1733     foreach(self :: $tmp_file as $filePath => $contentHash) {
1734       if ($hash == $contentHash) {
1735         return $filePath;
1736       }
1737     }
1738     return false;
1739   }
1740   
1741   /**
1742    * Retourne le chemin du fichier temporaire
1743    * 
1744    * Retourne le chemin du fichier temporaire qu'il créera Ã  partir de la valeur
1745    * s'il n'existe pas déjà.
1746    * 
1747    * @author Benjamin Renard <brenard@easter-eggs.com>
1748    * 
1749    * @param[in] $value La valeur du fichier
1750    * 
1751    * @retval mixed 
1752    **/
1753   public static function getTmpFile($value) {
1754     $exist = self :: tmpFileExist($value);
1755     if (!$exist) {
1756       $img_path = LS_TMP_DIR .rand().'.tmp';
1757       $fp = fopen($img_path, "w");
1758       fwrite($fp, $value);
1759       fclose($fp);
1760       self :: addTmpFile($value,$img_path);
1761       return $img_path;
1762     }
1763     else {
1764       return $exist;
1765     }
1766   }
1767   
1768   /**
1769    * Supprime les fichiers temporaires
1770    * 
1771    * @author Benjamin Renard <brenard@easter-eggs.com>
1772    * 
1773    * @retval void
1774    **/
1775   public static function deleteTmpFile($filePath=NULL) {
1776     if ($filePath) {
1777         @unlink($filePath);
1778         unset(self :: $tmp_file[$filePath]);
1779         unset($_SESSION['LSsession']['tmp_file'][$filePath]);
1780     }
1781     else {
1782       foreach(self :: $tmp_file as $file => $content) {
1783         @unlink($file);
1784       }
1785       self :: $tmp_file = array();
1786       $_SESSION['LSsession']['tmp_file'] = array();
1787     }
1788   }
1789
1790   /**
1791    * Retourne true si le cache des droits est activé
1792    *
1793    * @author Benjamin Renard <brenard@easter-eggs.com>
1794    * 
1795    * @retval boolean True si le cache des droits est activé, false sinon.
1796    */
1797   public static function cacheLSprofiles() {
1798     return ( (LSconfig :: get('cacheLSprofiles')) || (self :: $ldapServer['cacheLSprofiles']) );
1799   }
1800
1801   /**
1802    * Retourne true si le cache des subDn est activé
1803    *
1804    * @author Benjamin Renard <brenard@easter-eggs.com>
1805    * 
1806    * @retval boolean True si le cache des subDn est activé, false sinon.
1807    */
1808   public static function cacheSudDn() {
1809     return ( (LSconfig :: get('cacheSubDn')) || (self :: $ldapServer['cacheSubDn']));
1810   }
1811   
1812   /**
1813    * Retourne true si le cache des recherches est activé
1814    *
1815    * @author Benjamin Renard <brenard@easter-eggs.com>
1816    * 
1817    * @retval boolean True si le cache des recherches est activé, false sinon.
1818    */
1819   public static function cacheSearch() {
1820     return ( (LSconfig :: get('cacheSearch')) || (self :: $ldapServer['cacheSearch']));
1821   }
1822   
1823   /**
1824    * Retourne le label des niveaux pour le serveur ldap courant
1825    * 
1826    * @author Benjamin Renard <brenard@easter-eggs.com>
1827    * 
1828    * @retval string Le label des niveaux pour le serveur ldap dourant
1829    */
1830   public static function getSubDnLabel() {
1831     return (self :: $ldapServer['subDnLabel']!='')?__(self :: $ldapServer['subDnLabel']):_('Level');
1832   }
1833   
1834   /**
1835    * Retourne le nom du subDn
1836    * 
1837    * @param[in] $subDn string subDn
1838    * 
1839    * @retval string Le nom du subDn ou '' sinon
1840    */
1841   public static function getSubDnName($subDn=false) {
1842     if (!$subDn) {
1843       $subDn = self :: $topDn;
1844     }
1845     if (self :: getSubDnLdapServer()) {
1846       if (isset(self :: $_subDnLdapServer[self :: $ldapServerId][$subDn])) {
1847         return self :: $_subDnLdapServer[self :: $ldapServerId][$subDn];
1848       }
1849     }
1850     return '';
1851   }
1852
1853   /**
1854    * L'objet est t-il utilisé pour listé les subDnS
1855    * 
1856    * @param[in] $type string Le type d'objet
1857    * 
1858    * @retval boolean true si le type d'objet est un subDnObject, false sinon
1859    */
1860   public static function isSubDnLSobject($type) {
1861     $result = false;
1862     if (is_array(self :: $ldapServer['subDn']['LSobject'])) {
1863       foreach(self :: $ldapServer['subDn']['LSobject'] as $key => $value) {
1864         if ($key==$type) {
1865           $result=true;
1866         }
1867       }
1868     }
1869     return $result;
1870   }
1871   
1872   /**
1873    * Indique si un type d'objet est dans le menu courant
1874    * 
1875    * @retval boolean true si le type d'objet est dans le menu, false sinon
1876    */
1877   public static function in_menu($LSobject,$topDn=NULL) {
1878     if (!$topDn) {
1879       $topDn=self :: $topDn;
1880     }
1881     return isset(self :: $LSaccess[$topDn][$LSobject]);
1882   }
1883   
1884   /**
1885    * Indique si le serveur LDAP courant a des subDn
1886    * 
1887    * @retval boolean true si le serveur LDAP courant a des subDn, false sinon
1888    */
1889   public static function haveSubDn() {
1890     return (is_array(self :: $ldapServer['subDn']));
1891   }
1892
1893   /**
1894    * Ajoute une information à afficher
1895    * 
1896    * @param[in] $msg string Le message à afficher
1897    * 
1898    * @retval void
1899    */
1900   public static function addInfo($msg) {
1901     $_SESSION['LSsession_infos'][]=$msg;
1902   }
1903   
1904   /**
1905    * Redirection de l'utilisateur vers une autre URL
1906    * 
1907    * @param[in] $url string L'URL
1908    * @param[in] $exit boolean Si true, l'execution script s'arrête après la redirection
1909    * 
1910    * @retval void
1911    */  
1912   public static function redirect($url,$exit=true) {
1913     $GLOBALS['Smarty'] -> assign('url',$url);
1914     $GLOBALS['Smarty'] -> display('redirect.tpl');
1915     if ($exit) {
1916       exit();
1917     }
1918   }
1919   
1920   /**
1921    * Retourne l'adresse mail d'emission configurée pour le serveur courant
1922    * 
1923    * @retval string Adresse mail d'emission
1924    */
1925   public static function getEmailSender() {
1926     return self :: $ldapServer['emailSender'];  
1927   }
1928   
1929   /**
1930    * Ajout d'une information d'aide
1931    * 
1932    * @param[in] $group string Le nom du groupe d'infos dans lequels ajouter
1933    *                          celle-ci
1934    * @param[in] $infos array  Tableau array(name => value) des infos
1935    * 
1936    * @retval void
1937    */
1938   public static function addHelpInfos($group,$infos) {
1939     if (is_array($infos)) {
1940       if (is_array(self :: $_JSconfigParams['helpInfos'][$group])) {
1941         self :: $_JSconfigParams['helpInfos'][$group] = array_merge(self :: $_JSconfigParams['helpInfos'][$group],$infos);
1942       }
1943       else {
1944         self :: $_JSconfigParams['helpInfos'][$group] = $infos;
1945       }
1946     }
1947   }
1948   
1949  /**
1950   * Défini les codes erreur relative à la classe LSsession
1951   * 
1952   * @retval void
1953   */  
1954   private static function defineLSerrors() {
1955     /*
1956      * Error Codes
1957      */
1958     LSerror :: defineError('LSsession_01',
1959     _("LSsession : The constant %{const} is not defined.")
1960     );
1961     LSerror :: defineError('LSsession_02',
1962     _("LSsession : The %{addon} support is uncertain. Verify system compatibility and the add-on configuration.")
1963     );
1964     LSerror :: defineError('LSsession_03',
1965     _("LSsession : LDAP server's configuration data are invalid. Can't connect.")
1966     );
1967     LSerror :: defineError('LSsession_04',
1968     _("LSsession : Failed to load LSobject type %{type} : unknon type.")
1969     );
1970     // no longer used
1971     /*LSerror :: defineError(1005,
1972     _("LSsession : Object type use for authentication is unknow (%{type}).")
1973     );*/
1974     LSerror :: defineError('LSsession_06',
1975     _("LSsession : Login or password incorrect.")
1976     );
1977     LSerror :: defineError('LSsession_07',
1978     _("LSsession : Impossible to identify you : Duplication of identities.")
1979     );
1980     LSerror :: defineError('LSsession_08',
1981     _("LSsession : Can't load Smarty template engine.")
1982     );
1983     LSerror :: defineError('LSsession_09',
1984     _("LSsession : Can't connect to LDAP server.")
1985     );
1986     LSerror :: defineError('LSsession_10',
1987     _("LSsession : Could not load type of identifiable objects.")
1988     );
1989     LSerror :: defineError('LSsession_11',
1990     _("LSsession : Your are not authorized to do this action.")
1991     );
1992     LSerror :: defineError('LSsession_12',
1993     _("LSsession : Some informations are missing to display this page.")
1994     );
1995     // 13 -> 16 : not yet used
1996     LSerror :: defineError('LSsession_17',
1997     _("LSsession : Error during creation of list of levels. Contact administrators. (Code : %{code})")
1998     );
1999     LSerror :: defineError('LSsession_18',
2000     _("LSsession : The password recovery is disabled for this LDAP server.")
2001     );
2002     LSerror :: defineError('LSsession_19',
2003     _("LSsession : Some informations are missing to recover your password. Contact administrators.")
2004     );
2005     LSerror :: defineError('LSsession_20',
2006     _("LSsession : Error during password recovery. Contact administrators.(Step : %{step})")
2007     );
2008     // 21 : not yet used
2009     LSerror :: defineError('LSsession_22',
2010     _("LSsession : problem during initialisation.")
2011     );
2012
2013
2014     // LSrelations
2015     LSerror :: defineError('LSrelations_01',
2016     _("LSrelation : The listing function for the relation %{relation} is unknow.")
2017     );
2018     LSerror :: defineError('LSrelations_02',
2019     _("LSrelation : The update function of the relation %{relation} is unknow.")
2020     );
2021     LSerror :: defineError('LSrelations_03',
2022     _("LSrelation : Error during relation update of the relation %{relation}.")
2023     );
2024     LSerror :: defineError('LSrelations_04',
2025     _("LSrelation : Object type %{LSobject} unknow (Relation : %{relation}).")
2026     );
2027     LSerror :: defineError('LSrelations_05',
2028     _("LSrelation : Some parameters are missing in the call of methods to handle standard relations (Method : %{meth}).")
2029     );
2030   }
2031
2032   public static function ajax_onLdapServerChangedLogin(&$data) {  
2033     if ( isset($_REQUEST['server']) ) {
2034       self :: setLdapServer($_REQUEST['server']);
2035       $data = array();
2036       if ( self :: LSldapConnect() ) {
2037         session_start();
2038         if (isset($_SESSION['LSsession_topDn'])) {
2039           $sel = $_SESSION['LSsession_topDn'];
2040         }
2041         else {
2042           $sel = NULL;
2043         }
2044         $list = self :: getSubDnLdapServerOptions($sel);
2045         if (is_string($list)) {
2046           $data['list_topDn'] = "<select name='LSsession_topDn' id='LSsession_topDn'>".$list."</select>";
2047           $data['subDnLabel'] = self :: getSubDnLabel();
2048         }
2049       }
2050       $data['recoverPassword'] = isset(self :: $ldapServer['recoverPassword']);
2051     }
2052   }
2053   
2054   public static function ajax_onLdapServerChangedRecoverPassword(&$data) {  
2055     if ( isset($_REQUEST['server']) ) {
2056       self :: setLdapServer($_REQUEST['server']);
2057       $data=array('recoverPassword' => isset(self :: $ldapServer['recoverPassword']));
2058     }
2059   }
2060 }
2061
2062 ?>