KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jetspeed > services > ldap > LDAPService


1 /*
2  * Copyright 2000-2001,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.jetspeed.services.ldap;
18
19 import java.util.Enumeration;
20 import java.util.Hashtable;
21 import java.util.Properties;
22 import java.util.StringTokenizer;
23 import java.util.Vector;
24 import javax.naming.AuthenticationException;
25 import javax.naming.CommunicationException;
26 import javax.naming.Context;
27 import javax.naming.Name;
28 import javax.naming.NameNotFoundException;
29 import javax.naming.NameParser;
30 import javax.naming.NamingEnumeration;
31 import javax.naming.NamingException;
32 import javax.naming.ReferralException;
33 import javax.naming.directory.Attribute;
34 import javax.naming.directory.Attributes;
35 import javax.naming.directory.DirContext;
36 import javax.naming.directory.InitialDirContext;
37 import javax.naming.directory.ModificationItem;
38 import javax.naming.directory.SearchControls;
39 import javax.naming.directory.SearchResult;
40 import javax.servlet.ServletConfig;
41
42 // Turbine classes
43
import org.apache.turbine.services.InitializationException;
44 import org.apache.turbine.services.TurbineBaseService;
45 import org.apache.turbine.services.TurbineServices;
46 import org.apache.turbine.services.resources.ResourceService;
47
48 // Jetspeed classes
49
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
50 import org.apache.jetspeed.services.logging.JetspeedLogger;
51
52 /**
53  *
54  * @author <a HREF="mailto:ender@kilicoglu.nom.tr">Ender KILICOGLU</a>
55  * @author <a HREF="mailto:sami.leino@netorek.fi">Sami Leino</a>
56  *
57  * @version $Id: LDAPService.java,v 1.6 2004/02/23 03:28:31 jford Exp $
58  *
59  */

60 public class LDAPService extends TurbineBaseService
61 {
62     /**
63      * Static initialization of the logger for this class
64      */

65     private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(LDAPService.class.getName());
66     
67     public static String SERVICE_NAME = "ldap";
68     private static final String DEFAULT_ATTR[] = {
69         "objectclass"
70     };
71     public static final int BASE = 0;
72     public static final int ONE = 1;
73     public static final int SUB = 2;
74     public static final int DEFAULT_PORT = 389;
75     public static final int DEFAULT_SSLPORT = 636;
76     public static final int DEFAULT_LIMIT = 0;
77     public static final int DEFAULT_TIMEOUT = 0;
78     public static final int DEFAULT_VERSION = 3;
79     private static String DEFAULT_CTX = "com.sun.jndi.ldap.LdapCtxFactory";
80
81     private Hashtable connections;
82     private Connector connector;
83     private int limit;
84     private int timeout;
85     private int version;
86     private String host;
87     private int port;
88     private int sslport;
89     private String basedn;
90     private String managerdn;
91     private String password;
92     private String managerlogin;
93     private int batchsize;
94     private String securityAuthentication;
95     private String securityProtocol;
96     private String socketFactory;
97     private String saslclientpckgs;
98     private String jndiprovider;
99     private boolean anonymousBind;
100     private String listFilter;
101     private String attributesList[];
102     private NameParser parser;
103     private boolean showOpAttributes;
104     private boolean useCachedDirContexts;
105     private Properties env;
106
107     /**
108      * Main Connection Function
109      *
110      * Make first connection and store it in connections.
111      *
112      * @param url <code>LDAPURL</code> which locate server to connect.
113      * @return boolean true if success else false.
114      */

115     private boolean mainConnect(LDAPURL url)
116     {
117         setDefaultEnv();
118         String base = url.getBase();
119         env.put("java.naming.provider.url", base);
120         try
121         {
122             DirContext ctx = new InitialDirContext(env);
123             if (useCachedDirContexts)
124             {
125                 connections.put(basedn, ctx);
126             }
127             if(parser == null) parser = ctx.getNameParser("");
128             return true;
129         }
130         catch(NamingException e)
131         {
132             logger.error ("LDAP Service: Failed to connect to " + url.getUrl(), e);
133         }
134         return false;
135     }
136
137     /**
138      * Connection Function
139      *
140      * tries to connect given <code>LDAPURL</code>.
141      *
142      * @param url <code>LDAPURL</code> which locate server to connect.
143      * @return DirContext connection context object.
144      */

145     public DirContext connect(LDAPURL url)
146     {
147
148         String base = url.getBase();
149         DirContext ctx = (DirContext)connections.get(base);
150         if(ctx != null)
151         {
152             // System.out.println("LDAPService: returning cached context.");
153
// System.out.println("LDAPService: DN is " + url.getDN());
154
return ctx;
155         }
156         else
157         {
158             // System.out.println("LDAPService: creating new context for base " + base);
159
// System.out.println("LDAPService: DN is " + url.getDN());
160
}
161         
162         setDefaultEnv();
163         env.put("java.naming.provider.url", base);
164         do
165         {
166             try
167             {
168                 ctx = new InitialDirContext(env);
169                 if (useCachedDirContexts) connections.put(base, ctx);
170                 return ctx;
171             }
172             catch(AuthenticationException e)
173             {
174                 logger.error ("LDAP Service: Authentication error: " + base, e);
175                 if(connector == null)
176                     return null;
177                 Properties pr = connector.referralConnection(env, url, anonymousBind);
178                 if(pr != null)
179                 {
180                     env = pr;
181                     continue;
182                 }
183             }
184             catch(CommunicationException e)
185             {
186                 logger.error("LDAP Service: Communication error: " + base, e);
187                 if(connector == null)
188                     return null;
189                 if(connector.connectionFailed(url))
190                 {
191                     resetConnection(url);
192                     continue;
193                 }
194             }
195             catch(NamingException e)
196             {
197                 logger.error("LDAP Service:Failed to connect to " + base, e);
198             }
199             return ctx;
200         } while(true);
201     }
202
203     /**
204      * Reset Given Connection Function
205      *
206      * tries to connect given <code>LDAPURL</code>.
207      *
208      * @param url <code>LDAPURL</code> which locate server to connect.
209      *
210      */

211     private void resetConnection(LDAPURL url)
212     {
213         // System.out.println("LDAPService: resetConnection() called.");
214
connections.remove(url.getBase());
215     }
216      /**
217      * Set Default Environment
218      *
219      * Fill properties necessary to connect.
220      *
221      */

222     private void setDefaultEnv()
223     {
224         showOpAttributes = attributesList != null;
225         env.put("java.naming.referral", "ignore");
226         env.put("java.naming.batchsize", String.valueOf(batchsize));
227
228         if(anonymousBind)
229         {
230             env.remove("java.naming.security.principal");
231             env.remove("java.naming.security.credentials");
232         }
233         else
234         {
235             env.put("java.naming.security.principal", managerdn);
236             env.put("java.naming.security.credentials", password);
237         }
238
239         env.put("java.naming.security.authentication", securityAuthentication);
240         if(saslclientpckgs != null)
241         {
242             env.put("javax.security.sasl.client.pkgs", saslclientpckgs);
243         }
244         else
245         {
246             env.remove("javax.security.sasl.client.pkgs");
247         }
248
249         env.put("java.naming.ldap.derefAliases", "never");
250         env.put("java.naming.ldap.deleteRDN", "true" );
251         env.put("java.naming.ldap.version", String.valueOf(version));
252
253         if( securityProtocol != null)
254         {
255             env.put("java.naming.security.protocol", securityProtocol);
256             if(securityProtocol.equalsIgnoreCase("ssl"))
257             {
258                 env.put("java.naming.ldap.factory.socket", socketFactory );
259             }
260         }
261         else
262         {
263             env.remove("java.naming.security.protocol");
264             env.remove("java.naming.ldap.factory.socket");
265         }
266
267         // env.put("com.sun.jndi.ldap.trace.ber", System.err);
268
env.put("java.naming.factory.initial", (Object)(jndiprovider));
269     }
270
271     /**
272      * Disconnection Function
273      *
274      * tries to disconnect all connection.
275      *
276      * @return boolean true if success else false.
277      */

278
279     public boolean disconnect()
280     {
281         // System.out.println("LDAPService: disconnect() called.");
282
DirContext ctx = null;
283
284         for(Enumeration enum = connections.elements(); enum.hasMoreElements();)
285         {
286             try
287             {
288                 ctx = (DirContext)enum.nextElement();
289                 ctx.close();
290             }
291             catch(NamingException e)
292             {
293                 logger.error("LDAP Service: Disconnect failed", e);
294             }
295         }
296         
297         connections.clear();
298         return true;
299     }
300
301     public boolean checkAndCloseContext(Context context)
302     {
303         try
304         {
305             if (!useCachedDirContexts)
306             {
307                 context.close();
308                 // System.out.println("LDAPService: closeContext() called.");
309
}
310             else
311             {
312                 // System.out.println("LDAPService: context left in cache.");
313
}
314             return true;
315         }
316         catch(NamingException e)
317         {
318             logger.error("LDAP Service: closeContext() failed", e);
319             return false;
320         }
321     }
322
323
324     /**
325      * Delete Atrribute Function
326      *
327      * Delete given attribute for given <code>LDAPURL</code>.
328      *
329      * @param url object affected.
330      * @param at Atribute to delete
331      * @return boolean true if success else false.
332      */

333
334     public boolean deleteAttribute(LDAPURL url, Attribute at)
335     {
336         try
337         {
338             ModificationItem mods[] = new ModificationItem[1];
339             mods[0] = new ModificationItem(3, at);
340             return modifyAttribute(url, mods);
341         }
342         catch(NamingException e)
343         {
344             logger.debug("LDAP Service: Failed to delete '" + at.getID() + "' attribute for " + url.getUrl(), e);
345         }
346         return false;
347     }
348
349     /**
350      * Add Attribute Function
351      *
352      * add given attribute to given <code>LDAPURL</code>.
353      *
354      * @param url object affected.
355      * @param at Atribute to add
356      * @return boolean true if success else false.
357      */

358     public boolean addAttribute(LDAPURL url, Attribute at)
359     {
360         try
361         {
362             ModificationItem mods[] = new ModificationItem[1];
363             mods[0] = new ModificationItem(1, at);
364             return modifyAttribute(url, mods);
365         }
366         catch(NamingException e)
367         {
368             logger.debug("LDAP Service: Failed to add '" + at.getID() + "' attribute for " + url.getUrl(), e);
369         }
370         return false;
371     }
372
373     /**
374      * Add entry Function
375      *
376      * tries to add object with given <code>LDAPURL</code> and
377      * with given attributes.
378      *
379      * @param url object to create.
380      * @param at Atributes to add
381      * @return boolean true if success else false.
382      */

383     public boolean addEntry(LDAPURL url, Attributes at)
384     {
385         DirContext ctx = connect(url);
386
387         if(ctx == null)
388             return false;
389         try
390         {
391             ctx.createSubcontext(url.getDN(), at);
392             checkAndCloseContext(ctx);
393         }
394         catch(ReferralException e)
395         {
396             LDAPURL myurl = getReferralUrl(e);
397             return addEntry(myurl, at);
398         }
399         catch(NamingException e)
400         {
401
402 e.printStackTrace();
403
404             logger.error("LDAP Service: Failed to add new entry " + url.getDN(), e);
405             return false;
406         }
407         return true;
408     }
409
410     /**
411      * Query existense of an Object Function
412      *
413      * tries to locate given <code>LDAPURL</code>.
414      *
415      * @param url object affected.
416      * @return boolean true if exist else false.
417      */

418     public boolean exists(LDAPURL url)
419     {
420         DirContext ctx = connect(url);
421         if(ctx == null) return false;
422
423         try
424         {
425             NamingEnumeration results = search(ctx, url.getDN(), "(objectclass=*)", DEFAULT_ATTR, 0, false);
426             checkAndCloseContext(ctx);
427             return true;
428         }
429         catch(NameNotFoundException _ex)
430         {
431             return false;
432         }
433         catch(NamingException _ex)
434         {
435             return false;
436         }
437     }
438
439     /**
440      * Compare Function
441      *
442      * Compare given <code>LDAPURL</code>s.
443      *
444      * @param srcUrl object affected.
445      * @param dstUrl object affected.
446      * @return int 0 same host+DN, 1 same DN,2 child,3 no relation.
447      */

448     public int compare(LDAPURL srcUrl, LDAPURL dstUrl)
449     {
450         if(!srcUrl.sameHosts(dstUrl))
451             return 0;
452         Name src = parse(srcUrl.getDN());
453         Name dst = parse(dstUrl.getDN());
454         if(dst.compareTo(src) == 0)
455             return 1;
456         if(dst.startsWith(src))
457             return 2;
458         Name prefix = src.getPrefix(src.size() - 1);
459         return dst.compareTo(prefix) != 0 ? 0 : 3;
460     }
461
462     /**
463      * Import Function
464      *
465      * Import given <code>LDAPURL</code> to another dn.
466      *
467      * @param url object to import.
468      * @param dn Dn of new object.
469      * @param entry attributes.
470      * @param type 0 addnew, 1 update, 2 sync.
471      * @return int 1 success, 0 unknown type,-1 failure.
472      */

473     public int importEntry(LDAPURL url, String dn, Attributes entry, int type)
474     {
475         boolean rs = false;
476         LDAPURL myurl = new LDAPURL(url.getHost(), url.getPort(), dn);
477         if(type == 0)
478             rs = addEntry(myurl, entry);
479         else
480
481         if(type == 1)
482             rs = updateEntry(myurl, entry);
483         else
484         if(type == 2)
485             rs = synchEntry(myurl, entry);
486         else
487             return 0;
488         return !rs ? -1 : 1;
489     }
490
491     /**
492      * Modify Function
493      *
494      * Modify given <code>LDAPURL</code> with fiven modification items.
495      *
496      * @param url object to modify.
497      * @param mods Modification items.
498      * @exception NamingException
499      * @return boolean true if success else false.
500      */

501     private boolean modifyAttribute(LDAPURL url, ModificationItem mods[])
502         throws NamingException
503     {
504         DirContext ctx = connect(url);
505         if(ctx == null) return false;
506
507         try
508         {
509             ctx.modifyAttributes(url.getDN(), mods);
510             checkAndCloseContext(ctx);
511         }
512         catch(ReferralException e)
513         {
514             LDAPURL myurl = getReferralUrl(e);
515             return modifyAttribute(myurl, mods);
516         }
517         return true;
518     }
519
520     /**
521      * Build LDAPURL Function
522      *
523      * Build <code>LDAPURL</code> with given DN.
524      *
525      * @param DN DN value for object.
526      * @return LDAPURL build with given DN.
527      */

528     public LDAPURL buildURL(String DN)
529     {
530       return new LDAPURL(host,port,DN + "," + basedn);
531     }
532
533     /**
534      * Read Attributes Function
535      *
536      * Return attributes for given <code>LDAPURL</code>.
537      *
538      * @param url object to read attributes.
539      * @return Attributes attributes for given url.
540      */

541     public Attributes read(LDAPURL url)
542     {
543         DirContext ctx = connect(url);
544         if(ctx == null) return null;
545         
546         Attributes attrs = null;
547         try
548         {
549             if(showOpAttributes)
550             {
551                 attrs = ctx.getAttributes(url.getDN(), attributesList);
552             }
553             else
554             {
555                 attrs = ctx.getAttributes(url.getDN());
556             }
557             checkAndCloseContext(ctx);
558         }
559         catch(ReferralException e)
560         {
561             LDAPURL myurl = getReferralUrl(e);
562             if(myurl.getDN().length() == 0)
563             {
564                 myurl.setDN(url.getDN());
565             }
566             return read(myurl);
567         }
568         catch(CommunicationException e)
569         {
570             if(connector == null)
571             {
572                 logger.debug("LDAP Service: Communication error : " + url.getBase(), e);
573                 return null;
574             }
575             if(connector.connectionFailed(url))
576             {
577                 resetConnection(url);
578             }
579         }
580         catch(NamingException e)
581         {
582             logger.debug("LDAP Service: Failed to read entry " + url.getDN(), e);
583             return null;
584         }
585         return attrs;
586     }
587
588     /**
589      * Rename Entry Function
590      *
591      * Rename given <code>LDAPURL</code> with given DN.
592      *
593      * @param url object to modify.
594      * @param newDN DN value for new object.
595      * @return boolean true if success else false.
596      */

597     public boolean renameEntry(LDAPURL url, String newDN)
598     {
599         DirContext ctx = connect(url);
600         if(ctx == null) return false;
601
602         try
603         {
604             ctx.rename(url.getDN(), newDN);
605             checkAndCloseContext(ctx);
606         }
607         catch(ReferralException e)
608         {
609             logger.debug("LDAP Service: Failed to rename entry. (not supported for referrals)", e);
610             return false;
611         }
612         catch(NamingException e)
613         {
614             logger.debug("LDAP Service: Failed to rename entry " + url.getDN(), e);
615             return false;
616         }
617         return true;
618     }
619
620     /**
621      * Sync Entry Function
622      *
623      * Sync given <code>LDAPURL</code> with given atrributes.
624      *
625      * @param url object to sync.
626      * @param ats Modification items.
627      * @return boolean true if success else false.
628      */

629     public boolean synchEntry(LDAPURL url, Attributes ats)
630     {
631         DirContext ctx = connect(url);
632         if(ctx == null) return false;
633
634         try
635         {
636             ctx.modifyAttributes(url.getDN(), 2, ats);
637             checkAndCloseContext(ctx);
638         }
639         catch(ReferralException e)
640         {
641             LDAPURL myurl = getReferralUrl(e);
642             return synchEntry(url, ats);
643         }
644         catch(NameNotFoundException _ex)
645         {
646             try
647             {
648                 ctx.createSubcontext(url.getDN(), ats);
649             }
650             catch(NamingException _ex2)
651             {
652                 return false;
653             }
654         }
655         catch(NamingException e)
656         {
657             logger.debug("LDAP Service: Failed to synchronize entries", e);
658             return false;
659         }
660         return true;
661     }
662
663     /**
664      * Delete Attributes Function
665      *
666      * Delete Attributes for given <code>LDAPURL</code>.
667      *
668      * @param url object to modify.
669      * @param ats Attributes to delete.
670      * @return boolean true if success else false.
671      */

672     public boolean deleteAttrs(LDAPURL url, Attributes ats)
673     {
674         DirContext ctx = connect(url);
675         if(ctx == null) return false;
676
677         try
678         {
679             ctx.modifyAttributes(url.getDN(), DirContext.REMOVE_ATTRIBUTE, ats);
680             checkAndCloseContext(ctx);
681         }
682         catch(ReferralException e)
683         {
684             LDAPURL myurl = getReferralUrl(e);
685             return synchEntry(url, ats);
686         }
687         catch(NameNotFoundException _ex)
688         {
689             try
690             {
691                 ctx.createSubcontext(url.getDN(), ats);
692                 checkAndCloseContext(ctx);
693             }
694             catch(NamingException _ex2)
695             {
696                 return false;
697             }
698         }
699         catch(NamingException e)
700         {
701             logger.debug("LDAP Service: Failed to delete Attributes", e);
702             return false;
703         }
704         return true;
705     }
706
707     /**
708      * Delete Entry Function
709      *
710      * Delete given <code>LDAPURL</code>.
711      *
712      * @param url object to delete.
713      * @return boolean true if success else false.
714      */

715     public boolean deleteEntry(LDAPURL url)
716     {
717         DirContext ctx = connect(url);
718         if(ctx == null) return false;
719
720         try
721         {
722             ctx.destroySubcontext(url.getDN());
723             checkAndCloseContext(ctx);
724         }
725         catch(ReferralException e)
726         {
727             LDAPURL myurl = getReferralUrl(e);
728             return deleteEntry(myurl);
729         }
730         catch(NamingException e)
731         {
732             logger.debug("LDAP Service: Failed to delete entry " + url.getDN(), e);
733             return false;
734         }
735         return true;
736     }
737
738     /**
739      * Find Entry Name Function
740      *
741      * Return entry name for given <code>LDAPURL</code>.
742      *
743      * @param url object to modify.
744      * @return LDAPURL real entry DN.
745      */

746     public LDAPURL findEntryName(LDAPURL url)
747     {
748         DirContext ctx = connect(url);
749         if(ctx == null) return null;
750         
751         Name name = parse(url.getDN());
752         String base = name.getPrefix(name.size() - 1).toString();
753         String dn = url.getDN();
754         String rdn = name.get(name.size() - 1).toString();
755         int i = 1;
756         boolean foundName = true;
757
758         while(foundName)
759         {
760             try
761             {
762                 NamingEnumeration results = search(ctx, dn, "(objectclass=*)", DEFAULT_ATTR, 0, false);
763                 if(i == 1)
764                     rdn = rdn + " copy";
765                 else
766                 if(i == 2)
767                     rdn = rdn + " " + i;
768                 else
769                 if(i >= 3)
770                     rdn = rdn.substring(0, rdn.length() - 1) + i;
771                 dn = rdn + ", " + base;
772                 i++;
773             }
774             catch(NameNotFoundException _ex)
775             {
776                 foundName = false;
777                 return new LDAPURL(url.getHost(), url.getPort(), dn);
778             }
779             catch(NamingException _ex)
780             {
781                 return null;
782             }
783         }
784         
785         checkAndCloseContext(ctx);
786
787         return null;
788     }
789     
790     /**
791      * Delete Tree Function
792      *
793      * Delete record with all child node <code>LDAPURL</code>.
794      *
795      * @param url object to modify.
796      * @return boolean true if success else false.
797      */

798     public boolean deleteTree(LDAPURL url)
799     {
800         DirContext ctx = connect(url);
801         if(ctx == null) return false;
802
803         String entryDN = null;
804         LDAPURL myurl = null;
805         String baseDN = url.getDN();
806
807         try
808         {
809             for(NamingEnumeration results = search(ctx, baseDN, "(objectclass=*)", DEFAULT_ATTR, 1, false); results.hasMore();)
810             {
811                 SearchResult si = (SearchResult)results.next();
812                 entryDN = getFixedDN(si.getName(), baseDN);
813                 myurl = new LDAPURL(url.getHost(), url.getPort(), entryDN);
814                 if(!deleteTree(myurl))
815                 {
816                     return false;
817                 }
818             }
819
820             checkAndCloseContext(ctx);
821         }
822         catch(NamingException e)
823         {
824             logger.debug("LDAP Service: Delete tree failed", e);
825             return false;
826         }
827         return deleteEntry(url);
828     }
829
830     /**
831      * Transfer Function
832      *
833      * Transfer given <code>LDAPURL</code> to other <code>LDAPURL</code>.
834      *
835      * @param fromUrl object to transfer.
836      * @param toUrl target object.
837      * @param delete delete after transfer.
838      * @param replace replace if exist.
839      * @param withChildren transfer with childs.
840      * @return boolean true if success else false.
841      */

842     public boolean transfer(LDAPURL fromUrl, LDAPURL toUrl, boolean delete, boolean replace, boolean withChildren)
843     {
844         LDAPURL dstUrl = toUrl;
845         int rc = compare(fromUrl, toUrl);
846         if(rc == 1)
847             dstUrl = findEntryName(dstUrl);
848         if(withChildren)
849             return transferTreeSub(fromUrl, dstUrl, delete, replace);
850         else
851             return transferEntry(fromUrl, dstUrl, delete, replace);
852
853     }
854
855     /**
856      * Transfer with updates Function
857      *
858      * Transfer updated <code>LDAPURL</code> with given modification items
859      * to other <code>LDAPURL</code>.
860      *
861      * @param fromUrl object to transfer.
862      * @param toUrl target object.
863      * @param delete delete after transfer.
864      * @param replace replace if exist.
865      * @param ats attributes to update.
866      * @return boolean true if success else false.
867      */

868     public boolean transferEntry(LDAPURL fromUrl, Attributes ats, LDAPURL toUrl, boolean delete, boolean replace)
869     {
870         if(delete && !deleteEntry(fromUrl))
871             return false;
872         if(updateEntry(toUrl, ats, replace))
873             return true;
874         if(delete)
875             addEntry(fromUrl, ats);
876         return false;
877     }
878
879     /**
880      * Transfer without updates Function
881      *
882      * Transfer <code>LDAPURL</code> to other <code>LDAPURL</code>.
883      *
884      * @param fromUrl object to transfer.
885      * @param toUrl target object.
886      * @param delete delete after transfer.
887      * @param replace replace if exist.
888      * @return boolean true if success else false.
889      */

890
891     public boolean transferEntry(LDAPURL fromUrl, LDAPURL toUrl, boolean delete, boolean replace)
892     {
893         Attributes ats = read(fromUrl);
894         if(ats == null)
895             return false;
896         else
897             return transferEntry(fromUrl, ats, toUrl, delete, replace);
898     }
899
900     /**
901      * Transfer Tree Function
902      *
903      * Transfer <code>LDAPURL</code> with all child to other <code>LDAPURL</code>.
904      *
905      * @param fromUrl object to transfer.
906      * @param toUrl target object.
907      * @param delete delete after transfer.
908      * @param replace replace if exist.
909      * @return boolean true if success else false.
910      */

911     private boolean transferTreeSub(LDAPURL fromUrl, LDAPURL toUrl, boolean delete, boolean replace)
912     {
913         DirContext ctx = connect(fromUrl);
914         if(ctx == null) return false;
915
916         Attributes ats = read(fromUrl);
917         if(ats == null) return false;
918         
919         String srcDN = fromUrl.getDN();
920         String dstDN = toUrl.getDN();
921         boolean createdBase = false;
922         boolean rc = false;
923         boolean moreReferrals = true;
924
925         while(moreReferrals)
926         {
927             try
928             {
929                 NamingEnumeration results = search(ctx, srcDN, "(objectclass=*)", DEFAULT_ATTR, 1, false);
930                 if(!results.hasMore())
931                 {
932                     if(!transferEntry(fromUrl, ats, toUrl, delete, replace))
933                         return false;
934                 } else
935                 {
936                     String name = null;
937                     if(!createdBase)
938                     {
939                         if(!updateEntry(toUrl, ats, replace))
940                             return false;
941                         createdBase = true;
942                     }
943                     LDAPURL srcUrl;
944                     LDAPURL dstUrl;
945                     for(; results.hasMore(); transferTreeSub(srcUrl, dstUrl, delete, replace))
946                     {
947                         SearchResult si = (SearchResult)results.next();
948                         name = fixName(si.getName());
949                         String tmpSrcDN = getDN(name, srcDN);
950                         srcUrl = new LDAPURL(fromUrl.getHost(), fromUrl.getPort(), tmpSrcDN);
951                         String tmpDstDN = getDN(name, dstDN);
952                         dstUrl = new LDAPURL(toUrl.getHost(), toUrl.getPort(), tmpDstDN);
953                     }
954
955                     if(delete && !deleteEntry(fromUrl))
956                         return false;
957                 }
958                 moreReferrals = false;
959             }
960             catch(ReferralException e)
961             {
962                 if(delete)
963                 {
964                     moreReferrals = false;
965                 }
966                 else
967                 {
968                     if(!createdBase)
969                     {
970                         if(!updateEntry(toUrl, ats, replace)) return false;
971                         createdBase = true;
972                     }
973
974                     LDAPURL srcUrl = getReferralUrl(e);
975                     String tmpDstDN = getName(srcUrl.getDN()) + ", " + dstDN;
976                     LDAPURL dstUrl = new LDAPURL(toUrl.getHost(), toUrl.getPort(), tmpDstDN);
977                     boolean rs = transferTreeSub(srcUrl, dstUrl, delete, replace);
978                     if(!rs)return false;
979
980                     moreReferrals = e.skipReferral();
981                     try
982                     {
983                         // Close old context
984
checkAndCloseContext(ctx);
985                         ctx = (DirContext)e.getReferralContext();
986                     }
987                     catch(NamingException _ex) { }
988                 }
989             }
990             catch(NamingException e)
991             {
992                 logger.debug("LDAP Service: Transfer Tree failed", e);
993                 return false;
994             }
995         }
996
997         checkAndCloseContext(ctx);
998         return true;
999     }
1000
1001    /**
1002     * Update Atribute Function
1003     *
1004     * Update an attribute for given <code>LDAPURL</code>.
1005     *
1006     * @param url object to update.
1007     * @param at atrribute to update.
1008     * @return boolean true if success else false.
1009     */

1010    public boolean updateAttribute(LDAPURL url, Attribute at)
1011    {
1012        try
1013        {
1014            ModificationItem mods[] = new ModificationItem[1];
1015            mods[0] = new ModificationItem(2, at);
1016            return modifyAttribute(url, mods);
1017        }
1018        catch(NamingException e)
1019        {
1020            logger.debug("LDAP Service: Failed to update '" + at.getID() + "' attribute for " + url.getUrl(), e);
1021        }
1022        return false;
1023    }
1024
1025    /**
1026     * Update Atributes Function
1027     *
1028     * Update attributes for given <code>LDAPURL</code>.
1029     *
1030     * @param url object to update.
1031     * @param at atrributes to update.
1032     * @return boolean true if success else false.
1033     */

1034    public boolean updateEntry(LDAPURL url, Attributes at)
1035    {
1036        DirContext ctx = connect(url);
1037        if(ctx == null) return false;
1038
1039        try
1040        {
1041            ctx.modifyAttributes(url.getDN(), 2, at);
1042            checkAndCloseContext(ctx);
1043        }
1044        catch(ReferralException e)
1045        {
1046            LDAPURL myurl = getReferralUrl(e);
1047            return updateEntry(myurl, at);
1048        }
1049        catch(NamingException e)
1050        {
1051            logger.error("LDAP Service: Failed to update entry " + url.getDN(), e);
1052            return false;
1053        }
1054        return true;
1055    }
1056 
1057    /**
1058     * Update Entry Function
1059     *
1060     * Update attributes for given <code>LDAPURL</code>.
1061     *
1062     * @param url object to update.
1063     * @param ats atrributes to update.
1064     * @param replace replace if exist.
1065     * @return boolean true if success else false.
1066     */

1067    public boolean updateEntry(LDAPURL url, Attributes ats, boolean replace)
1068    {
1069        return replace ? synchEntry(url, ats) : addEntry(url, ats);
1070    }
1071
1072    /**
1073     * Search Function
1074     *
1075     * Search objects for given Base DN and filter.
1076     *
1077     * @param ctx directory context.
1078     * @param dn Base search DN.
1079     * @param filter Search filter.
1080     * @param attribs attributes to receive.
1081     * @param type search scope 1 Subscope, else 0.
1082     * @exception NamingException
1083     * @return NamingEnumeration Results.
1084     */

1085    public NamingEnumeration search(DirContext ctx, String dn, String filter, String attribs[], int type)
1086        throws NamingException
1087    {
1088        return search(ctx, dn, filter, attribs, type, true);
1089    }
1090
1091    /**
1092     * Search Function
1093     *
1094     * Search objects for given Base DN and filter.
1095     *
1096     * @param ctx directory context.
1097     * @param dn Base search DN.
1098     * @param filter Search filter.
1099     * @param attribs attributes to receive.
1100     * @param type search scope 2 Subscope, else 1.
1101     * @param setLimits enable limits.
1102     * @exception NamingException
1103     * @return NamingEnumeration Results.
1104     */

1105    private NamingEnumeration search(DirContext ctx, String dn, String filter, String attribs[], int type, boolean setLimits)
1106        throws NamingException
1107    {
1108        SearchControls constraints = new SearchControls();
1109        constraints.setSearchScope(type);
1110        constraints.setReturningAttributes(attribs);
1111        if(setLimits)
1112        {
1113            constraints.setCountLimit(limit);
1114            constraints.setTimeLimit(timeout);
1115        }
1116        NamingEnumeration results = ctx.search(dn, filter, constraints);
1117        return results;
1118    }
1119
1120    /**
1121     * Search Function
1122     *
1123     * Search objects for given BaseURL and filter.
1124     *
1125     * @param url Base URL .
1126     * @param filter Search filter.
1127     * @param attribs attributes to receive.
1128     * @param subTreeScope true subtree else false.
1129     * @return Vector Results.
1130     */

1131    public Vector search(LDAPURL url, String filter, String attribs[], boolean subTreeScope)
1132    {
1133        /*
1134        System.out.println("===== LDAPService: search");
1135        System.out.println("===== LDAPService: " + url);
1136        System.out.println("===== LDAPService: " + filter);
1137        System.out.println("===== LDAPService: " + attribs);
1138        System.out.println("===== LDAPService: " + subTreeScope);
1139        */

1140        
1141        Vector results = new Vector();
1142        String attrs[] = new String[attribs.length + 1];
1143        attrs[0] = "objectclass";
1144        System.arraycopy(attribs, 0, attrs, 1, attribs.length);
1145        int scope = subTreeScope ? 2 : 1;
1146        subSearch(url, filter, attrs, scope, results);
1147
1148        return results;
1149    }
1150
1151    /**
1152     * Search Function
1153     *
1154     * Search objects for given BaseURL and filter.
1155     *
1156     * @param url Base URL .
1157     * @param filter Search filter.
1158     * @param attribs attributes to receive.
1159     * @param scope true subtree else false.
1160     * @param rs Result
1161     * @return boolean true if success else false.
1162     */

1163    private boolean subSearch(LDAPURL url, String filter, String attribs[], int scope, Vector rs)
1164    {
1165        DirContext ctx = connect(url);
1166        if(ctx == null) return false;
1167        
1168        String entryDN = null;
1169        Attributes at = null;
1170        Attribute a = null;
1171        LDAPURL myurl = null;
1172        int subscope = 0;
1173        String baseDN = url.getDN();
1174
1175        boolean moreReferrals = true;
1176        while(moreReferrals)
1177        {
1178            try
1179            {
1180                Vector vl;
1181                for(NamingEnumeration results = search(ctx, baseDN, filter, attribs, scope); results.hasMore(); rs.addElement(vl))
1182                {
1183                    SearchResult si = (SearchResult)results.next();
1184                    vl = new Vector(attribs.length);
1185                    entryDN = getFixedDN(si.getName(), baseDN);
1186                    myurl = new LDAPURL(url.getHost(), url.getPort(), entryDN);
1187                    vl.addElement(myurl);
1188                    at = si.getAttributes();
1189                    for(int i = 1; i < attribs.length; i++)
1190                    {
1191                        a = at.get(attribs[i]);
1192                        if(a == null)
1193                        {
1194                            vl.addElement("N/A");
1195                        } else
1196                        {
1197                            Object v = a.get();
1198                            if(v instanceof byte[])
1199                                vl.addElement(v);
1200                            else
1201                                vl.addElement(a.get().toString());
1202                        }
1203                    }
1204                }
1205                moreReferrals = false;
1206            }
1207
1208            catch(ReferralException e)
1209            {
1210                myurl = getReferralUrl(e);
1211                subscope = scope != 1 ? scope : 0;
1212                boolean error = subSearch(myurl, filter, attribs, subscope, rs);
1213                if(!error) return error;
1214                
1215                moreReferrals = e.skipReferral();
1216                try
1217                {
1218                    // Close old context
1219
checkAndCloseContext(ctx);
1220                    ctx = (DirContext)e.getReferralContext();
1221                }
1222                catch(NamingException _ex) { }
1223            }
1224            catch(NamingException e)
1225            {
1226                logger.debug("LDAP Service: Search failed", e);
1227                return false;
1228            }
1229        }
1230        
1231        checkAndCloseContext(ctx);
1232        return true;
1233    }
1234
1235    /**
1236     * Get value Function
1237     *
1238     * Return value for attribute value pair.
1239     *
1240     * @param attrvalue input.
1241     * @return String Value.
1242     */

1243    public String removeAttrName(String attrvalue)
1244    {
1245        StringTokenizer token = new StringTokenizer(attrvalue,"=");
1246        if (token.countTokens()==2)
1247        {
1248            token.nextToken();
1249            return token.nextToken();
1250        }
1251        else
1252        {
1253            return attrvalue;
1254        }
1255    }
1256 
1257    /**
1258     * Return full DN Function
1259     *
1260     * Add Base DN to given DN.
1261     *
1262     * @param rdn full DN.
1263     * @param base Base DN.
1264     * @return String DN.
1265     */

1266    private String getFixedDN(String rdn, String base)
1267    {
1268        return getDN(fixName(rdn), base);
1269    }
1270
1271    /**
1272     * Return Name Function
1273     *
1274     * Return name for given DN.
1275     *
1276     * @param dn DN.
1277     * @return String Name.
1278     */

1279    public String getName(String dn)
1280    {
1281        try
1282        {
1283            Name nm = parser.parse(dn);
1284            return nm.get(nm.size() - 1).toString();
1285        }
1286        catch(NamingException _ex)
1287        {
1288            return null;
1289        }
1290    }
1291
1292    /**
1293     * Fix Name Function
1294     *
1295     * Fix chars .
1296     *
1297     * @param name Name to fix.
1298     * @return String Fixed name.
1299     */

1300    private String fixName(String name)
1301    {
1302        if(name.length() > 0 && name.charAt(0) == '"')
1303        {
1304            int size = name.length() - 1;
1305            StringBuffer buf = new StringBuffer();
1306            for(int i = 1; i < size; i++)
1307            {
1308                if(name.charAt(i) == '/')
1309                    buf.append("\\");
1310                buf.append(name.charAt(i));
1311            }
1312
1313            return buf.toString();
1314        }
1315        else
1316        {
1317            return name;
1318        }
1319    }
1320
1321    /**
1322     * Return full DN Function
1323     *
1324     * Add Base DN to given DN.
1325     *
1326     * @param rdn DN.
1327     * @param base Base DN.
1328     * @return String full DN.
1329     */

1330    private String getDN(String rdn, String base)
1331    {
1332        if(rdn.length() == 0)
1333            return base;
1334        if(base.length() == 0)
1335            return rdn;
1336        else
1337            return rdn + ", " + base;
1338    }
1339
1340    /**
1341     * Return Name Function
1342     *
1343     * Add Base DN to given DN.
1344     *
1345     * @param dn full DN.
1346     * @return Name Name for given DN.
1347     */

1348    public Name parse(String dn)
1349    {
1350        try
1351        {
1352            return parser.parse(dn);
1353        }
1354        catch(NamingException _ex)
1355        {
1356            return null;
1357        }
1358    }
1359
1360    /**
1361     * Get Referral URL Function
1362     *
1363     * Return <code>LDAPURL</code> extracted from exception.
1364     *
1365     * @param e Exception to extract.
1366     * @return LDAPURL referrral URL.
1367     */

1368    public LDAPURL getReferralUrl(ReferralException e)
1369    {
1370        String url = (String)e.getReferralInfo();
1371        try
1372        {
1373            return new LDAPURL(url);
1374        }
1375        catch(Exception ex)
1376        {
1377            logger.debug("Invalid url: " + ex.getMessage() + " " + url);
1378        }
1379        return null;
1380    }
1381
1382    ///////////////////////////////////////////////////////////////////////////
1383
// Service Init
1384
///////////////////////////////////////////////////////////////////////////
1385

1386    /**
1387     * This is the early initialization method called by the
1388     * Turbine <code>Service</code> framework
1389     * @param conf The <code>ServletConfig</code>
1390     * @exception InitializationException if the service fails to initialize
1391     */

1392    public void init( ServletConfig conf ) throws InitializationException
1393    {
1394        connections = new Hashtable();
1395        connector = null;
1396        parser = null;
1397        env = new Properties();
1398        ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance())
1399                                                     .getResources(SERVICE_NAME);
1400        this.host = serviceConf.getString("host");
1401        this.port = serviceConf.getInt("port",DEFAULT_PORT);
1402        this.sslport = serviceConf.getInt("sslport",DEFAULT_SSLPORT);
1403        this.limit = serviceConf.getInt("limit",DEFAULT_LIMIT);
1404        this.timeout = serviceConf.getInt("timeout",DEFAULT_TIMEOUT);
1405        this.version = serviceConf.getInt("version",DEFAULT_VERSION);
1406        this.listFilter = repair(serviceConf.getString("listfilter","(objectclass=*)"));
1407        this.basedn = repair(serviceConf.getString("basedn"));
1408        this.managerdn = repair(serviceConf.getString("managerdn"));
1409        this.password = serviceConf.getString("password");
1410        this.attributesList = getList(serviceConf.getString("attributeslist")," ");
1411        this.showOpAttributes = serviceConf.getBoolean("showopattributes",false);
1412        this.anonymousBind = serviceConf.getBoolean("anonymousbind",false);
1413        this.securityAuthentication = serviceConf.getString("securityauthentication","simple");
1414        this.securityProtocol = serviceConf.getString("securityprotocol");
1415        this.socketFactory = serviceConf.getString("socketfactory");
1416        this.useCachedDirContexts = serviceConf.getBoolean("contextcache", false);
1417
1418        this.jndiprovider = serviceConf.getString("jndiprovider",DEFAULT_CTX);
1419        this.saslclientpckgs = serviceConf.getString("saslclientpckgs");
1420        mainConnect(new LDAPURL(host,port,basedn));
1421        setInit(true);
1422    }
1423
1424    /**
1425     * This is the late initialization method called by the
1426     * Turbine <code>Service</code> framework
1427     * @param conf The <code>ServletConfig</code>
1428     * @exception InitializationException if the service fails to initialize
1429     */

1430    public void init() throws InitializationException
1431    {
1432        while( !getInit() )
1433        {
1434            //Not yet...
1435
try
1436            {
1437                Thread.sleep( 500 );
1438            }
1439            catch (InterruptedException ie )
1440            {
1441                logger.error( ie );
1442            }
1443        }
1444    }
1445
1446    /**
1447     * Repair Given Parameter Function
1448     *
1449     * Repair String read from config.
1450     *
1451     * @param value String to repair.
1452     * @return String Repaired String.
1453     */

1454    private String repair(String value)
1455    {
1456        value = value.replace('/', '=');
1457        value = value.replace('%', ',');
1458        return value;
1459    }
1460
1461    /**
1462     * Tokenizer Wrapper Function
1463     *
1464     * Tokenize given string with given parameter.
1465     *
1466     * @param value String to repair.
1467     * @param separator separator
1468     * @return String Result.
1469     */

1470    private String[] getList(String value, String separator)
1471    {
1472        if(value == null) return null;
1473
1474        StringTokenizer tokens = new StringTokenizer(value, separator);
1475        String at[] = new String[tokens.countTokens()];
1476
1477        for(int i = 0; tokens.hasMoreTokens(); i++)
1478        {
1479            at[i] = tokens.nextToken();
1480        }
1481
1482        return at;
1483    }
1484
1485}
Popular Tags