KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jahia > services > usermanager > JahiaUserManagerLDAPProvider


1 /*
2  * ____.
3  * __/\ ______| |__/\. _______
4  * __ .____| | \ | +----+ \
5  * _______| /--| | | - \ _ | : - \_________
6  * \\______: :---| : : | : | \________>
7  * |__\---\_____________:______: :____|____:_____\
8  * /_____|
9  *
10  * . . . i n j a h i a w e t r u s t . . .
11  *
12  *
13  *
14  * ----- BEGIN LICENSE BLOCK -----
15  * Version: JCSL 1.0
16  *
17  * The contents of this file are subject to the Jahia Community Source License
18  * 1.0 or later (the "License"); you may not use this file except in
19  * compliance with the License. You may obtain a copy of the License at
20  * http://www.jahia.org/license
21  *
22  * Software distributed under the License is distributed on an "AS IS" basis,
23  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
24  * for the rights, obligations and limitations governing use of the contents
25  * of the file. The Original and Upgraded Code is the Jahia CMS and Portal
26  * Server. The developer of the Original and Upgraded Code is JAHIA Ltd. JAHIA
27  * Ltd. owns the copyrights in the portions it created. All Rights Reserved.
28  *
29  * The Shared Modifications are Jahia View Helper.
30  *
31  * The Developer of the Shared Modifications is Jahia Solution S�rl.
32  * Portions created by the Initial Developer are Copyright (C) 2002 by the
33  * Initial Developer. All Rights Reserved.
34  *
35  * Contributor(s):
36  * 29-AUG-2003, Jahia Solutions Sarl, Fulco Houkes
37  *
38  * ----- END LICENSE BLOCK -----
39  */

40
41
42 package org.jahia.services.usermanager;
43
44 import java.io.File JavaDoc;
45 import java.io.FileInputStream JavaDoc;
46 import java.io.FileNotFoundException JavaDoc;
47 import java.io.IOException JavaDoc;
48 import java.sql.Connection JavaDoc;
49 import java.sql.ResultSet JavaDoc;
50 import java.sql.SQLException JavaDoc;
51 import java.sql.Statement JavaDoc;
52 import java.util.*;
53 import javax.naming.*;
54 import javax.naming.directory.Attribute JavaDoc;
55 import javax.naming.directory.Attributes JavaDoc;
56 import javax.naming.directory.DirContext JavaDoc;
57 import javax.naming.directory.InitialDirContext JavaDoc;
58 import javax.naming.directory.SearchControls JavaDoc;
59 import javax.naming.directory.SearchResult JavaDoc;
60
61 import org.jahia.data.JahiaDBDOMObject;
62 import org.jahia.data.JahiaDOMObject;
63 import org.jahia.exceptions.JahiaException;
64 import org.jahia.exceptions.JahiaInitializationException;
65 import org.jahia.exceptions.database.JahiaDatabaseException;
66 import org.jahia.registries.ServicesRegistry;
67 import org.jahia.services.acl.JahiaACLManagerService;
68 import org.jahia.services.cache.Cache;
69 import org.jahia.services.cache.CacheFactory;
70 import org.jahia.services.database.JahiaIncrementorsDBService;
71 import org.jahia.settings.SettingsBean;
72 import org.jahia.utils.JahiaTools;
73
74 /**
75  * An LDAP provider implementation for the management of users. This class works
76  * with another UserLDAPService in org.jahia.services.ldap that contains the
77  * configuration of the LDAP repository for user management.
78  *
79  * @author Serge Huber
80  * @version 2.0
81  * @todo Khue suggested that we might want to use the site ID to use multiple
82  * connection to different LDAP repository. This is a very interesting suggestion
83  * but is not yet implemented.
84  */

85 public class JahiaUserManagerLDAPProvider extends JahiaUserManagerProvider {
86
87     /** logging */
88     private static org.apache.log4j.Logger logger =
89         org.apache.log4j.Logger.getLogger(JahiaUserManagerLDAPProvider.class);
90
91     private static final String JavaDoc USERNAME_PROPERTY_NAME = "username";
92
93     private static String JavaDoc DEFAULT_CONFIGURATION_FILE = "users.ldap.properties";
94
95     private static String JavaDoc CONTEXT_FACTORY_PROP = "users.ldap.context.factory";
96     private static String JavaDoc LDAP_URL_PROP = "users.ldap.url";
97     private static String JavaDoc AUTHENTIFICATION_MODE_PROP =
98         "users.ldap.authentification.mode";
99     private static String JavaDoc PUBLIC_BIND_DN_PROP = "users.ldap.public.bind.dn";
100     private static String JavaDoc PUBLIC_BIND_PASSWORD_PROP =
101         "users.ldap.public.bind.password";
102
103     private static String JavaDoc UID_SEARCH_ATTRIBUTE_PROP =
104         "users.ldap.uid.search.attribute";
105     private static String JavaDoc UID_SEARCH_NAME_PROP = "users.ldap.uid.search.name";
106     private static String JavaDoc USERS_OBJECTCLASS_ATTRIBUTE =
107         "users.ldap.search.objectclass";
108
109     private static String JavaDoc LDAP_REFFERAL_PROP = "users.ldap.refferal";
110     private static String JavaDoc SEARCH_COUNT_LIMIT_PROP =
111         "users.ldap.search.countlimit";
112     private static String JavaDoc SEARCH_WILDCARD_ATTRIBUTE_LIST =
113         "users.ldap.search.wildcards.attributes";
114
115     private static String JavaDoc LDAP_USERNAME_ATTRIBUTE =
116         "users.ldap.username.attribute.map";
117
118     private Properties ldapProperties = null;
119
120     private DirContext JavaDoc publicCtx = null;
121     private boolean connectedToPublic = false;
122     private Vector searchWildCardAttributeList = null;
123
124     public static final String JavaDoc PROVIDER_NAME = "ldap";
125
126     private final String JavaDoc MSG_INTERNAL_ERROR = new String JavaDoc(
127         "JahiaUserManagerLDAPProvider");
128
129     private static JahiaUserManagerLDAPProvider instance;
130
131     // the LDAP User cache name.
132
public static final String JavaDoc LDAP_USER_CACHE = "LDAPUsersCache";
133
134     /** the overall provider User cache name. */
135     public static final String JavaDoc PROVIDERS_USER_CACHE = "ProvidersUsersCache";
136
137     private Cache mUserCache;
138     private Cache mProvidersUserCache;
139
140     //(-PredragV-) private JahiaGroupManagerDBService mGroupService = null;
141
private JahiaGroupManagerRoutingService mGroupService = null;
142     private JahiaACLManagerService mACLService = null;
143     private JahiaIncrementorsDBService mIncrementorService = null;
144
145     /** Root user unique identification number */
146     public static final int ROOT_USER_ID = 0;
147
148     /** Guest user unique identification number */
149     public static final int GUEST_USER_ID = 1;
150
151     /**
152      * Default constructor
153      *
154      * @throws JahiaException The user manager need some Jahia services to be
155      * able to run correctly. If one of these services are not instanciated then a
156      * JahiaException exception is thrown.
157      */

158     protected JahiaUserManagerLDAPProvider ()
159         throws JahiaException {
160         mUserCache = CacheFactory.createCache(LDAP_USER_CACHE);
161         mProvidersUserCache = CacheFactory.createCache(PROVIDERS_USER_CACHE);
162
163         ServicesRegistry registry = ServicesRegistry.getInstance();
164         if (registry != null) {
165             mIncrementorService = registry.getJahiaIncrementorsDBService();
166             if (mIncrementorService == null) {
167                 throw new JahiaException(MSG_INTERNAL_ERROR,
168                                          "User manager could not get the Incrementors DB Service instance.",
169                                          JahiaException.SERVICE_ERROR,
170                                          JahiaException.CRITICAL_SEVERITY);
171             }
172
173             mGroupService =
174                 (JahiaGroupManagerRoutingService) registry.
175                 getJahiaGroupManagerService();
176             //(-PredragV-) mGroupService = (JahiaGroupManagerDBService)registry.getJahiaGroupManagerService();
177
if (mGroupService == null) {
178                 throw new JahiaException(MSG_INTERNAL_ERROR,
179                                          "User manager could not get the Group Manager Service instance.",
180                                          JahiaException.SERVICE_ERROR,
181                                          JahiaException.CRITICAL_SEVERITY);
182             }
183
184             mACLService = registry.getJahiaACLManagerService();
185             if (mACLService == null) {
186                 throw new JahiaException(MSG_INTERNAL_ERROR,
187                                          "User manager could not get the ACL Manager Service instance.",
188                                          JahiaException.SERVICE_ERROR,
189                                          JahiaException.CRITICAL_SEVERITY);
190             }
191         } else {
192             throw new JahiaException(MSG_INTERNAL_ERROR,
193                                      "User manager could not get the Service Registry instance.",
194                                      JahiaException.REGISTRY_ERROR,
195                                      JahiaException.CRITICAL_SEVERITY);
196         }
197     }
198
199     /**
200      * Create an new instance of the User Manager Service if the instance do not
201      * exist, or return the existing instance.
202      *
203      * @return Return the instance of the User Manager Service.
204      */

205     public static JahiaUserManagerLDAPProvider getInstance () {
206         if (instance == null) {
207             try {
208                 instance = new JahiaUserManagerLDAPProvider();
209             } catch (JahiaException ex) {
210                 logger.error(
211                     "Could not create an instance of the JahiaUserManagerLDAPProvider class");
212             }
213         }
214         return instance;
215     }
216
217     /**
218      * This is the method that creates a new user in the system, with all the
219      * specified attributes.
220      *
221      * @param name User login name.
222      * @param password User password
223      * @param userKey User identifier on the Jahia installation
224      * @param siteID Identifier of the site this user is defined in
225      * @param properties User additional parameters. If the user has no additional
226      * attributes, give a NULL pointer to this parameter.
227      *
228      * @return a JahiaUser object containing an instance of the created user,
229      * in this case a instance of JahiaLDAPUser.
230      */

231     public synchronized JahiaUser createUser (String JavaDoc name,
232                                               String JavaDoc password,
233                                               String JavaDoc userKey,
234                                               int siteID,
235                                               Properties properties) {
236         if (!isNameValid(name)) {
237             return null;
238         }
239
240         // try to avoid a NullPointerException
241
if (!isNameValid(password)) {
242             return null;
243         }
244
245         // Check first if the user already exists in the database.
246
if (userExists(siteID, name)) {
247             return null;
248         }
249
250         // get the user and guest group
251
JahiaGroup usersGroup = mGroupService.getUsersGroup(siteID);
252         JahiaGroup guestGroup = mGroupService.getGuestGroup(siteID);
253         if ( (usersGroup == null) || (guestGroup == null)) {
254             logger.debug(
255                 "createUser() : could not get the [users] or/and [guest] group instance.");
256             return null;
257         }
258
259         // Get the next available user ID
260
int userID;
261         try {
262             userID = mIncrementorService.autoIncrement("jahia_users");
263             logger.debug("got new user ID = [" + Integer.toString(userID) + "]");
264         } catch (JahiaException ex) {
265             logger.warn(
266                 "Exception !!! Could not get a new user ID from the incrementor DB");
267             return null;
268         }
269
270         // Encrypt the password
271
password = encryptPassword(password);
272         if (password == null) {
273             logger.debug("createUser() could not encrypt the user password.");
274             return null;
275         }
276
277         // Create the user
278
JahiaLDAPUser user = null;
279         user = new JahiaLDAPUser(userID, name, password, userKey, siteID,
280                                  new UserProperties(properties, true), null);
281
282         if (user == null) {
283             logger.debug(
284                 "createUser() couldn't create and instance of JahiaUser class");
285             return null;
286         }
287
288         // add the user into the cache if the user could be added into the database.
289
if (addUserIntoLDAP (userID, name, password, userKey, siteID, properties)) {
290             mUserCache.put ("k"+user.getUserKey(), new JahiaUserWrapper(user));
291
292             logger.debug ("User [" + name + "] was added into the database and in the cache");
293
294             /* 2004-16-06 : update by EP
295             new cache to populate : cross providers only based upon names... */

296             mProvidersUserCache.put("k"+user.getUserKey(), user);
297
298             mUserCache.put("n"+user.getSiteID()+"_"+user.getUsername(), new JahiaUserWrapper(user));
299             mProvidersUserCache.put("n"+user.getSiteID()+"_"+user.getUsername(), user);
300
301             // by default each user is added to the users and guest group
302
usersGroup.addMember (user);
303             guestGroup.addMember (user);
304         } else {
305             logger.debug ("Could not add the user [" + name + "] in the database!!");
306             user = null;
307         }
308
309         return user;
310     }
311
312     //--------------------------------------------------------------------------
313
/**
314      * This method removes a user from the system. All the user's attributes are
315      * remove, and also all the related objects belonging to the user. On success,
316      * true is returned and the user parameter is not longer valid. Return false
317      * on any failure.
318      *
319      * @param user reference on the user to be deleted.
320      *
321      * @return Return true on success, or false on any failure.
322      */

323     public synchronized boolean deleteUser (JahiaUser user) {
324         return false;
325             /** @todo not yet supported since the LDAP is read-only. */
326     }
327
328     //--------------------------------------------------------------------------
329
/**
330      * Load all the user data and attributes. On success a reference on the user
331      * is returned, otherwise NULL is returned.
332      *
333      * @param userKey User's identification name.
334      *
335      * @return a reference on a new created jahiaUser object.
336      */

337     public JahiaUser lookupUser (String JavaDoc userKey) {
338
339         /* 2004-16-06 : update by EP
340         new cache to use : cross providers only based upon names... */

341         JahiaUser user = (JahiaUser)mProvidersUserCache.get ("k"+userKey);
342
343         // 2004-23-07 : use wrappers
344
if (user == null) {
345             // then look into the local cache
346
JahiaUserWrapper juw = (JahiaUserWrapper) mUserCache.get ("k"+userKey);
347
348             if (juw == null) {
349                 //logger.debug(" user with key=" + userKey + " is not found in cache");
350
user = lookupUserInLDAP (removeKeyPrefix(userKey));
351
352                 if (user != null) {
353                     /* 2004-16-06 : update by EP
354                     new cache to populate : cross providers only based upon names... */

355                     mProvidersUserCache.put("k"+userKey, user);
356
357                     // name storage for speed
358
mUserCache.put("n"+user.getSiteID()+"_"+user.getUsername(), new JahiaUserWrapper(user));
359                     mProvidersUserCache.put("n"+user.getSiteID()+"_"+user.getUsername(), user);
360                 }
361                 // use wrappers in local cache
362
mUserCache.put ("k"+userKey, new JahiaUserWrapper(user));
363             } else {
364                 user = juw.getUser();
365             }
366         }
367
368         return user;
369     }
370
371
372     // @author NK
373
/**
374      * Load all the user data and attributes. On success a reference on the user
375      * is returned, otherwise NULL is returned.
376      *
377      * @param siteID the identifier of the site the user belongs to
378      * @param name User's identification name.
379      *
380      * @return Return a reference on a new created jahiaUser object.
381      */

382     public JahiaUser lookupUser (int siteID, String JavaDoc name) {
383 //(-PredragV-)
384
/*
385           // try to avoid a NullPointerException
386           if (!isNameValid (name)) {
387               return null;
388           }
389
390           String tmpUserName = removeKeyPrefix (name);
391
392           // first lookup in the cache.
393           Enumeration enumeration = mUserCache.elements();
394           JahiaUser user = null;
395           while ( enumeration.hasMoreElements() ){
396               user = (JahiaUser)enumeration.nextElement();
397               //modif predrag
398               /*
399               if ( (user.getSiteID() == siteID)
400                       && ( user.getUsername().equals(tmpUserName) ) ){
401                   return user;
402               }
403                */

404 /*
405             if (
406                     ( user.getUsername().equals(tmpUserName) ) ){
407                 return user;
408              }
409
410
411             //fin modif predrag
412
413         }
414
415         user = (JahiaUser)lookupUserInLDAP (siteID, tmpUserName);
416
417         if ( user != null ){
418             logger.debug(" user not null");
419             //moddif predrag
420             //mUserCache.put(user.getName(),user);
421             mUserCache.put(user.getUsername(),user);
422
423
424             //fin modif predrag
425         }
426
427
428
429         return user;
430 //modif predrag 2
431         */

432         //(-PredragV-)
433
JahiaUser user = lookupUser ("{ldap}"+name);
434         if (user != null)
435             // user.setSiteID (siteID);
436
user.setSiteID(-1);
437         return user;
438         //end (-PredragV-)
439
}
440
441     //--------------------------------------------------------------------------
442
/**
443      * Load all the user data and attributes. On success a reference on the user
444      * is returned, otherwise NULL is returned.
445      *
446      * @param userKey User's identification name.
447      *
448      * @return a reference on a new created jahiaUser object.
449      */

450     public JahiaUser lookupUser (String JavaDoc userKey, String JavaDoc searchAttributeName) {
451
452         /* 2004-16-06 : update by EP
453         new cache to use : cross providers only based upon names... */

454         JahiaUser user = (JahiaUser)mProvidersUserCache.get ("k"+userKey);
455
456         // 2004-23-07 : use wrappers
457
if (user == null) {
458             // then look into the local cache
459
JahiaUserWrapper juw = (JahiaUserWrapper) mUserCache.get ("k"+userKey);
460
461             if (juw == null) {
462                 //logger.debug(" user with key=" + userKey + " is not found in cache");
463
user = lookupUserInLDAP (removeKeyPrefix(userKey), searchAttributeName);
464
465                 if (user != null) {
466                     /* 2004-16-06 : update by EP
467                     new cache to populate : cross providers only based upon names... */

468                     mProvidersUserCache.put("k"+userKey, user);
469
470                     // name storage for speed
471
mUserCache.put("n"+user.getSiteID()+"_"+user.getUsername(), new JahiaUserWrapper(user));
472                     mProvidersUserCache.put("n"+user.getSiteID()+"_"+user.getUsername(), user);
473                 }
474                 // use wrappers in local cache
475
mUserCache.put ("k"+userKey, new JahiaUserWrapper(user));
476             } else {
477                 user = juw.getUser();
478             }
479         }
480            return user;
481     }
482
483     //--------------------------------------------------------------------------
484
/**
485      * This function checks into the system if the name has already been
486      * assigned to another user.
487      *
488      * @param siteID the identifier of the site the user logged in to.
489      * @param name User login name.
490      *
491      * @return Return true if the specified name has not been assigned yet,
492      * return false on any failure.
493      */

494     public boolean userExists (int siteID, String JavaDoc name) {
495         // try to avoid a NullPointerException
496
if (name == null) {
497             return false;
498         }
499
500         // name should not be empty.
501
if (name.length() == 0) {
502             return false;
503         }
504
505         return (lookupUser(siteID, name) != null);
506     }
507
508     //--------------------------------------------------------------------------
509
/**
510      * This method returns the list of all the user names registed into the system.
511      *
512      * @param siteID the identifier of the site to get the user list for
513      *
514      * @return Return a vector of strings holding the user identification names.
515      */

516     public Vector getUsernameList (int siteID) {
517
518         Vector result = new Vector();
519
520         try {
521
522             NamingEnumeration answer = getUsers(getPublicContext(false), new Properties(), ldapProperties.getProperty (UID_SEARCH_NAME_PROP), SearchControls.SUBTREE_SCOPE);
523             while (answer.hasMore()) {
524                 SearchResult JavaDoc sr = (SearchResult JavaDoc) answer.next();
525                 JahiaUser curUser = ldapToJahiaUser(sr);
526                 if (curUser != null) {
527                     result.add (curUser.getUsername ());
528                 }
529             }
530         } catch (SizeLimitExceededException slee) {
531             // we just return the list as it is
532
logger.debug ("Search generated more than configured maximum search limit in " +
533                     DEFAULT_CONFIGURATION_FILE +
534                     ", limiting to " +
535                     this.ldapProperties.getProperty (SEARCH_COUNT_LIMIT_PROP) +
536                     " first results...");
537         } catch (NamingException ne) {
538             logger.warn ("JNDI warning",ne);
539             invalidatePublicCtx ();
540             result = new Vector ();
541         }
542
543         return result;
544     }
545
546     /**
547      * This method returns the list of this site's users' keys.
548      *
549      * @param siteID an identifier for the site whose user list we can to
550      * retrieve
551      *
552      * @return Return a vector of strings holding the user identification key .
553      */

554     public Vector getUserList (int siteID) {
555
556         return getUserList ();
557
558     }
559
560
561     /**
562      * This method return all users' keys in the system.
563      *
564      * @return Return a vector of strings holding the user identification key .
565      */

566     public Vector getUserList () {
567
568         Vector result = new Vector ();
569
570         try {
571
572             NamingEnumeration answer = getUsers(getPublicContext(false), new Properties(), ldapProperties.getProperty (UID_SEARCH_NAME_PROP), SearchControls.SUBTREE_SCOPE);
573             while (answer.hasMore()) {
574                 SearchResult JavaDoc sr = (SearchResult JavaDoc) answer.next();
575                 JahiaUser curUser = ldapToJahiaUser(sr);
576                 if (curUser != null) {
577                     result.add(curUser.getUserKey());
578                 }
579             }
580         } catch (SizeLimitExceededException slee) {
581             // we just return the list as it is
582
logger.debug(
583                 "Search generated more than configured maximum search limit in " +
584                 DEFAULT_CONFIGURATION_FILE +
585                 ", limiting to " +
586                 this.ldapProperties.getProperty(SEARCH_COUNT_LIMIT_PROP) +
587                 " first results...");
588         } catch (NamingException ne) {
589             logger.warn ("JNDI warning",ne);
590             invalidatePublicCtx ();
591             result = new Vector ();
592         }
593
594         return result;
595     }
596
597     /**
598      * Find users according to a table of name=value properties. If the left
599      * side value is "*" for a property then it will be tested against all the
600      * properties. ie *=test* will match every property that starts with "test"
601      *
602      * @param siteID site identifier
603      * @param searchCriterias a Properties object that contains search criterias
604      * in the format name,value (for example "*"="*" or "username"="*test*") or
605      * null to search without criterias
606      *
607      * @return Set a set of JahiaUser elements that correspond to those
608      * search criterias, or an empty one if an error has occured. Note this will
609      * only return the configured limit of users at maxium. Check out the
610      * users.ldap.properties file to change the limit.
611      */

612     public Set JavaDoc searchUsers (int siteID, Properties searchCriterias) {
613
614         Set JavaDoc result = new HashSet();
615         // first let's lookup the user by the properties in Jahia's DB
616
try {
617             Set JavaDoc userKeys = searchLDAPUsersByDBProperties(siteID,
618                 searchCriterias);
619             // now that we have the keys, let's load all the users.
620
Iterator userKeyEnum = userKeys.iterator();
621             while (userKeyEnum.hasNext()) {
622                 String JavaDoc curUserKey = (String JavaDoc) userKeyEnum.next();
623                 JahiaUser user = lookupUser(curUserKey);
624                 result.add(user);
625             }
626
627         } catch (JahiaDatabaseException jde) {
628             logger.error("Error while trying to search for user by properties",
629                          jde);
630         }
631
632         // now let's lookup in LDAP properties.
633
try {
634             NamingEnumeration ldapUsers = getUsers(getPublicContext(false),
635                 searchCriterias, ldapProperties.getProperty (UID_SEARCH_NAME_PROP), SearchControls.SUBTREE_SCOPE);
636             while (ldapUsers.hasMore()) {
637                 SearchResult JavaDoc sr = (SearchResult JavaDoc) ldapUsers.next();
638                 JahiaLDAPUser user = ldapToJahiaUser(sr);
639                 if (user != null) {
640                     result.add(user);
641                 }
642             }
643         } catch (PartialResultException pre) {
644             logger.warn (pre);
645         } catch (SizeLimitExceededException slee) {
646             // logger.error(slee);
647
// we just return the list as it is
648
logger.debug(
649                 "Search generated more than configured maximum search limit in " +
650                 DEFAULT_CONFIGURATION_FILE +
651                 ", limiting to " +
652                 this.ldapProperties.getProperty(SEARCH_COUNT_LIMIT_PROP) +
653                 " first results...");
654         } catch (NamingException ne) {
655             logger.warn ("JNDI warning",ne);
656             invalidatePublicCtx ();
657             result = new HashSet ();
658         }
659         return result;
660     }
661
662     public void init (SettingsBean jSettings)
663         throws JahiaInitializationException {
664         String JavaDoc configPath = jSettings.getJahiaLdapDiskPath();
665         String JavaDoc configFileName;
666
667         File JavaDoc configFile = new File JavaDoc(configPath + File.separator +
668                                    DEFAULT_CONFIGURATION_FILE);
669         if (configFile.exists()) {
670
671             configFileName = configPath + File.separator +
672                              DEFAULT_CONFIGURATION_FILE;
673
674             try {
675                 File JavaDoc ldapPropFile = new File JavaDoc(configFileName);
676                 FileInputStream JavaDoc ldapPropInputStr = new FileInputStream JavaDoc(
677                     ldapPropFile);
678                 ldapProperties = new Properties();
679                 ldapProperties.load(ldapPropInputStr);
680                 ldapPropInputStr.close();
681                 if (!ldapProperties.containsKey(LDAP_USERNAME_ATTRIBUTE)) {
682                     ldapProperties.put(LDAP_USERNAME_ATTRIBUTE, ldapProperties.get(UID_SEARCH_ATTRIBUTE_PROP));
683                 }
684             } catch (FileNotFoundException JavaDoc fnfe) {
685                 logger.error(
686                     "Error while loading user manager LDAP configuration file",
687                     fnfe);
688
689             } catch (IOException JavaDoc ioe) {
690                 logger.error(
691                     "Error while loading user manager LDAP configuration file",
692                     ioe);
693             }
694
695         } else {
696             logger.debug(
697                 "Config file not found in " + configPath + File.separator +
698                 DEFAULT_CONFIGURATION_FILE);
699         }
700
701         try {
702             getPublicContext (true);
703         } catch (NamingException ne) {
704             logger.error(
705                 "Error while initializing public browsing connection to LDAP repository",
706                 ne);
707             invalidatePublicCtx();
708         }
709
710         String JavaDoc wildCardAttributeStr = ldapProperties.getProperty(
711             JahiaUserManagerLDAPProvider.SEARCH_WILDCARD_ATTRIBUTE_LIST);
712         if (wildCardAttributeStr != null) {
713             this.searchWildCardAttributeList = new Vector();
714             StringTokenizer wildCardTokens = new StringTokenizer(
715                 wildCardAttributeStr, ", ");
716             while (wildCardTokens.hasMoreTokens()) {
717                 String JavaDoc curAttrName = wildCardTokens.nextToken().trim();
718                 this.searchWildCardAttributeList.add(curAttrName);
719             }
720         }
721
722         logger.debug("Initialized and connected to public repository");
723     }
724
725     /**
726      * Return the amount of users in the database.
727      *
728      * @return The amount of users.
729      *
730      * @throws JahiaException in case there's a problem retrieving the number
731      * of users from the storage
732      */

733     public synchronized int getNbUsers ()
734         throws JahiaException {
735         return -1;
736     }
737
738     /**
739      * Return the number of user for a gived site
740      *
741      * @param siteID the site identifier for which to retrieve the number of
742      * users
743      *
744      * @return Return the number of users in the system.
745      *
746      * @throws JahiaException in case there is a problem retrieving the number
747      * of users for a given site.
748      */

749     public int getNbUsers (int siteID)
750         throws JahiaException {
751         return getNbUsers();
752     }
753
754     /**
755      * This method returns the list of this site's users' ids.
756      *
757      * @param siteID the identifier for the site for which to retrieve userIDs
758      *
759      * @return Return a vector of strings holding the user ids .
760      */

761     private Vector getUserIds (int siteID) {
762         Vector result = new Vector();
763         return result;
764     }
765
766     /**
767      * return a DOM document of all users of a site
768      *
769      * @param siteID the site id
770      *
771      * @return JahiaDOMObject a DOM representation of this object
772      *
773      * @throws JahiaException in case there is an error communicating with
774      * the storage system
775      */

776     public JahiaDOMObject getUsersAsDOM (int siteID)
777         throws JahiaException {
778
779         JahiaDBDOMObject dom = null;
780
781         return dom;
782     }
783
784     /**
785      * return a DOM document of all user props of a site
786      *
787      * @param siteID the site id
788      *
789      * @return JahiaDOMObject a DOM representation of this object
790      *
791      * @throws JahiaException in case there is a problem communicating with the
792      * storage backend system.
793      */

794     public JahiaDOMObject getUserPropsAsDOM (int siteID)
795         throws JahiaException {
796
797         JahiaDBDOMObject dom = null;
798
799         return dom;
800     }
801
802     public void updateCache(JahiaUser jahiaUser) {
803         mUserCache.put("k"+jahiaUser.getName(), new JahiaUserWrapper(jahiaUser));
804         mProvidersUserCache.put("k"+jahiaUser.getName(), jahiaUser);
805         mUserCache.put("n"+jahiaUser.getSiteID()+"_"+jahiaUser.getUsername(), new JahiaUserWrapper(jahiaUser));
806         mProvidersUserCache.put("n"+jahiaUser.getSiteID()+"_"+jahiaUser.getUsername(), jahiaUser);
807     }
808
809     private boolean addUserIntoLDAP (int id, String JavaDoc username, String JavaDoc password,
810                                      String JavaDoc userKey, int siteID,
811                                      Properties properties) {
812         return true;
813     }
814
815     private String JavaDoc removeKeyPrefix (String JavaDoc userKey) {
816         if (userKey.startsWith("{ldap}")) {
817             return userKey.substring(6);
818         } else {
819             return userKey;
820         }
821     }
822
823     private JahiaLDAPUser lookupUserInLDAP (int siteID, String JavaDoc name) {
824         JahiaLDAPUser user = lookupUserInLDAP(name);
825         if (user == null) {
826             return null;
827         }
828         // user.setSiteID(siteID);
829
user.setSiteID(-1);
830         return user;
831     }
832
833     private JahiaLDAPUser lookupUserInLDAP (String JavaDoc userKey) {
834         JahiaLDAPUser user = null;
835
836         try {
837             SearchResult JavaDoc sr = getPublicUser (getPublicContext (false), ldapProperties.getProperty (UID_SEARCH_ATTRIBUTE_PROP), userKey);
838             if (sr == null) {
839                 return null;
840             }
841             user = ldapToJahiaUser (sr);
842         } catch (SizeLimitExceededException slee) {
843             logger.debug ("Search generated more than configured maximum search limit in " +
844                     DEFAULT_CONFIGURATION_FILE +
845                     ", limiting to " +
846                     this.ldapProperties.getProperty (SEARCH_COUNT_LIMIT_PROP) +
847                     " first results...");
848             user = null;
849
850         } catch (NamingException ne) {
851             logger.warn ("JNDI warning",ne);
852             invalidatePublicCtx ();
853             user = null;
854         }
855         return user;
856     }
857     /**
858      * This method is the rigth way to rtrieve a user from the information stored in the member attribute in groups.
859      * For example, if the member attribute of a group contains the distinguishedName of the memebers,
860      * you have to use lookupUserInLDAP (userDn, "distinguishedName").
861      * If your properties file are correctly defined, you could use the value of the
862      * JahiaGroupManagerLDAPProvider.SEARCH_USER_ATTRIBUTE_NAME for searchAttributeName.
863      *
864      * This method is only called by lookupUser (String userKey, String searchAttributeName)
865      * which was only called by JahiaGroupManagerLDAPProvider.getGroupMembers()
866      */

867     private JahiaLDAPUser lookupUserInLDAP (String JavaDoc userKey, String JavaDoc searchAttributeName) {
868         JahiaLDAPUser user = null;
869
870         try {
871             SearchResult JavaDoc sr = getPublicUser (getPublicContext (false), searchAttributeName, userKey);
872             if (sr == null) {
873                 return null;
874             }
875             user = ldapToJahiaUser (sr);
876         } catch (SizeLimitExceededException slee) {
877             logger.debug ("Search generated more than configured maximum search limit in " +
878                     DEFAULT_CONFIGURATION_FILE +
879                     ", limiting to " +
880                     this.ldapProperties.getProperty (SEARCH_COUNT_LIMIT_PROP) +
881                     " first results...");
882             user = null;
883
884         } catch (NamingException ne) {
885             logger.warn ("JNDI warning",ne);
886             invalidatePublicCtx ();
887             user = null;
888         }
889         return user;
890     }
891
892     public JahiaLDAPUser lookupUserFromDN(String JavaDoc dn) {
893          logger.debug ("Lookup user from dn " + dn);
894          JahiaLDAPUser user = null;
895          if (mUserCache.containsKey("d"+dn)) {
896              return (JahiaLDAPUser) mUserCache.get("d"+dn);
897          }
898          try {
899              Attributes JavaDoc attributes = getUser (getPublicContext(false), dn);
900              user = ldapToJahiaUser (attributes, dn);
901              mUserCache.put("d"+dn, user);
902              mUserCache.put("k"+user.getUserKey(), new JahiaUserWrapper(user));
903              mUserCache.put("n"+user.getSiteID()+"_"+user.getUsername(), new JahiaUserWrapper(user));
904              mProvidersUserCache.put("n"+user.getSiteID()+"_"+user.getUsername(), user);
905          } catch (NameNotFoundException nnfe) {
906              user = null;
907          } catch (NamingException ne) {
908              logger.warn ("JNDI warning",ne);
909              invalidatePublicCtx ();
910              user = null;
911          }
912          return user;
913      }
914
915      /**
916       * Translates LDAP attributes to a JahiaUser properties set. Multi-valued
917       * attribute values are converted to Strings containing LINEFEED (\n)
918       * characters. This way it is quite simple to use String Tokenizers to
919       * extract multiple values. Note that if a value ALREADY contains a line
920       * feed characters this will cause unexpected behavior.
921       *
922       * @param sr result of a search on a LDAP directory context
923       * @return JahiaLDAPUser a user initialized with the properties loaded
924       * from the LDAP database, or null if no userKey could be determined for
925       * the user.
926       */

927      private JahiaLDAPUser ldapToJahiaUser (SearchResult JavaDoc sr) {
928          Attributes JavaDoc attrs = sr.getAttributes();
929          String JavaDoc dn = sr.getName() + "," + ldapProperties.getProperty (UID_SEARCH_NAME_PROP);
930          return ldapToJahiaUser(attrs, dn);
931      }
932
933      private JahiaLDAPUser ldapToJahiaUser(Attributes JavaDoc attrs, String JavaDoc dn) {
934          JahiaLDAPUser user = null;
935          UserProperties userProps = new UserProperties ();
936          String JavaDoc usingUserKey = null;
937
938          Enumeration attrsEnum = attrs.getAll();
939          while (attrsEnum.hasMoreElements()) {
940              Attribute JavaDoc curAttr = (Attribute JavaDoc) attrsEnum.nextElement();
941              String JavaDoc attrName = curAttr.getID();
942              StringBuffer JavaDoc attrValueBuf = new StringBuffer JavaDoc();
943              try {
944                  Enumeration curAttrValueEnum = curAttr.getAll();
945                  while (curAttrValueEnum.hasMoreElements()) {
946                      Object JavaDoc curAttrValueObj = curAttrValueEnum.nextElement();
947                      if ( (curAttrValueObj instanceof String JavaDoc)) {
948                          attrValueBuf.append( (String JavaDoc) curAttrValueObj);
949                      } else {
950                          logger.debug("Converting attribute <" + attrName +
951                                       "> from class " +
952                                       curAttrValueObj.getClass().toString() +
953                                       " to String...");
954                          /** @todo FIXME : for the moment we convert everything to String */
955                          attrValueBuf.append(curAttrValueObj);
956                      }
957                      attrValueBuf.append('\n');
958                  }
959              } catch (NamingException ne) {
960                  logger.warn ("JNDI warning",ne);
961                  attrValueBuf = new StringBuffer JavaDoc ();
962              }
963              String JavaDoc attrValue = attrValueBuf.toString();
964              if (attrValue.endsWith("\n")) {
965                  attrValue = attrValue.substring(0, attrValue.length() - 1);
966              }
967              if ( (attrName != null) && (attrValue != null)) {
968                  if (usingUserKey == null) {
969                      if (attrName.equalsIgnoreCase(
970                          ldapProperties.getProperty(UID_SEARCH_ATTRIBUTE_PROP))) {
971                          usingUserKey = attrValue;
972                      }
973                  }
974                  // mark user property as read-only as it is coming from LDAP
975
UserProperty curUserProperty = new UserProperty(attrName, attrValue, true);
976                  userProps.setUserProperty(attrName, curUserProperty);
977              }
978          }
979          if (usingUserKey != null) {
980              mapLDAPToJahiaProperties(userProps);
981              // FIXME : Quick hack for merging Jahia DB user properties with LDAP user
982
mapDBToJahiaProperties (userProps, JahiaLDAPUser.USERKEY_LDAP_PREFIX + usingUserKey);
983              /* EP : changes the code to handle the name of the user as defined in properties file.
984              The name of the user is the value of the LDAP_USERNAME_ATTRIBUTE properties */

985              String JavaDoc name = usingUserKey;
986
987              if (ldapProperties.getProperty(LDAP_USERNAME_ATTRIBUTE) != null
988                      && ldapProperties.getProperty(LDAP_USERNAME_ATTRIBUTE).length() > 0) {
989                  name = userProps
990                          .getProperty
991                          (ldapProperties
992                          .getProperty(
993                          LDAP_USERNAME_ATTRIBUTE));
994              }
995
996                 user = new JahiaLDAPUser (0,
997                          name,
998                          "",
999                          usingUserKey,
1000                         0,
1001                         userProps,
1002                         dn);
1003         } else {
1004             logger.debug ("Ignoring entry " + dn +
1005                     " because it has no valid " +
1006                     ldapProperties.getProperty (UID_SEARCH_ATTRIBUTE_PROP) +
1007                     " attribute to be mapped onto user key...");
1008         }
1009
1010         return user;
1011     }
1012
1013
1014
1015    /**
1016     * Map LDAP properties to Jahia user properties, such as first name,
1017     * last name, etc...
1018     * This method modifies the userProps object passed on parameters to add
1019     * the new properties.
1020     *
1021     * @param userProps User properties to check for mappings. Basically what
1022     * we do is copy LDAP properties to standard Jahia properties. This is
1023     * defined in the user ldap properties file. Warning this object is modified
1024     * by this method !
1025     *
1026     * @todo FIXME : if properties exist in LDAP that have the same name as
1027     * Jahia properties these will be erased. We should probably look into
1028     * making the properties names more unique such as org.jahia.propertyname
1029     */

1030    private void mapLDAPToJahiaProperties (UserProperties userProps) {
1031        // copy attribute to standard Jahia properties if they exist both in
1032
// the mapping and in the repository
1033
for (Iterator iterator = ldapProperties.keySet().iterator();
1034                                 iterator.hasNext(); ) {
1035            String JavaDoc key = (String JavaDoc) iterator.next();
1036            if (key.endsWith(".attribute.map")) {
1037                String JavaDoc jahiaProperty = key.substring(11, key.length() - 14);
1038                String JavaDoc curProperty = ldapProperties.getProperty(key);
1039                if (userProps.getUserProperty(curProperty) != null) {
1040                    UserProperty sourceProp = userProps.getUserProperty(curProperty);
1041                    UserProperty targetProp = new UserProperty(jahiaProperty, sourceProp.getValue(), sourceProp.isReadOnly());
1042                    userProps.setUserProperty(jahiaProperty,
1043                                              targetProp);
1044                } else {
1045                    // for properties that don't have a value in LDAP, we still
1046
// create a read-only Jahia property, in case it is added
1047
// later in LDAP. We don't want to authorize edition of an
1048
// LDAP-mapped property.
1049
UserProperty targetProp = new UserProperty(jahiaProperty, "", true);
1050                    userProps.setUserProperty(jahiaProperty,
1051                                              targetProp);
1052                }
1053            }
1054        }
1055    }
1056
1057    /**
1058     * Maps Jahia user to LDAP properties using the definition
1059     * mapping in the user LDAP configuration properties file. This modifies
1060     * the userProps
1061     *
1062     * @param userProps
1063     */

1064    private void mapJahiaPropertiesToLDAP (Properties userProps) {
1065        for (Iterator iterator = ldapProperties.keySet().iterator();
1066                                 iterator.hasNext(); ) {
1067            String JavaDoc key = (String JavaDoc) iterator.next();
1068            if (key.endsWith(".attribute.map")) {
1069                String JavaDoc jahiaProperty = key.substring(11, key.length() - 14);
1070                String JavaDoc curProperty = ldapProperties.getProperty(key);
1071                if (userProps.getProperty(jahiaProperty) != null) {
1072                    userProps.setProperty(curProperty,
1073                                          (String JavaDoc) userProps.remove(jahiaProperty));
1074                }
1075            }
1076        }
1077    }
1078
1079    //-------------------------------------------------------------------------
1080
private boolean isNameValid (String JavaDoc name) {
1081
1082        if (name == null) {
1083            return false;
1084        }
1085
1086        if (name.length() == 0) {
1087            return false;
1088        }
1089
1090        String JavaDoc authorizedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789{}";
1091        /* EP : 2004-17-06
1092        char[] chars = authorizedCharacters.toCharArray ();
1093        char[] nameBuffer = name.toCharArray ();*/

1094
1095        boolean badCharFound = false;
1096        for (int i = 0; i < name.length() && !badCharFound; i++) {
1097            badCharFound = authorizedCharacters.indexOf((int)name.charAt(i)) < 0;
1098            if (badCharFound) {
1099                logger.debug ("Bad character found in LDAP user name [" +
1100                        name +
1101                        "] at position " + i);
1102            }
1103        }
1104        /* end EP mods */
1105
1106        return (!badCharFound);
1107    }
1108
1109    /**
1110     * Returns the internal public context variable. The point of this is to
1111     * keep this connection open as long as possible, in order to reuser the
1112     * connection.
1113     *
1114     * @param boolean forceRefresh
1115     *
1116     * @return DirContext the current public context.
1117     *
1118     * @throws NamingException
1119     */

1120    public DirContext JavaDoc getPublicContext (boolean forceRefresh) throws NamingException {
1121        if (forceRefresh || publicCtx == null) {
1122            // this shouldn't happen... but timeouts have to be checked.
1123
try {
1124                publicCtx = connectToPublicDir ();
1125            } catch (NamingException ne) {
1126                logger.warn ("JNDI warning",ne);
1127                publicCtx = null;
1128            }
1129            if (publicCtx == null) {
1130                logger.debug ("reconnect failed, returning null context...");
1131                // we've tried everything, still can't connect...
1132
return null;
1133            }
1134        }
1135        return publicCtx;
1136    }
1137
1138    /**
1139     * EP : 2004/07/05
1140     */

1141    private boolean isContextValid(DirContext JavaDoc ctx) {
1142        try {
1143            ctx.getEnvironment();
1144            return true;
1145        } catch (NamingException ne) {
1146            logger.warn ("Reconnection is required... ", ne);
1147        } catch (NullPointerException JavaDoc npe) {
1148            logger.warn ("Reconnection is required... ", npe);
1149        }
1150
1151        return false;
1152    }
1153
1154    /**
1155     * Performs a login of the specified user.
1156     *
1157     * @param userKey the user identifier defined in this service properties
1158     * @param userPassword the password of the user
1159     *
1160     * @return String a string that contains the common name of this user
1161     * whithin the repository.
1162     */

1163    public synchronized boolean login (String JavaDoc userKey, String JavaDoc userPassword) {
1164        String JavaDoc dn = null;
1165        String JavaDoc userFinalKey = userKey;
1166
1167        if ("".equals (userPassword)) {
1168            logger.debug ("Empty passwords are not authorized for LDAP login ! Failing user " +
1169                    userKey + " login request.");
1170            return false;
1171        }
1172
1173        userFinalKey = removeKeyPrefix(userKey);
1174        DirContext JavaDoc privateCtx = null;
1175
1176        try {
1177            dn = ((JahiaLDAPUser) lookupUser (userFinalKey)).getDN();
1178            //invalidatePublicCtx ();
1179

1180            privateCtx = connectToPrivateDir (dn, userPassword);
1181
1182            if (privateCtx == null) {
1183                dn = null;
1184            }
1185
1186            invalidateCtx (privateCtx);
1187
1188            // reconnect to public context
1189
//getPublicContext (true);
1190
} catch (javax.naming.CommunicationException JavaDoc ce) {
1191            logger.warn ("CommunicationException", ce);
1192            logger.debug ("Invalidating connection to public LDAP context...");
1193            invalidateCtx (privateCtx);
1194            dn = null;
1195        } catch (NamingException ne) {
1196            logger.debug("Login refused, server message : " + ne.getMessage());
1197            dn = null;
1198
1199            invalidateCtx (privateCtx);
1200            // reconnect to public context
1201
/*
1202            try {
1203                getPublicContext(true);
1204            } catch (NamingException ne2) {
1205                logger.error("Error reconnecting to public LDAP context", ne2);
1206            }
1207            */

1208        }
1209        return (dn != null);
1210    }
1211
1212    private void invalidateCtx (DirContext JavaDoc ctx) {
1213        if (ctx == null) {
1214            logger.debug ("Context passed is null, ignoring it...");
1215            return;
1216        }
1217        try {
1218            ctx.close ();
1219            ctx = null;
1220        } catch (Exception JavaDoc e) {
1221            logger.warn (e);
1222        }
1223    }
1224
1225    private void invalidatePublicCtx () {
1226        try {
1227            invalidateCtx (getPublicContext(false));
1228        } catch (NamingException ne) {
1229            logger.error("Couldn't invalidate public LDAP context", ne);
1230        }
1231    }
1232
1233    private DirContext JavaDoc connectToPublicDir ()
1234            throws NamingException {
1235        // EP : 2004/29/06 : implement reconnection mechanism on ldap...
1236
if (((JahiaUserManagerRoutingService)ServicesRegistry
1237             .getInstance()
1238             .getJahiaUserManagerService())
1239            .getServerList(PROVIDER_NAME) != null) {
1240            return connectToAllPublicDir();
1241        }
1242
1243        // Identify service provider to use
1244
logger.debug ("Attempting connection to LDAP repository on " +
1245                ldapProperties.getProperty (LDAP_URL_PROP) + "...");
1246
1247        Hashtable publicEnv = new Hashtable (11);
1248        publicEnv.put (Context.INITIAL_CONTEXT_FACTORY,
1249                ldapProperties.getProperty (CONTEXT_FACTORY_PROP));
1250        publicEnv.put (Context.PROVIDER_URL,
1251                ldapProperties.getProperty (LDAP_URL_PROP));
1252        publicEnv.put (Context.SECURITY_AUTHENTICATION,
1253                ldapProperties.getProperty (AUTHENTIFICATION_MODE_PROP));
1254        publicEnv.put (Context.SECURITY_PRINCIPAL,
1255                ldapProperties.getProperty (PUBLIC_BIND_DN_PROP));
1256        publicEnv.put (Context.REFERRAL,
1257                       ldapProperties.getProperty (LDAP_REFFERAL_PROP, "ignore"));
1258        if (ldapProperties.getProperty (PUBLIC_BIND_PASSWORD_PROP) != null) {
1259            logger.debug ("Using authentification mode to connect to public dir...");
1260            publicEnv.put (Context.SECURITY_CREDENTIALS,
1261                    ldapProperties.getProperty (PUBLIC_BIND_PASSWORD_PROP));
1262        }
1263
1264        // Create the initial directory context
1265
return new InitialDirContext JavaDoc (publicEnv);
1266    }
1267
1268    private DirContext JavaDoc connectToAllPublicDir ()
1269            throws NamingException {
1270        DirContext JavaDoc ctx = null;
1271    TreeSet servers = ((JahiaUserManagerRoutingService)ServicesRegistry
1272                            .getInstance()
1273                            .getJahiaUserManagerService())
1274                            .getServerList(PROVIDER_NAME);
1275
1276    for (Iterator ite = servers.iterator(); ite.hasNext();) {
1277        ServerBean sb = (ServerBean) ite.next();
1278        String JavaDoc sbUrl = (String JavaDoc)sb.getPublicConnectionParameters()
1279                        .get(Context.PROVIDER_URL);
1280
1281        int tryNumber = 1;
1282        while (tryNumber <= sb.getMaxReconnection()) {
1283                // Identify service provider to use
1284
logger.debug ("Attempting public connection "
1285                            + tryNumber
1286                            + " to LDAP repository on "
1287                            + sbUrl
1288                            + "...");
1289
1290                // Create the initial directory context
1291
try {
1292                    ctx = new InitialDirContext JavaDoc (sb.getPublicConnectionParameters());
1293                    if (isContextValid(ctx))
1294                        return ctx;
1295                } catch (NamingException ne) {
1296                    // all others exception lead to try another connection...
1297
logger.error("Erreur while getting public context on " + sbUrl, ne);
1298                }
1299                tryNumber++;
1300        }
1301    }
1302
1303    if (ctx == null) {
1304        throw new NamingException("All servers used without success...");
1305    }
1306
1307        return ctx;
1308    }
1309
1310    private DirContext JavaDoc connectToAllPrivateDir (String JavaDoc username, String JavaDoc password)
1311            throws NamingException {
1312        DirContext JavaDoc ctx = null;
1313    TreeSet servers = ((JahiaUserManagerRoutingService)ServicesRegistry
1314                            .getInstance()
1315                            .getJahiaUserManagerService())
1316                            .getServerList(PROVIDER_NAME);
1317
1318    for (Iterator ite = servers.iterator(); ite.hasNext();) {
1319        ServerBean sb = (ServerBean) ite.next();
1320        Hashtable parameters = sb.getPrivateConnectionParameters(
1321                        username,
1322                        password);
1323
1324        String JavaDoc sbUrl = (String JavaDoc)parameters.get(Context.PROVIDER_URL);
1325
1326        int tryNumber = 1;
1327        while (tryNumber <= sb.getMaxReconnection()) {
1328                // Identify service provider to use
1329
logger.debug ("Attempting private connection "
1330                            + tryNumber
1331                            + " to LDAP repository on "
1332                            + sbUrl
1333                            + "...");
1334
1335                // Create the initial directory context
1336
try {
1337                    return new InitialDirContext JavaDoc (parameters);
1338                } catch (NamingSecurityException nse) {
1339                    // exception while authenticating
1340
return null;
1341                } catch (NamingException ne) {
1342                    // all others exception lead to try another connection...
1343
}
1344                tryNumber++;
1345        }
1346    }
1347
1348    if (ctx == null) {
1349        throw new NamingException("All servers used without success...");
1350    }
1351
1352        return ctx;
1353    }
1354
1355    private DirContext JavaDoc connectToPrivateDir (String JavaDoc dn, String JavaDoc personPassword)
1356            throws NamingException {
1357        // EP : 2004/29/06 : implement reconnection mechanism on ldap...
1358
if (((JahiaUserManagerRoutingService)ServicesRegistry
1359             .getInstance()
1360             .getJahiaUserManagerService())
1361            .getServerList(PROVIDER_NAME) != null) {
1362            return connectToAllPrivateDir(dn, personPassword);
1363        }
1364
1365        // Identify service provider to use
1366
Hashtable privateEnv = new Hashtable (11);
1367        privateEnv.put (Context.INITIAL_CONTEXT_FACTORY,
1368                ldapProperties.getProperty (CONTEXT_FACTORY_PROP));
1369        privateEnv.put (Context.PROVIDER_URL,
1370                ldapProperties.getProperty (LDAP_URL_PROP));
1371        privateEnv.put (Context.SECURITY_AUTHENTICATION,
1372                ldapProperties.getProperty (AUTHENTIFICATION_MODE_PROP));
1373        privateEnv.put (Context.SECURITY_PRINCIPAL, dn );
1374        privateEnv.put (Context.SECURITY_CREDENTIALS,
1375                personPassword);
1376
1377        // Create the initial directory context
1378
return new InitialDirContext JavaDoc (privateEnv);
1379    }
1380
1381    /**
1382     * Retrieves users from the LDAP public repository.
1383     *
1384     * @param ctx the current context in which to search for the user
1385     * @param filters a set of name=value string that contain RFC 2254 format
1386     * filters in the value, or null if we want to look in the full repository
1387     *
1388     * @param searchBase
1389     * @param scope
1390     * @return NamingEnumeration a naming enumeration of SearchResult objects
1391     * that contains the LDAP user entries that correspond to the filter
1392     *
1393     * @throws NamingException
1394     */

1395    private NamingEnumeration getUsers (DirContext JavaDoc ctx, Properties filters, String JavaDoc searchBase, int scope)
1396        throws NamingException {
1397        if (ctx == null) {
1398            throw new NamingException("Context is null !");
1399        }
1400
1401        StringBuffer JavaDoc filterString = new StringBuffer JavaDoc();
1402
1403        if (filters == null) {
1404            filters = new Properties();
1405        }
1406
1407        if (filters.containsKey("ldap.url")) {
1408            String JavaDoc url = filters.getProperty("ldap.url");
1409            StringTokenizer st = new StringTokenizer(url.substring(8), "?");
1410            String JavaDoc thisBase = st.nextToken();
1411            String JavaDoc thisScope = st.nextToken();
1412            String JavaDoc thisFilter = st.nextToken();
1413            int intScope;
1414            if ("one".equalsIgnoreCase(thisScope)) {
1415                intScope = SearchControls.ONELEVEL_SCOPE;
1416            } else if ("base".equalsIgnoreCase(thisScope)) {
1417                intScope = SearchControls.OBJECT_SCOPE;
1418            } else {
1419                intScope = SearchControls.SUBTREE_SCOPE;
1420            }
1421            if (filters.containsKey("user.key")) {
1422                thisFilter = "(&("+ldapProperties.getProperty (UID_SEARCH_ATTRIBUTE_PROP)+"="+filters.get("user.key")+")"+thisFilter+")";
1423            }
1424            return getUsers(ctx, thisFilter, thisBase, intScope);
1425        } else {
1426            filterString.append("(&(objectClass=" + ldapProperties.getProperty(
1427                            USERS_OBJECTCLASS_ATTRIBUTE, "*") + ")");
1428
1429            // let's translate Jahia properties to LDAP properties
1430
mapJahiaPropertiesToLDAP(filters);
1431
1432
1433            if (filters.size() > 1) {
1434                filterString.append("(|");
1435            }
1436
1437            Enumeration filterKeys = filters.keys();
1438            while (filterKeys.hasMoreElements()) {
1439                String JavaDoc filterName = (String JavaDoc) filterKeys.nextElement();
1440                String JavaDoc filterValue = filters.getProperty(filterName);
1441                // we do all the RFC 2254 replacement *except* the "*" character
1442
// since this is actually something we want to use.
1443
filterValue = JahiaTools.replacePattern(filterValue, "\\",
1444                        "\\5c");
1445                filterValue = JahiaTools.replacePattern(filterValue, "(",
1446                        "\\28");
1447                filterValue = JahiaTools.replacePattern(filterValue, ")",
1448                        "\\29");
1449
1450                if ("*".equals(filterName)) {
1451                    // we must match the value for all the attributes
1452
// declared in the property file.
1453
if (this.searchWildCardAttributeList != null) {
1454                        if (this.searchWildCardAttributeList.size() > 1) {
1455                            filterString.append("(|");
1456                        }
1457                        Enumeration attributeEnum = this.
1458                                searchWildCardAttributeList.elements();
1459                        while (attributeEnum.hasMoreElements()) {
1460                            String JavaDoc curAttributeName = (String JavaDoc)
1461                                    attributeEnum.nextElement();
1462                            filterString.append("(");
1463                            filterString.append(curAttributeName);
1464                            filterString.append("=");
1465                            filterString.append(filterValue);
1466                            filterString.append(")");
1467                        }
1468                        if (this.searchWildCardAttributeList.size() > 1) {
1469                            filterString.append(")");
1470                        }
1471                    }
1472                } else {
1473                    filterString.append("(");
1474                    filterString.append(filterName);
1475                    filterString.append("=");
1476                    filterString.append(filterValue);
1477                    filterString.append(")");
1478                }
1479            }
1480
1481            if (filters.size() > 1) {
1482                filterString.append(")");
1483            }
1484
1485            filterString.append(")");
1486
1487            return getUsers(ctx, filterString.toString(), searchBase, scope);
1488        }
1489    }
1490
1491    private Attributes JavaDoc getUser (DirContext JavaDoc ctx, String JavaDoc dn)
1492            throws NamingException {
1493        try {
1494            return ctx.getAttributes(dn);
1495        } catch (javax.naming.NoInitialContextException JavaDoc nice) {
1496            logger.warn("Reconnection required", nice);
1497            return getUser(getPublicContext(true), dn);
1498        } catch (javax.naming.CannotProceedException JavaDoc cpe) {
1499            logger.warn("Reconnection required", cpe);
1500            return getUser(getPublicContext(true), dn);
1501        } catch (javax.naming.ServiceUnavailableException JavaDoc sue) {
1502            logger.warn("Reconnection required", sue);
1503            return getUser(getPublicContext(true), dn);
1504        } catch (javax.naming.TimeLimitExceededException JavaDoc tlee) {
1505            logger.warn("Reconnection required", tlee);
1506            return getUser(getPublicContext(true), dn);
1507        } catch (javax.naming.CommunicationException JavaDoc ce) {
1508            logger.warn("Reconnection required", ce);
1509            return getUser(getPublicContext(true), dn);
1510        }
1511    }
1512
1513    private NamingEnumeration getUsers (DirContext JavaDoc ctx, String JavaDoc filterString, String JavaDoc searchBase, int scope)
1514            throws NamingException {
1515        // Search for objects that have those matching attributes
1516
SearchControls JavaDoc searchCtl = new SearchControls JavaDoc ();
1517        searchCtl.setSearchScope (scope);
1518        int countLimit = Integer.parseInt (
1519                ldapProperties.getProperty (
1520                        JahiaUserManagerLDAPProvider.SEARCH_COUNT_LIMIT_PROP));
1521        searchCtl.setCountLimit (countLimit);
1522        logger.debug ("Using filter string [" + filterString.toString () + "]...");
1523        try {
1524            return ctx.search (
1525                    searchBase,
1526                    filterString.toString (),
1527                    searchCtl);
1528        } catch (javax.naming.NoInitialContextException JavaDoc nice) {
1529            logger.warn("Reconnection required", nice);
1530            return getUsers(getPublicContext(true), filterString, searchBase, scope);
1531        } catch (javax.naming.CannotProceedException JavaDoc cpe) {
1532            logger.warn("Reconnection required", cpe);
1533            return getUsers(getPublicContext(true), filterString, searchBase, scope);
1534        } catch (javax.naming.ServiceUnavailableException JavaDoc sue) {
1535            logger.warn("Reconnection required", sue);
1536            return getUsers(getPublicContext(true), filterString, searchBase, scope);
1537        } catch (javax.naming.TimeLimitExceededException JavaDoc tlee) {
1538            logger.warn("Reconnection required", tlee);
1539            return getUsers(getPublicContext(true), filterString, searchBase, scope);
1540        } catch (javax.naming.CommunicationException JavaDoc ce) {
1541            logger.warn("Reconnection required", ce);
1542            return getUsers(getPublicContext(true), filterString, searchBase, scope);
1543        }
1544
1545    }
1546
1547    /**
1548     * Retrieves a user from the LDAP public repository.
1549     *
1550     * @param ctx the current context in which to search for the user
1551     * @param prop
1552     * @param val the unique identifier for the user
1553     *
1554     * @return a SearchResult object, which is the *first* result matching the
1555     * uid
1556     *
1557     * @throws NamingException
1558     */

1559    private SearchResult JavaDoc getPublicUser (DirContext JavaDoc ctx, String JavaDoc prop, String JavaDoc val)
1560        throws NamingException {
1561
1562        Properties filters = new Properties();
1563
1564        filters.setProperty(prop, val);
1565        NamingEnumeration answer = getUsers(ctx, filters, ldapProperties.getProperty (UID_SEARCH_NAME_PROP), SearchControls.SUBTREE_SCOPE);
1566        SearchResult JavaDoc sr = null;
1567        if (answer.hasMore()) {
1568            // we only take the first value if there are multiple answers, which
1569
// should normally NOT happend if the uid is unique !!
1570
sr = (SearchResult JavaDoc) answer.next ();
1571            boolean hasMore = false;
1572            try {
1573                hasMore = answer.hasMore ();
1574            } catch (PartialResultException pre) {
1575                logger.warn (pre);
1576            }
1577
1578            if (hasMore) { // there is at least a second result.
1579
// throw new NamingException("UserLDAPService.getPublicUser>" +
1580
// "Warning : multiple users with same UID in LDAP repository.");
1581
logger.debug(
1582                    "Warning : multiple users with same UID in LDAP repository.");
1583            }
1584        }
1585        return sr;
1586    }
1587
1588// FIXME : These following methods are temporary. It is a stupid cut and paste
1589
// from JahiaUserManagerDBProvider.java file. They process the LDAP user
1590
// properties from/into Jahia DB.
1591

1592    /**
1593     * Retrieves properties from internal jahia DB
1594     *
1595     * @param userProps the user properties to set
1596     * @param usingUserKey the user whose the properties has to be extracted.
1597     */

1598    private void mapDBToJahiaProperties (UserProperties userProps,
1599                                         String JavaDoc usingUserKey) {
1600
1601        try {
1602            UserProperties dbProperties = JahiaUserDBUtils.getInstance().
1603                                      getUserProperties( -1,
1604                PROVIDER_NAME, usingUserKey);
1605            userProps.putAll(dbProperties);
1606        } catch (JahiaException je) {
1607            logger.warn("SQL Exception occured : Could not read the user [" +
1608                        usingUserKey +
1609                        "] from the database for site LDAP user", je);
1610        }
1611    }
1612
1613    public String JavaDoc getUrl () {
1614        return ldapProperties.getProperty(LDAP_URL_PROP);
1615    }
1616
1617    /**
1618     * Transforms a search with "*" characters into a valid LIKE statement
1619     * with "%" characters. Also escapes the string to remove all "'" and
1620     * other chars that might disturb the request construct.
1621     *
1622     * @param input the original String
1623     *
1624     * @return String a resulting string that has
1625     */

1626    private String JavaDoc makeLIKEString (String JavaDoc input) {
1627        String JavaDoc result = JahiaTools.replacePattern(input, "*", "%");
1628        result = JahiaTools.replacePattern(result, "'", "\\'");
1629        result = JahiaTools.replacePattern(result, "\"", "\\\"");
1630        result = JahiaTools.replacePattern(result, "_", "\\_");
1631        return result;
1632    }
1633
1634    /**
1635     * Find users according to a table of name=value properties. If the left
1636     * side value is "*" for a property then it will be tested against all the
1637     * properties. ie *=test* will match every property that starts with "test"
1638     *
1639     * @param siteID site identifier
1640     * @param searchCriterias a Properties object that contains search criterias
1641     * in the format name,value (for example "*"="*" or "username"="*test*") or
1642     * null to search without criterias
1643     *
1644     * @return Set a set of JahiaUser elements that correspond to those
1645     * search criterias
1646     *
1647     * @todo this code could be cleaner if username was a real user property
1648     * but as it isn't we have to do a lot of custom handling.
1649     */

1650    private synchronized Set JavaDoc searchLDAPUsersByDBProperties (int siteID,
1651        Properties searchCriterias)
1652        throws JahiaDatabaseException {
1653        Set JavaDoc userKeys = new HashSet();
1654
1655        // Get a database connection
1656
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.
1657                            getConnection();
1658        if (dbConn == null) {
1659            return userKeys;
1660        }
1661
1662        if (searchCriterias == null) {
1663            searchCriterias = new Properties();
1664            searchCriterias.setProperty("*", "*");
1665        }
1666
1667        boolean haveWildCardProperty = false;
1668        if (searchCriterias.getProperty("*") != null) {
1669            haveWildCardProperty = true;
1670        }
1671
1672        // execute the SELECT query
1673
Statement JavaDoc statement = null;
1674        try {
1675            statement = dbConn.createStatement();
1676            if (statement != null) {
1677
1678                StringBuffer JavaDoc query;
1679
1680                query =
1681                    new StringBuffer JavaDoc(
1682                    "SELECT DISTINCT userkey_jahia_user_prop FROM jahia_user_prop WHERE provider_jahia_user_prop='");
1683                query.append(PROVIDER_NAME);
1684                query.append("' AND ");
1685                Enumeration criteriaNames = searchCriterias.keys();
1686                while (criteriaNames.hasMoreElements()) {
1687                    String JavaDoc curCriteriaName = (String JavaDoc) criteriaNames.
1688                                             nextElement();
1689                    String JavaDoc curCriteriaValue = makeLIKEString(
1690                        searchCriterias.getProperty(curCriteriaName));
1691                    if ("*".equals(curCriteriaName)) {
1692                        // we must look in all columns, including special for
1693
// the user.
1694
query.append(
1695                            " value_jahia_user_prop LIKE '");
1696                        query.append(curCriteriaValue);
1697                        query.append("' ");
1698                        if (criteriaNames.hasMoreElements()) {
1699                            query.append(" AND ");
1700                        }
1701                    } else {
1702                        query.append(
1703                            "(name_jahia_user_prop='");
1704                        query.append(makeLIKEString(curCriteriaName));
1705                        query.append(
1706                            "' AND value_jahia_user_prop LIKE '");
1707                        query.append(curCriteriaValue);
1708                        query.append("') ");
1709                        if (criteriaNames.hasMoreElements()) {
1710                            query.append(" AND ");
1711                        }
1712                    }
1713                }
1714                logger.debug("Executing query [" + query.toString() + "]");
1715
1716                ResultSet JavaDoc rs = statement.executeQuery(query.toString());
1717                if (rs != null) {
1718                    while (rs.next()) {
1719                        String JavaDoc name = rs.getString(1);
1720                        if (name != null) {
1721                            userKeys.add(name);
1722                        }
1723                    }
1724                }
1725            }
1726        } catch (SQLException JavaDoc ex) {
1727            logger.error("Error while searching users in site " + siteID, ex);
1728        } finally {
1729            closeStatement(statement);
1730        }
1731
1732        return userKeys;
1733
1734    }
1735
1736    //-------------------------------------------------------------------------
1737
private void closeStatement (Statement JavaDoc statement)
1738        throws JahiaDatabaseException {
1739        // Close the opened statement
1740
try {
1741            if (statement != null) {
1742                statement.close();
1743            }
1744        } catch (SQLException JavaDoc sqlEx) {
1745            throw new JahiaDatabaseException(
1746                "Could not close a statement in JahiaDBUser",
1747                sqlEx, JahiaDatabaseException.ERROR_SEVERITY);
1748        }
1749    }
1750
1751}
1752
Popular Tags