View Javadoc

1   
2   /*
3    * LDAPPersistenceFactory.java
4    *
5    * Created on January 21, 2005, 9:37 AM
6    */
7   
8   package gov.bnl.gums.persistence;
9   
10  import gov.bnl.gums.configuration.Configuration;
11  import gov.bnl.gums.db.AccountPoolMapperDB;
12  import gov.bnl.gums.db.LDAPAccountMapperDB;
13  import gov.bnl.gums.db.LDAPUserGroupDB;
14  import gov.bnl.gums.db.ManualAccountMapperDB;
15  import gov.bnl.gums.db.ManualUserGroupDB;
16  import gov.bnl.gums.db.UserGroupDB;
17  import gov.bnl.gums.*;
18  
19  import java.io.FileInputStream;
20  import java.io.FileOutputStream;
21  import java.io.InputStream;
22  import java.security.KeyStore;
23  import java.security.cert.CertificateFactory;
24  import java.security.cert.X509Certificate;
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.Iterator;
28  import java.util.LinkedList;
29  import java.util.List;
30  import java.util.Properties;
31  import java.util.StringTokenizer;
32  
33  import javax.naming.NameNotFoundException;
34  import javax.naming.NamingEnumeration;
35  import javax.naming.NamingException;
36  import javax.naming.directory.Attribute;
37  import javax.naming.directory.Attributes;
38  import javax.naming.directory.BasicAttribute;
39  import javax.naming.directory.BasicAttributes;
40  import javax.naming.directory.DirContext;
41  import javax.naming.directory.ModificationItem;
42  import javax.naming.directory.SearchControls;
43  import javax.naming.directory.SearchResult;
44  import javax.naming.ldap.InitialLdapContext;
45  
46  import org.apache.commons.logging.Log;
47  import org.apache.commons.logging.LogFactory;
48  
49  /**
50   *
51   * @author Gabriele Carcassi, Jay Packard
52   */
53  public class LDAPPersistenceFactory extends PersistenceFactory {
54      private static String gumsOU = "ou=GUMS";
55      static public String getTypeStatic() {
56  		return "ldap";
57  	}
58      
59      private Log log = LogFactory.getLog(LDAPPersistenceFactory.class);
60      private Log adminLog = LogFactory.getLog(GUMS.resourceAdminLog);
61      private boolean synchGroups;
62      private List contexts = Collections.synchronizedList(new LinkedList());// *** LDAP connection pool management    
63  	private boolean skipReleaseContext = false;
64  	private String trustStore = System.getProperty("java.home")+"/lib/security/cacerts"; // doesn't do anything anymore because it required tomcat restart
65  	private String trustStorePassword = ""; // doesn't do anything anymore because it required tomcat restart
66  	private String caCertFile = ""; // doesn't do anything anymore because it required tomcat restart
67  	private String accountField = "uid";
68  	private String memberAccountField = "memberUid";
69  	private String groupIdField = "gidNumber";
70      
71      /**
72       * Create a new ldap persistence factory.  This empty constructor is needed by the XML Digester.
73       */
74      public LDAPPersistenceFactory() {
75      	super();
76      }
77      
78      /**
79       * Create a new ldap persistence factory with a configuration.
80       * 
81       * @param configuration
82       */
83      public LDAPPersistenceFactory(Configuration configuration) {
84      	super(configuration);
85      }
86      
87      /**
88       * Create a new ldap persistence factory with a configuration and a name.
89       * 
90       * @param configuration
91       * @param name
92       */
93      public LDAPPersistenceFactory(Configuration configuration, String name) {
94      	super(configuration, name);
95      }
96      
97      /** 
98       * Adds a userDN -> account mapping entry in the "map=mapName" LDAP map.
99       * 
100      * @param userDN the certificate DN of the user (i.e. "/DC=org/DC=doegrids/OU=People/CN=John Smith")
101      * @param account the account to whith to map the DN (i.e. "carcassi")
102      * @param mapName the name of the map (i.e. "usatlasSpecialMap")
103      * @param mapDN the map DN (i.e. "map=usatlasSpecialMap, ou=GUMS")
104      */
105     public void addMapEntry(String userDN, String account, String mapName, String mapDN) {
106         DirContext context = retrieveContext();
107         try {
108             try {
109                 ModificationItem[] mods = new ModificationItem[1];
110                 mods[0] = new ModificationItem(context.ADD_ATTRIBUTE, new BasicAttribute("user", userDN));
111                 context.modifyAttributes("account=" + account + "," + mapDN, mods);
112                 log.trace("Added user '" + userDN + "' / account '" + account + "' to map '" + mapName + "' at '" + mapDN + "' (account entry present)");
113             } catch (NameNotFoundException e) {
114                 Attributes atts = new BasicAttributes();
115                 Attribute oc = new BasicAttribute("objectclass");
116                 oc.add("GUMStruct");
117                 oc.add("GUMSAccount");
118                 Attribute userAtt = new BasicAttribute("user", userDN);
119                 Attribute accountAtt = new BasicAttribute("account", account);
120                 atts.put(oc);
121                 atts.put(userAtt);
122                 atts.put(accountAtt);
123                 context.createSubcontext("account=" + account + "," + mapDN , atts);
124                 log.trace("Added user '" + userDN + "' / account '" + account + "' to map '" + mapName + "' at '" + mapDN + "' (account entry created)");
125             }
126         } catch (Exception e) {
127             log.info("LDAPPersistence error - addMapEntry - user '" + userDN + "' / account '" + account + "' to map '" + mapName + "' at '" + mapDN + "'", e);
128             throw new RuntimeException("Couldn't add mapping to LDAP map - user '" + userDN + "' / account '" + account + "' to map '" + mapName + "' at '" + mapDN + "': " + e.getMessage(), e);
129         } finally {
130             releaseContext(context);
131         }
132     }
133     
134     /** 
135      * Adds the account to the given secondary group.
136      * 
137      * @param account the account to add to the secondary group (i.e. "carcassi")
138      * @param groupname the secondary group name (i.e. "usatlas")
139      */
140     public void addToSecondaryGroup(String account, String groupname) {
141         DirContext context = retrieveContext();
142         try {
143             SearchControls ctrls = new SearchControls();
144             ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
145             NamingEnumeration result;
146            	result = context.search("cn="+groupname+",ou=Group", "("+memberAccountField+"={0})", new Object[] {account}, ctrls);
147             if (result.hasMore()) return;
148             ModificationItem[] mods = new ModificationItem[1];
149             mods[0] = new ModificationItem(context.ADD_ATTRIBUTE, new BasicAttribute(memberAccountField, account));
150             context.modifyAttributes("cn="+groupname+",ou=Group", mods);
151             log.trace("Added secondary group to user - user '" + account + "' to group '" + groupname + "'");
152         } catch (Exception e) {
153             log.info("Couldn't add user to secondary group - user '" + account + "' to group '" + groupname + "'", e);
154             throw new RuntimeException("Couldn't add user to secondary group - user '" + account + "' to group '" + groupname + "': " + e.getMessage(), e);
155         } finally {
156             releaseContext(context);
157         }
158     }
159     
160     /** 
161      * Adds a certificate DN to the group "group=groupName".
162      * 
163      * @param userDN the certificate DN of the user (i.e. "/DC=org/DC=doegrids/OU=People/CN=John Smith")
164      * @param groupName the name of the group (i.e. "usatlas")
165      * @param groupDN the group DN (i.e. "group=usatlas, ou=GUMS")
166      */
167     public void addUserGroupEntry(String userDN, String groupName, String groupDN) {
168         DirContext context = retrieveContext();
169         try {
170             ModificationItem[] mods = new ModificationItem[1];
171             mods[0] = new ModificationItem(context.ADD_ATTRIBUTE,
172                 new BasicAttribute("user", userDN));
173             context.modifyAttributes(groupDN, mods);
174             log.trace("Added user '" + userDN + "' to group '" + groupName + "' at '" + groupDN + "'");
175         } catch (Exception e) {
176             log.info("LDAPPersistence error - addUserGroupEntry - user '" + userDN + "' to group '" + groupName + "' at '" + groupDN + "'", e);
177             throw new RuntimeException("Couldn't add user to LDAP group - user '" + userDN + "' to group '" + groupName + "' at '" + groupDN + "': " + e.getMessage(), e);
178         } finally {
179             releaseContext(context);
180         }
181     }
182 
183     /** 
184      * Changes the primary gid for the given account.
185      * 
186      * @param account the account to change the primary group (i.e. "carcassi")
187      * @param groupname the primary group name (i.e. "usatlas")
188      */
189     public void changeGroupID(String account, String groupname) {
190         String gid = findGID(groupname);
191         if (gid == null) {
192         	log.error("GID for group '" + groupname + "' wasn't found.");
193             throw new RuntimeException("GID for group '" + groupname + "' wasn't found.");
194         }
195         updateGID(account, gid);
196     }
197 
198     public PersistenceFactory clone(Configuration configuration) {
199     	LDAPPersistenceFactory persistenceFactory = new LDAPPersistenceFactory(configuration, new String(getName()));
200     	persistenceFactory.setDescription(new String(getDescription()));
201 //    	persistenceFactory.setCaCertFile(getCaCertFile());
202 //   	persistenceFactory.setTrustStorePassword(getTrustStorePassword());
203     	persistenceFactory.setAccountField(new String(getAccountField()));
204     	persistenceFactory.setGroupIdField(new String(getGroupIdField()));
205     	persistenceFactory.setMemberAccountField(new String(getMemberAccountField()));
206     	persistenceFactory.setProperties((Properties)getProperties().clone());
207     	persistenceFactory.setSynchGroups(persistenceFactory.isSynchGroups());
208     	return persistenceFactory;
209     }
210     
211     /** 
212      * Creates an account in the map "map=mapName", without having a userDN: this is useful
213      * for pools of accounts.
214      * 
215      * @param account the account to whith to map the DN (i.e. "grid0001")
216      * @param mapName the name of the map (i.e. "usatlasSpecialMap")
217      * @param mapDN the map DN (i.e. "map=usatlasSpecialMap, ou=GUMS")
218      */
219     public void createAccountInMap(String account, String mapName, String mapDN) {
220         DirContext context = retrieveContext();
221         try {
222             Attributes atts = new BasicAttributes();
223             Attribute oc = new BasicAttribute("objectclass");
224             oc.add("GUMStruct");
225             oc.add("GUMSAccount");
226             Attribute accountAtt = new BasicAttribute("account", account);
227             atts.put(oc);
228             atts.put(accountAtt);
229             context.createSubcontext("account=" + account + "," + mapDN , atts);
230             log.trace("Added account '" + account + "' to map '" + mapName + "' at '" + mapDN + "'");
231         } catch (Exception e) {
232             log.info("LDAPPersistence error - createAccountInMap - account '" + account + "' to map '" + mapName + "' at '" + mapDN + "'", e);
233             throw new RuntimeException("Couldn't add account to LDAP map - account '" + account + "' to map '" + mapName + "' at '" + mapDN + "': " + e.getMessage(), e);
234         } finally {
235             releaseContext(context);
236         }
237     }
238     
239     /** 
240      * Creates a new "map=mapName" entry in the LDAP GUMS tree.
241      * 
242      * @param mapName the name of the map (i.e. "usatlasSpecialMap")
243      * @param mapDN the map DN (i.e. "map=usatlasSpecialMap, ou=GUMS")
244      */
245     public void createMap(String mapName, String mapDN) {
246         DirContext context = retrieveContext();
247         try {
248             Attributes atts = new BasicAttributes();
249             Attribute oc = new BasicAttribute("objectclass");
250             oc.add("GUMStruct");
251             oc.add("GUMSMap");
252             Attribute map = new BasicAttribute("map", mapName);
253             atts.put(oc);
254             atts.put(map);
255             context.createSubcontext(mapDN , atts);
256             log.trace("Created LDAP map '" + mapName + "' at '" + mapDN + "'");
257         } catch (Exception e) {
258             log.info("LDAPPersistence error - createMap - map '" + mapName + "'", e);
259             throw new RuntimeException("Couldn't create LDAP map '" + mapName + "': " + e.getMessage(), e);
260         } finally {
261             releaseContext(context);
262         }
263     }
264 
265     /** 
266      * Creates a new "group=groupName" entry in the LDAP GUMS tree.
267      * 
268      * @param groupName the name of the group (i.e. "usatlas")
269      * @param groupDN the group DN (i.e. "group=usatlas, ou=GUMS")
270      */
271     public void createUserGroup(String groupName, String groupDN) {
272         DirContext context = retrieveContext();
273         try {
274             Attributes atts = new BasicAttributes();
275             Attribute oc = new BasicAttribute("objectclass");
276             oc.add("GUMStruct");
277             oc.add("GUMSGroup");
278             Attribute group = new BasicAttribute("group", groupName);
279             atts.put(oc);
280             atts.put(group);
281             context.createSubcontext(groupDN , atts);
282             log.trace("Created user group '" + groupName + "' at '" + groupDN + "'");
283         } catch (Exception e) {
284             log.info("LDAPPersistence error - createUserGroup - group '" + groupName + "'", e);
285             throw new RuntimeException("Couldn't create LDAP group '" + groupName + "': " + e.getMessage(), e);
286         } finally {
287             releaseContext(context);
288         }
289     }
290 
291     /** 
292      * Deletes the account in map.
293      * 
294      * @param mapName the name of the map (i.e. "usatlasSpecialMap")
295      * @param mapDN the map DN (i.e. "map=usatlasSpecialMap, ou=GUMS")
296      */
297     public boolean destroyAccountInMap(String account, String mapName, String mapDN) {
298         DirContext context = retrieveContext();
299         try {
300             context.destroySubcontext("account=" + account + "," + mapDN );
301             log.trace("Destroyed LDAP map '" + mapName + "' at '" + mapDN + "'");
302         } catch (Exception e) {
303             log.info("LDAPPersistence error - destroyMap - map '" + mapName + "'", e);
304             throw new RuntimeException("Couldn't destroy LDAP map '" + mapName + "': " + e.getMessage(), e);
305         } finally {
306             releaseContext(context);
307         }
308         return true;
309     }
310     
311     /** 
312      * Deletes the "map=mapName" map in the LDAP GUMS tree. Will completely
313      * delete the map.
314      * 
315      * @param mapName the name of the map (i.e. "usatlasSpecialMap")
316      * @param mapDN the map DN (i.e. "map=usatlasSpecialMap, ou=GUMS")
317      */
318     public void destroyMap(String mapName, String mapDN) {
319         DirContext context = retrieveContext();
320         try {
321             SearchControls ctrls = new SearchControls();
322             ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
323             NamingEnumeration result = context.search(mapDN, "(objectclass=*)", ctrls);
324             while (result.hasMore()) {
325                 SearchResult res = (SearchResult) result.next();
326                 if ("".equals(res.getName().trim())) continue;
327                 context.destroySubcontext(res.getName() + "," + mapDN);
328             }
329             context.destroySubcontext(mapDN);
330             log.trace("Destroyed LDAP map '" + mapName + "' at '" + mapDN + "'");
331         } catch (Exception e) {
332             log.info("LDAPPersistence error - destroyMap - map '" + mapName + "'", e);
333             throw new RuntimeException("Couldn't destroy LDAP map '" + mapName + "': " + e.getMessage(), e);
334         } finally {
335             releaseContext(context);
336         }
337     }    
338 
339     public String getAccountField() {
340     	return accountField;
341     }
342     
343     public String getCaCertFile() {
344     	return caCertFile;
345     }
346     
347     public String getGumsOU() {
348     	return gumsOU;
349     }
350     
351     public String getGroupIdField() {
352     	return groupIdField;
353     }
354     
355     /** 
356      * Returns a Context ready to be used (taken from the pool).
357      * This is the entry point for the pool, and it can be used
358      * by test cases to prepare the LDAP server.
359      * 
360      * @return an LDAP context
361      */
362     public DirContext getLDAPContext() {
363         return retrieveContext();
364     }
365         
366     public String getMemberAccountField() {
367     	return memberAccountField;
368     }
369     
370 
371     public String getTrustStorePassword() {
372     	return trustStorePassword;
373     }
374 
375     public String getType() {
376 		return "ldap";
377 	}
378 
379     /**
380      * This property forces the gid update for account pools at every access.
381      * It's handy for when gids gets out of synch.
382      * 
383      * @return if true gids are updated every time accounts from the pool are returned.
384      */
385     public boolean isSynchGroups() {
386         return this.synchGroups;
387     }
388 
389     /** Returns the LDAP DirContext to the pool, so that it can be reused.
390      * 
391      * @param context the LDAP context to be returned
392      */
393     public void releaseContext(DirContext context) {
394         if (skipReleaseContext) {
395             skipReleaseContext = false;
396             return;
397         }
398         contexts.add(0, context);
399         log.trace("LDAP connection returned to pool " + context);
400     }
401 
402     /** Removes a userDN -> acount mapping entry in the "map=mapName LDAP map.
403      * It will only remove the user entry, while leaving the account entry.
404      * 
405      * @param userDN the certificate DN of the user (i.e. "/DC=org/DC=doegrids/OU=People/CN=Gabriele Carcassi 12345")
406      * @param mapName the name of the map (i.e. "usatlasSpecialMap")
407      * @param mapDN the map DN (i.e. "map=usatlasSpecialMap")
408      * @return false if no mapping was removed
409      */
410     public boolean removeMapEntry(String userDN, String mapName, String mapDN) {
411         DirContext context = retrieveContext();
412         boolean deleted = false;
413         try {
414             SearchControls ctrls = new SearchControls();
415             ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
416             NamingEnumeration result = context.search(mapDN, "(user={0})", new Object[] {userDN}, ctrls);
417             while (result.hasMore()) {
418                 SearchResult res = (SearchResult) result.next();
419                 if ("".equals(res.getName().trim())) continue;
420                 ModificationItem[] mods = new ModificationItem[1];
421                 mods[0] = new ModificationItem(context.REMOVE_ATTRIBUTE, new BasicAttribute("user", userDN));
422                 context.modifyAttributes(res.getName() + "," + mapDN, mods);
423                 deleted = true;
424                 log.trace("Removed map entry - user '" + userDN + "' to map '" + mapName + "' at '" + mapDN + "'");
425             }
426             return deleted;
427         } catch (Exception e) {
428             log.info("LDAPPersistence error - removeMapEntry - user '" + userDN + "' to map '" + mapName + "' at '" + mapDN + "'", e);
429             throw new RuntimeException("Couldn't remove map entry from LDAP map - user '" + userDN + "' to map '" + mapName + "' at '" + mapDN + "': " + e.getMessage(), e);
430         } finally {
431             releaseContext(context);
432         }
433     }
434     
435     /** Removes a certificate DN to the group "group=groupName".
436      * 
437      * @param userDN the certificate DN of the user (i.e. "/DC=org/DC=doegrids/OU=People/CN=Gabriele Carcassi 12345")
438      * @param groupName the name of the group (i.e. "usatlas")
439      * @param groupDN the group DN (i.e. "group=usatlas")
440      */
441     public void removeUserGroupEntry(String userDN, String groupName, String groupDN) {
442         DirContext context = retrieveContext();
443         try {
444             ModificationItem[] mods = new ModificationItem[1];
445             mods[0] = new ModificationItem(context.REMOVE_ATTRIBUTE,
446                 new BasicAttribute("user", userDN));
447             context.modifyAttributes(groupDN, mods);
448             log.trace("Removed user '" + userDN + "' to group '" + groupName + "' at '" + groupDN + "'");
449         } catch (Exception e) {
450             log.info("LDAPPersistence error - removeUserGroupEntry - user '" + userDN + "' to group '" + groupName + "' at '" + groupDN + "'", e);
451             throw new RuntimeException("Couldn't remove user to LDAP group  - user '" + userDN + "' to group '" + groupName + "' at '" + groupDN + "': " + e.getMessage(), e);
452         } finally {
453             releaseContext(context);
454         }
455     }
456     
457     public AccountPoolMapperDB retrieveAccountPoolMapperDB(String nameAndGroups) {
458         StringTokenizer tokens = new StringTokenizer(nameAndGroups, ".");
459         if (!tokens.hasMoreTokens()) {
460             log.trace("Creating LDAP AccountPoolMapperDB '" + nameAndGroups + "' (no GIDs)");
461             return new LDAPAccountMapperDB(this, nameAndGroups);
462         }
463         
464         String pool = tokens.nextToken();
465         if (!tokens.hasMoreTokens()) {
466             log.trace("Creating LDAP AccountPoolMapperDB '" + nameAndGroups + "' (no GIDs)");
467             return new LDAPAccountMapperDB(this, nameAndGroups);
468         }
469         
470         String group = tokens.nextToken();
471         List secondaryGroups = new ArrayList();
472         while (tokens.hasMoreTokens()) {
473             secondaryGroups.add(tokens.nextToken());
474         }
475         
476         log.trace("Creating LDAP AccountPoolMapperDB '" + nameAndGroups + "' primary group '" + group + "' secondary groups '" + secondaryGroups + "'");
477         return new LDAPAccountMapperDB(this, pool, group, secondaryGroups);
478     }
479 
480     /** 
481      * Retrieves an LDAP DirContext from the pool, if available and still valid,
482      * or creates a new DirContext if none are found.
483      * 
484      * @return an LDAP DirContext
485      */
486     public DirContext retrieveContext() {
487         DirContext context;
488         while (contexts.size() != 0) {
489             context = (DirContext) contexts.remove(0);
490             if (isContextValid(context)) {
491                 log.trace("Using LDAP connection from pool " + context);
492                 return context;
493             }
494         }
495         context = createLDAPContext();
496         log.trace("New LDAP connection created " + context);
497         return context;
498     }
499     
500     public ManualAccountMapperDB retrieveManualAccountMapperDB(String name) {
501         log.trace("Creating LDAP ManualAccountMapperDB '" + name + "'");
502         return new LDAPAccountMapperDB(this, name);
503     }
504     
505     public ManualUserGroupDB retrieveManualUserGroupDB(String name) {
506         log.trace("Creating LDAP ManualUserGroupDB '" + name + "'");
507         return new LDAPUserGroupDB(this, name);
508     }
509     
510     public UserGroupDB retrieveUserGroupDB(String name) {
511         log.trace("Creating LDAP UserGroupDB '" + name + "'");
512         return new LDAPUserGroupDB(this, name);
513     }
514 
515     public void setAccountField(String accountField) {
516     	this.accountField = accountField;
517     }
518     
519     public void setCaCertFile(String caCertFile) {
520        	//System.setProperty("javax.net.ssl.trustStore", trustStore );
521     	this.caCertFile = caCertFile;
522     	//if (!trustStorePassword.equals(""))
523     		//addCertToTrustStore();
524     }
525     
526     public void setGroupIdField(String groupIdField) {
527     	this.groupIdField = groupIdField;
528     }
529     
530     public void setMemberAccountField(String memberAccountField) {
531     	this.memberAccountField = memberAccountField;
532     }
533     
534     /**
535      * Sets the list of properties to be used to connect to LDAP, that is
536      * to create the JNDI context.
537      * 
538      * @param properties a set of JNDI properties
539      */
540     public void setProperties(Properties properties) {
541         if (properties.getProperty("java.naming.factory.initial") == null) {
542             properties.put("java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory");
543         }
544         
545         // For JUnit test only
546         /*if (properties.getProperty("caCertFile")!=null) {
547         	setCaCertFile(properties.getProperty("caCertFile"));
548         	properties.remove("caCertFile");
549         }
550         if (properties.getProperty("trustStorePassword")!=null) {
551         	setTrustStorePassword(properties.getProperty("trustStorePassword"));
552         	properties.remove("trustStorePassword");
553         }*/
554 
555         super.setProperties(properties);
556     }
557 
558     /**
559      * This property forces the gid update for account pools at every access.
560      * It's handy for when gids gets out of synch.
561      * @param synchGroups if true gids are updated every time accounts from the pool are returned.
562      */
563     public void setSynchGroups(boolean synchGroups) {
564         this.synchGroups = synchGroups;
565     }
566     
567     public void setTrustStorePassword(String trustStorePassword) {
568        	//System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword );
569         this.trustStorePassword = trustStorePassword;
570     	//if (!caCertFile.equals(""))
571     		//addCertToTrustStore();
572     }
573     
574     public String toXML() {
575     	String retStr = "\t\t<ldapPersistenceFactory\n"+
576     		"\t\t\tname='"+getName()+"'\n"+
577     		"\t\t\tdescription='"+getDescription()+"'\n"+
578     		"\t\t\tsynchGroups='"+synchGroups+"'\n"+
579 //			"\t\t\tcaCertFile='"+getCaCertFile()+"'\n"+
580 //			"\t\t\ttrustStorePassword='"+trustStorePassword+"'\n"+
581 			"\t\t\tgroupIdField='"+groupIdField+"'\n"+
582 			"\t\t\taccountField='"+accountField+"'\n"+
583 			"\t\t\tmemberAccountField='"+memberAccountField+"'\n";
584     	
585     	Iterator keyIt = getProperties().keySet().iterator();
586     	while(keyIt.hasNext()) {
587     		String key = (String)keyIt.next();
588     		retStr += "\t\t\t"+key+"='"+getProperties().getProperty(key)+"'\n";
589     	}
590 
591     	if (retStr.charAt(retStr.length()-1)=='\n')
592     		retStr = retStr.substring(0, retStr.length()-1);    	
593     	
594     	retStr += "/>\n\n";
595     	
596     	return retStr;
597 	}
598     
599     private void addCertToTrustStore() {
600     	X509Certificate cert = null;
601     	try {
602 			InputStream inStream = new FileInputStream(caCertFile);
603 			CertificateFactory cf = CertificateFactory.getInstance("X.509");
604 			cert = (X509Certificate)cf.generateCertificate(inStream);
605 			inStream.close();
606 		} catch (Exception e) {
607             log.error("Cannot open " + caCertFile, e);
608             adminLog.error("Cannot open " + caCertFile + ": " + e.getMessage());
609             return;
610 		}
611 		try {
612 			KeyStore ks = KeyStore.getInstance("jks");
613 			ks.load(new FileInputStream(trustStore), trustStorePassword.toCharArray());
614 			ks.setCertificateEntry("gumsldapda", cert);
615 			FileOutputStream fos = new FileOutputStream(trustStore);
616 			ks.store(fos, trustStorePassword.toCharArray());
617 			fos.close();
618 		} catch (Exception e) {
619             log.error("Couldn't put " + caCertFile + " into trust store", e);
620             adminLog.error("Couldn't put " + caCertFile + " into trust store: " + e.getMessage() );
621 		}
622     }
623     
624     private String findGID(String groupname) {
625         DirContext context = retrieveContext();
626         try {
627             NamingEnumeration result = context.search("ou=Group", "(cn={0})", new Object[] {groupname}, null);
628             String gid = null;
629             if (result.hasMore()) {
630                 SearchResult item = (SearchResult) result.next();
631                 Attributes atts = item.getAttributes();
632                 Attribute gidAtt = atts.get(groupIdField);
633                 if (gidAtt != null) {
634                     gid = (String) gidAtt.get();
635                 }
636             }
637             log.trace("Found gid '" + gid + "' for group '" + groupname + "'");
638             return gid;
639         } catch (Exception e) {
640             log.info("Couldn't retrieve gid for '" + groupname + "'", e);
641             throw new RuntimeException("Couldn't retrieve gid for '" + groupname + "': " + e.getMessage(), e);
642         } finally {
643             releaseContext(context);
644         }
645     }
646     
647     private boolean isContextValid(DirContext context) {
648         try {
649             context.search(gumsOU, "(map=*)", null);
650             return true;
651         } catch (Exception e) {
652             log.trace("Removing stale LDAP connection from pool " + context, e);
653             adminLog.warn("LDAP connection test failed, discarding connection from pool: " + e.getMessage());
654             return false;
655         }
656     }
657     
658     private void updateGID(String account, String gid) {
659         DirContext context = retrieveContext();
660         try {
661             ModificationItem[] mods = new ModificationItem[1];
662             mods[0] = new ModificationItem(context.REPLACE_ATTRIBUTE, new BasicAttribute(groupIdField, gid));
663             context.modifyAttributes(accountField+"="+account+",ou=People", mods);
664             log.trace("Changed primary gid for user '" + account + "' to gid '" + gid + "''");
665         } catch (Exception e) {
666             log.warn("Couldn't change gid for user '" + account + "' to gid '" + gid + "''", e);
667             throw new RuntimeException("Couldn't change gid for user '" + account + "' to gid '" + gid + "''", e);
668         } finally {
669             releaseContext(context);
670         }
671     }
672     
673     /** Create a new LDAP DirContext based on the configuration.
674      * 
675      * @return a new LDAP DirContext
676      */
677     protected DirContext createLDAPContext() {
678         try {
679             log.info("Trying to create LDAP connection with properties: " + getProperties());
680             return new InitialLdapContext(getProperties(), null);
681         } catch (NamingException e) {
682             log.warn("Couldn't create LDAP connection: " + e.getMessage() + " - parameters: " + getProperties(), e);
683             throw new RuntimeException("Couldn't create LDAP connection: " + e.getMessage());
684         }
685     }
686 
687 }