View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  
21  
22  package org.apache.james.userrepository;
23  
24  import org.apache.avalon.framework.activity.Initializable;
25  import org.apache.avalon.framework.configuration.Configurable;
26  import org.apache.avalon.framework.configuration.Configuration;
27  import org.apache.avalon.framework.configuration.ConfigurationException;
28  import org.apache.james.api.user.User;
29  import org.apache.james.impl.jamesuser.AbstractUsersRepository;
30  import org.apache.james.impl.user.DefaultUser;
31  
32  import javax.naming.AuthenticationException;
33  import javax.naming.NamingEnumeration;
34  import javax.naming.NamingException;
35  import javax.naming.directory.Attribute;
36  import javax.naming.directory.Attributes;
37  import javax.naming.directory.BasicAttribute;
38  import javax.naming.directory.BasicAttributes;
39  import javax.naming.directory.DirContext;
40  import javax.naming.directory.InitialDirContext;
41  import javax.naming.directory.ModificationItem;
42  import javax.naming.directory.SearchControls;
43  import javax.naming.directory.SearchResult;
44  
45  import java.util.ArrayList;
46  import java.util.Hashtable;
47  import java.util.Iterator;
48  import java.util.List;
49  
50  /**
51   * Implementation of a Repository to store users.
52   *
53   * This clas is a dummy for the proposal!
54   *
55   * TODO: Check for aliases (mail attribute) 
56   * 
57   * @version This is $Revision: 521427 $
58   */
59  public class UsersLDAPRepository
60      extends AbstractUsersRepository
61      implements Configurable, Initializable{
62  
63      private DirContext ctx;
64  
65      private String LDAPHost;
66      private String rootNodeDN;
67      private String rootURL;
68      private String serverRDN;
69      private String baseNodeDN;
70      private String baseURL;
71      private String mailAddressAttr;
72      private String identAttr;
73      private String authType;
74      private String principal;
75      private String password;
76      private String usersDomain;
77      private String membersAttr;
78      private boolean manageGroupAttr;
79      private String groupAttr;
80      private boolean managePasswordAttr;
81      private String passwordAttr;
82      private SearchControls searchControls = new SearchControls();
83  
84      /**
85       * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
86       */
87      public void configure(Configuration conf) throws ConfigurationException {
88          super.configure(conf);
89  
90          //TODO: Take care of baseNodeDN
91          LDAPHost = conf.getChild("LDAPServer").getValue();
92          usersDomain = conf.getChild("domain").getValue("localhost");
93          rootNodeDN = conf.getChild("LDAPRoot").getValue();
94          serverRDN = conf.getChild("ThisServerRDN").getValue();
95          mailAddressAttr
96              = conf.getChild("MailAddressAttribute").getValue();
97          identAttr = conf.getChild("IdentityAttribute").getValue();
98          authType = conf.getChild("AuthenticationType").getValue();
99          principal = conf.getChild("Principal").getValue();
100         password = conf.getChild("Password").getValue();
101 
102         membersAttr = conf.getChild("MembersAttribute").getValue();
103         manageGroupAttr = conf.getChild("ManageGroupAttribute").getValueAsBoolean( false );
104         
105         // Check if groupAttr is needed
106         if (manageGroupAttr == true) {
107             groupAttr = conf.getChild("GroupAttribute").getValue();
108         }
109         
110         managePasswordAttr = conf.getChild("ManagePasswordAttribute").getValueAsBoolean( false );
111         
112         // Check if passwordAttr is needed
113         if (managePasswordAttr) {
114             passwordAttr = conf.getChild("PasswordAttribute").getValue();
115         }
116     }
117 
118     public void setServerRoot() {
119         StringBuffer serverRootBuffer =
120             new StringBuffer(128)
121                     .append(serverRDN)
122                     .append(", ")
123                     .append(rootNodeDN);
124         this.setBase(serverRootBuffer.toString());
125     }
126 
127     public void setBase(String base) {
128         baseNodeDN = base;
129     }
130 
131     /**
132      * @see org.apache.avalon.framework.activity.Initializable#initialize()
133      */
134     public void initialize() throws Exception {
135         //setServerRoot();
136         StringBuffer urlBuffer =
137             new StringBuffer(128)
138                     .append(LDAPHost)
139                     .append("/");
140         rootURL = urlBuffer.toString() + rootNodeDN;
141         baseURL = urlBuffer.toString(); // + baseNodeDN;
142 
143         getLogger().info("Creating initial context from " + baseURL);
144 
145         Hashtable env = new Hashtable();
146         env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY,
147                 "com.sun.jndi.ldap.LdapCtxFactory");
148         env.put(javax.naming.Context.PROVIDER_URL, baseURL);
149         
150         env.put(javax.naming.Context.SECURITY_AUTHENTICATION, authType);
151         env.put(javax.naming.Context.SECURITY_PRINCIPAL, principal);
152         env.put(javax.naming.Context.SECURITY_CREDENTIALS, password);
153         
154         searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
155 
156 
157         ctx = new InitialDirContext(env); // Could throw a NamingExcpetion
158 
159 
160         getLogger().info("Initial context initialized from " + baseURL);
161     }
162 
163 
164 
165     public String getChildDestination(String childName) {
166 
167         String destination = null;
168         String filter = "cn=" + childName;
169         SearchControls ctls = new SearchControls();
170 
171         try {
172 
173             NamingEnumeration result  = ctx.search("", filter, ctls);
174 
175             if (result.hasMore()) {
176                 StringBuffer destinationBuffer =
177                     new StringBuffer(128)
178                             .append("cn=")
179                             .append(childName)
180                             .append(", ")
181                             .append(baseNodeDN);
182                 destination = destinationBuffer.toString();
183                 getLogger().info("Pre-exisisting LDAP node: " + destination);
184             } else {
185                 Attributes attrs = new BasicAttributes(true);
186                 Attribute objclass = new BasicAttribute("objectclass");
187                 objclass.add("top");
188                 objclass.add("rfc822MailGroup");
189                 attrs.put(objclass);
190                 Attribute cname = new BasicAttribute("cn");
191                 cname.add(childName);
192                 attrs.put(cname);
193                 Attribute owner = new BasicAttribute("owner");
194                 owner.add("JAMES-unassigned");
195                 attrs.put(owner);
196 /*
197                 ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType);
198                 ctx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal);
199                 ctx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password);
200 */
201                 ctx.createSubcontext("cn=" + childName, attrs);
202 //                ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none");
203 
204                 StringBuffer destinationBuffer =
205                     new StringBuffer(128)
206                             .append("cn=")
207                             .append(childName)
208                             .append(", ")
209                             .append(baseNodeDN);
210                 destination = destinationBuffer.toString();
211                 getLogger().info("Created new LDAP node: " + destination);
212             }
213         } catch (NamingException e) {
214             getLogger().error("Problem with child nodes " + e.getMessage(), e);
215         }
216 
217         return destination;
218     }
219 
220     /**
221      * List users in repository.
222      *
223      * @return Iterator over a collection of Strings, each being one user in the repository.
224      */
225     public Iterator list() {
226         return getUsers().iterator();
227     }
228     
229     /**
230      * Update the repository with the specified user object.  Unsupported for
231      * this user repository type.
232      *
233      * @return false
234      */
235     public boolean addUser(User user) {
236         return false;
237     }
238 
239     /**
240      * @see org.apache.james.api.user.UsersRepository#getUserByName(java.lang.String)
241      */
242     public  User getUserByName(String name) {
243         return new DefaultUser("dummy", "dummy");
244     }
245 
246     /**
247      * @see org.apache.james.api.user.UsersRepository#getUserByNameCaseInsensitive(java.lang.String)
248      */
249     public User getUserByNameCaseInsensitive(String name) {
250         return getUserByName(name);
251     }
252 
253     /**
254      * @see org.apache.james.api.user.UsersRepository#containsCaseInsensitive(java.lang.String)
255      */
256     public boolean containsCaseInsensitive(String name) {
257         return getUsers().contains(name);
258     }
259 
260     /**
261      * @see org.apache.james.api.user.UsersRepository#getRealName(java.lang.String)
262      */
263     public String getRealName(String name) {
264         return getRealName(name, ignoreCase);
265     }
266     
267     /**
268      * Return the real name, given the ignoreCase boolean parameter
269      */
270     public String getRealName(String name, boolean ignoreCase) {
271         Iterator it = list();
272         while (it.hasNext()) {
273             String temp = (String) it.next();     
274             if (ignoreCase) {
275                 if (name.equalsIgnoreCase(temp)) {
276                     return temp;
277                 }
278             } else {
279                 if (name.equals(temp)) {
280                     return temp;
281                 }     
282             }
283         }
284         return null;
285     }
286 
287     /**
288      * @see org.apache.james.api.user.UsersRepository#updateUser(org.apache.james.api.user.User)
289      */
290     public boolean updateUser(User user) {
291         return false;
292     }
293     
294     /**
295      * @see org.apache.james.api.user.UsersRepository#addUser(java.lang.String, java.lang.String)
296      */
297     public boolean addUser(String username, String password) {
298         if (!contains(username)) {
299             addUser(username, password);
300             return contains(username);
301         } else {
302             return false;
303         }
304     }
305 
306     private void addGroupToUser(String userName) {
307         String[] attrIDs = {membersAttr};
308 
309         Hashtable env = new Hashtable();
310         env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
311         env.put(javax.naming.Context.PROVIDER_URL, rootURL);
312 
313         DirContext rootCtx = null;
314         try {
315             rootCtx = new InitialDirContext(env);
316 
317             String[] returnAttrs = {groupAttr};
318             SearchControls ctls = new SearchControls();
319             ctls.setReturningAttributes(attrIDs);
320             ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
321             StringBuffer filterBuffer =
322                 new StringBuffer(128)
323                         .append(mailAddressAttr)
324                         .append("=")
325                         .append(userName)
326                         .append("@")
327                         .append(usersDomain);
328             String filter = filterBuffer.toString();
329 
330             NamingEnumeration enumeration  = rootCtx.search("", filter, ctls);
331 
332             if (enumeration.hasMore()) { // ie User is in Directory
333                 SearchResult newSr = (SearchResult)enumeration.next();
334                 String userDN = newSr.getName();
335                 Attribute servers = rootCtx.getAttributes(userDN, returnAttrs).get(groupAttr);
336 
337 
338                 if (servers != null && servers.contains(baseNodeDN)) {//server already registered for user
339                     getLogger().info(baseNodeDN + " already in user's Groups. " );
340                     //System.out.println(baseNodeDN + " already in user's Groups. ");
341 
342                 } else {
343 /*
344                     rootCtx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType);
345                     rootCtx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal);
346                     rootCtx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password);
347 */
348                     rootCtx.modifyAttributes(userDN, DirContext.ADD_ATTRIBUTE, new BasicAttributes(groupAttr, baseNodeDN, true));
349 
350                     //rootCtx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none");
351                     getLogger().info(baseNodeDN + " added to user's groups ");
352                     //System.out.println(baseNodeDN + " added to users' groups ");
353 
354                 }
355 
356             } else {
357                 StringBuffer infoBuffer =
358                     new StringBuffer(64)
359                             .append("User ")
360                             .append(userName)
361                             .append(" not in directory.");
362                 getLogger().info(infoBuffer.toString());
363                 // System.out.println(infoBuffer.toString());
364 
365             }
366         } catch (NamingException e) {
367             getLogger().error("Problem adding group to user " + userName);
368             //System.out.println("Problem adding group to user " + userName);
369             //System.out.println(e.getMessage());
370             //e.printStackTrace();
371         } finally {
372             closeDirContext(rootCtx);
373         }
374     }
375 
376     /**
377      * @see org.apache.james.api.user.UsersRepository#removeUser(java.lang.String)
378      */
379     public synchronized void removeUser(String userName) {
380         String[] attrIDs = {membersAttr};
381 
382         try {
383             Attribute members = ctx.getAttributes("", attrIDs).get(membersAttr);
384             if (members == null) {
385                 System.out.println("UsersLDAPRepository - Null list attribute.");
386 
387             } else  if (!members.contains(userName)) {//user not here
388                 getLogger().info(userName + " missing from mailGroup. ");
389                 //System.out.println(userName + " missing from mailGroup. ");
390 
391             } else {
392                 // First, remove username from mailGroup at baseNode
393 /*
394                 ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType);
395                 ctx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal);
396                 ctx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password);
397 */
398                 ModificationItem[] mods = new ModificationItem[1];
399                 mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute(membersAttr, userName));
400 
401                 ctx.modifyAttributes("", mods);
402 
403 
404 //                ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none");
405                 getLogger().info(userName + " removed from mailGroup. ");
406                 //System.out.println(userName + " removed from mailGroup. ");
407             }
408         } catch (NamingException e) {
409             StringBuffer exceptionBuffer =
410                 new StringBuffer(256)
411                         .append("Problem removing user ")
412                         .append(userName)
413                         .append(": ")
414                         .append(e);
415             getLogger().error(exceptionBuffer.toString());
416             //System.out.println("Problem removing user " + userName);
417             //System.out.println(e.getMessage());
418             //e.printStackTrace();
419         }
420         if (manageGroupAttr) {
421             removeGroupFromUser(userName);
422         }
423 
424         if (managePasswordAttr) {
425             // not yet implemented
426         }
427 
428     }
429 
430     public void removeGroupFromUser(String userName) {
431 
432         Hashtable env = new Hashtable();
433         env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
434         env.put(javax.naming.Context.PROVIDER_URL, rootURL);
435 
436 
437         DirContext rootCtx = null;
438         try {
439             rootCtx = new InitialDirContext(env);
440 
441             // Find directory entry
442             String[] returnAttrs = {groupAttr};
443             SearchControls ctls = new SearchControls();
444             ctls.setReturningAttributes(returnAttrs);
445             ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
446             StringBuffer filterBuffer =
447                 new StringBuffer(128)
448                         .append(mailAddressAttr)
449                         .append("=")
450                         .append(userName)
451                         .append("@")
452                         .append(usersDomain);
453             String filter = filterBuffer.toString();
454 
455             NamingEnumeration enumeration  = rootCtx.search("", filter, ctls);
456 
457             if (enumeration.hasMore()) { // ie User is in Directory
458                 SearchResult newSr = (SearchResult)enumeration.next();
459                 String userDN = newSr.getName();
460 
461                 System.out.println("Found user entry: " + userDN);
462 
463                 Attribute servers = rootCtx.getAttributes(userDN, returnAttrs).get(groupAttr);
464                 if (servers == null) { //should not happen
465                     getLogger().info("GroupAttribute missing from user: " + userName);
466                     // System.out.println("GroupAttribute missing from user: " + userName );
467 
468                 } else if (!servers.contains(baseNodeDN)) {//server not registered for user
469                     getLogger().info(baseNodeDN + " missing from users' Groups. " );
470                     //System.out.println(baseNodeDN + " missing from users' Groups. ");
471 
472                 } else {
473 /*
474                     rootCtx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType);
475                     rootCtx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal);
476                     rootCtx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password);
477 */
478                     ModificationItem[] mods = new ModificationItem[1];
479                     mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute(groupAttr, baseNodeDN));
480 
481                     rootCtx.modifyAttributes(userDN, mods);
482 
483                     //rootCtx.modifyAttributes(userDN, DirContext.REPLACE_ATTRIBUTE, changes);
484 
485 //                    rootCtx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none");
486                     getLogger().info(baseNodeDN + " removed from users' groups " );
487                     //System.out.println(baseNodeDN + " removed from users' groups ");
488 
489                 }
490 
491             } else {
492                 StringBuffer infoBuffer =
493                     new StringBuffer(64)
494                             .append("User ")
495                             .append(userName)
496                             .append(" not in directory.");
497                 getLogger().info(infoBuffer.toString());
498                 //System.out.println(infoBuffer.toString());
499 
500             }
501         } catch (NamingException e) {
502             StringBuffer exceptionBuffer =
503                 new StringBuffer(256)
504                         .append("Problem removing user ")
505                         .append(userName)
506                         .append(e);
507             getLogger().error(exceptionBuffer.toString());
508             //System.out.println("Problem removing user " + userName);
509             //System.out.println(e.getMessage());
510             //e.printStackTrace();
511         } finally {
512             closeDirContext(rootCtx);
513             rootCtx = null;
514         }
515     }
516 
517 
518     /**
519      * @see org.apache.james.api.user.UsersRepository#contains(java.lang.String)
520      */
521     public boolean contains(String name) {
522         boolean found = false;
523         if (ignoreCase) {
524             if(containsCaseInsensitive(name)) {
525                 found = true;
526             }
527         } else {
528            Iterator it = list();
529            
530            while (it.hasNext()) {
531                if (name.equals(it.next())) {
532                    found = true;
533                }
534            }
535         }
536         
537         if(found) {
538             StringBuffer infoBuffer =
539                 new StringBuffer(64)
540                         .append("Found ")
541                         .append(name)
542                         .append(" in mailGroup. ");
543             getLogger().info(infoBuffer.toString());
544             return true;
545         }
546         return false;
547     }
548 
549 
550     /**
551      * @see org.apache.james.api.user.UsersRepository#test(java.lang.String, java.lang.String)
552      */
553     public boolean test(String name, String testPassword) {
554         boolean result = false;
555         boolean foundFlag = false;
556         String userDN = null;
557 
558         try {
559             String[] returnAttrs = {identAttr, passwordAttr};
560             SearchControls ctls = new SearchControls();
561             ctls.setReturningAttributes(returnAttrs);
562             ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
563             StringBuffer filterBuffer = 
564                 new StringBuffer(128)
565                         .append(mailAddressAttr)
566                         .append("=")
567                         .append(name)
568                         .append("@")
569                         .append(usersDomain);
570             String filter = filterBuffer.toString();
571 
572             Hashtable env = new Hashtable();
573             env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
574             env.put(javax.naming.Context.PROVIDER_URL, rootURL);
575             DirContext rootCtx = null;
576 
577             try {
578                 rootCtx = new InitialDirContext(env);
579     
580                 NamingEnumeration enumeration  = rootCtx.search("", filter, ctls);
581                 if (enumeration.hasMore()) { // ie User is in Directory
582                     SearchResult sr = (SearchResult)enumeration.next();
583                     String userRDN = sr.getName();
584                     StringBuffer userDNBuffer =
585                         new StringBuffer(128)
586                                 .append(userRDN)
587                                 .append(", ")
588                                 .append(rootNodeDN);
589                     userDN = userDNBuffer.toString();
590                     foundFlag = true;
591                     //System.out.println("UserDN is : " + userDN);
592                 }
593             } finally {
594                 closeDirContext(rootCtx);
595             }
596         } catch (Exception e) {
597             StringBuffer exceptionBuffer =
598                 new StringBuffer(256)
599                         .append("Problem finding user ")
600                         .append(name)
601                         .append(" for password test.")
602                         .append(e); 
603             getLogger().error(exceptionBuffer.toString());
604             //e.getMessage();
605             //e.printStackTrace();
606         }
607 
608         if (foundFlag) { // ie User is in Directory
609             Hashtable env2 = new Hashtable();
610             env2.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
611             env2.put(javax.naming.Context.PROVIDER_URL, rootURL);
612             env2.put(javax.naming.Context.SECURITY_AUTHENTICATION, "simple");
613             env2.put(javax.naming.Context.SECURITY_PRINCIPAL, userDN);
614             env2.put(javax.naming.Context.SECURITY_CREDENTIALS, testPassword);
615             //System.out.println("Creating initial context from " + baseURL);
616 
617             DirContext testCtx = null;
618             try {
619                 testCtx = new InitialDirContext(env2);
620                 result = true;
621 
622             } catch (AuthenticationException ae) {
623                 result = false;
624                 StringBuffer exceptionBuffer =
625                     new StringBuffer(256)
626                             .append("Attempt to authenticate with incorrect password for ")
627                             .append(name)
628                             .append(" : ")
629                             .append(ae); 
630                 getLogger().error(exceptionBuffer.toString());
631                 //System.out.println(exceptionBuffer.toString());
632                 //System.out.println(ae.getMessage());
633                 //ae.printStackTrace();
634             } catch (Exception e) {
635                 StringBuffer exceptionBuffer =
636                     new StringBuffer(256)
637                             .append("Problem checking password for ")
638                             .append(name)
639                             .append(" : ")
640                             .append(e); 
641                 getLogger().error(exceptionBuffer.toString());
642                 //System.out.println(exceptionBuffer.toString());
643                 //System.out.println(e.getMessage());
644                 //e.printStackTrace();
645             } finally {
646                 closeDirContext(testCtx);
647             }
648         }
649         return result;
650 
651     }
652 
653     /**
654      * @see org.apache.james.api.user.UsersRepository#countUsers()
655      */
656     public int countUsers() {
657         return getUsers().size();
658     }
659 
660     /**
661      * Disposes of all open directory contexts
662      *
663      * @throws Exception if an error is encountered during shutdown
664      */
665     public void dispose() throws Exception {
666         closeDirContext(ctx);
667         ctx = null;
668     }
669 
670     private void closeDirContext(DirContext ctx) {
671         try {
672             if (ctx != null) {
673                 ctx.close();
674             }
675         } catch (NamingException ne) {
676             getLogger().warn("UsersLDAPRepository: Unexpected exception encountered while closing directory context: " + ne);
677         }
678     }
679 
680 
681     /**
682      * Adds userName to the MemberAttribute (specified in conf.xml) of this
683      * node.
684      * If ManageGroupAttribute (conf.xml) is TRUE then calls addGroupToUser.
685      */
686     protected void doAddUser(User user) {
687         String userName = user.getUserName();
688         
689         String[] attrIDs = {membersAttr};
690 
691         // First, add username to mailGroup at baseNode
692 
693         try {
694             Attribute members = ctx.getAttributes("", attrIDs).get(membersAttr);
695 
696 
697             if (members != null && members.contains(userName)) {//user already here
698                 StringBuffer infoBuffer =
699                     new StringBuffer(64)
700                             .append("Found ")
701                             .append(userName)
702                             .append(" already in mailGroup. ");
703                 getLogger().info(infoBuffer.toString());
704                 //System.out.println(infoBuffer.toString());
705 
706             } else {
707              /*
708             ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType);
709                 ctx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal);
710                 ctx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password);
711 */
712                 ModificationItem[] mods = new ModificationItem[1];
713                 mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute(membersAttr, userName));
714 
715                 ctx.modifyAttributes("", mods);
716 
717 //                ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none");
718                 StringBuffer infoBuffer =
719                     new StringBuffer(128)
720                             .append(userName)
721                             .append(" added to mailGroup ")
722                             .append(baseNodeDN);
723                 getLogger().info(infoBuffer.toString());
724                 //System.out.println(infoBuffer.toString());
725             }
726         } catch (NamingException e) {
727             StringBuffer exceptionBuffer =
728                 new StringBuffer(256)
729                         .append("Problem adding user ")
730                         .append(userName)
731                         .append(" to: ")
732                         .append(baseNodeDN)
733                         .append(e);
734             getLogger().error(exceptionBuffer.toString());
735         }
736 
737         // Add attributes to user objects, if necessary
738 
739         if (manageGroupAttr) {
740             addGroupToUser(userName);
741         }
742 
743 //        if (managePasswordAttr) {
744 //            String userPassword = (String) attributes; // Not yet implemented
745 //        }
746     }
747 
748     protected void doUpdateUser(User user) {
749         // Do nothing
750     }
751     
752     /**
753      * Return a list of all users
754      * 
755      * @return
756      */
757     private List getUsers() {
758         List result = new ArrayList();
759         String filter = mailAddressAttr + "=*";
760 
761         try {
762             NamingEnumeration results = ctx.search(rootNodeDN, filter, searchControls);
763             
764             while (results != null && results.hasMore()) {
765                 Attributes members = ((SearchResult) results.next()).getAttributes();
766        
767                 if (members != null) {
768 
769                     Attribute attr = members.get(identAttr);
770                     if (attr != null) {
771                         NamingEnumeration e = attr.getAll();
772                         while (e.hasMore()) {
773                             result.add(e.next());
774                         }
775                     }
776                 }
777             }
778         } catch (NamingException e) {
779             getLogger().error("Problem listing mailboxes. " + e );
780 
781         }
782         return result;
783     }
784 }
785 
786