1 /*
2  * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.jndi.url.ldap;
27 
28 import javax.naming.spi.ResolveResult;
29 import javax.naming.*;
30 import javax.naming.directory.*;
31 import java.util.Hashtable;
32 import java.util.StringTokenizer;
33 import com.sun.jndi.ldap.LdapURL;
34 
35 /**
36  * An LDAP URL context.
37  *
38  * @author Rosanna Lee
39  * @author Scott Seligman
40  */
41 
42 final public class ldapURLContext
43         extends com.sun.jndi.toolkit.url.GenericURLDirContext {
44 
ldapURLContext(Hashtable<?,?> env)45     ldapURLContext(Hashtable<?,?> env) {
46         super(env);
47     }
48 
49     /**
50       * Resolves 'name' into a target context with remaining name.
51       * It only resolves the hostname/port number. The remaining name
52       * contains the root DN.
53       *
54       * For example, with a LDAP URL "ldap://localhost:389/o=widget,c=us",
55       * this method resolves "ldap://localhost:389/" to the root LDAP
56       * context on the server 'localhost' on port 389,
57       * and returns as the remaining name "o=widget, c=us".
58       */
getRootURLContext(String name, Hashtable<?,?> env)59     protected ResolveResult getRootURLContext(String name, Hashtable<?,?> env)
60     throws NamingException {
61         return ldapURLContextFactory.getUsingURLIgnoreRootDN(name, env);
62     }
63 
64     /**
65      * Return the suffix of an ldap url.
66      * prefix parameter is ignored.
67      */
getURLSuffix(String prefix, String url)68     protected Name getURLSuffix(String prefix, String url)
69         throws NamingException {
70 
71         LdapURL ldapUrl = new LdapURL(url);
72         String dn = (ldapUrl.getDN() != null? ldapUrl.getDN() : "");
73 
74         // Represent DN as empty or single-component composite name.
75         CompositeName remaining = new CompositeName();
76         if (!"".equals(dn)) {
77             // if nonempty, add component
78             remaining.add(dn);
79         }
80         return remaining;
81     }
82 
83     /*
84      * Override context operations.
85      * Test for presence of LDAP URL query components in the name argument.
86      * Query components are permitted only for search operations and only
87      * when the name has a single component.
88      */
89 
lookup(String name)90     public Object lookup(String name) throws NamingException {
91         if (LdapURL.hasQueryComponents(name)) {
92             throw new InvalidNameException(name);
93         } else {
94             return super.lookup(name);
95         }
96     }
97 
lookup(Name name)98     public Object lookup(Name name) throws NamingException {
99         if (LdapURL.hasQueryComponents(name.get(0))) {
100             throw new InvalidNameException(name.toString());
101         } else {
102             return super.lookup(name);
103         }
104     }
105 
bind(String name, Object obj)106     public void bind(String name, Object obj) throws NamingException {
107         if (LdapURL.hasQueryComponents(name)) {
108             throw new InvalidNameException(name);
109         } else {
110             super.bind(name, obj);
111         }
112     }
113 
bind(Name name, Object obj)114     public void bind(Name name, Object obj) throws NamingException {
115         if (LdapURL.hasQueryComponents(name.get(0))) {
116             throw new InvalidNameException(name.toString());
117         } else {
118             super.bind(name, obj);
119         }
120     }
121 
rebind(String name, Object obj)122     public void rebind(String name, Object obj) throws NamingException {
123         if (LdapURL.hasQueryComponents(name)) {
124             throw new InvalidNameException(name);
125         } else {
126             super.rebind(name, obj);
127         }
128     }
129 
rebind(Name name, Object obj)130     public void rebind(Name name, Object obj) throws NamingException {
131         if (LdapURL.hasQueryComponents(name.get(0))) {
132             throw new InvalidNameException(name.toString());
133         } else {
134             super.rebind(name, obj);
135         }
136     }
137 
unbind(String name)138     public void unbind(String name) throws NamingException {
139         if (LdapURL.hasQueryComponents(name)) {
140             throw new InvalidNameException(name);
141         } else {
142             super.unbind(name);
143         }
144     }
145 
unbind(Name name)146     public void unbind(Name name) throws NamingException {
147         if (LdapURL.hasQueryComponents(name.get(0))) {
148             throw new InvalidNameException(name.toString());
149         } else {
150             super.unbind(name);
151         }
152     }
153 
rename(String oldName, String newName)154     public void rename(String oldName, String newName) throws NamingException {
155         if (LdapURL.hasQueryComponents(oldName)) {
156             throw new InvalidNameException(oldName);
157         } else if (LdapURL.hasQueryComponents(newName)) {
158             throw new InvalidNameException(newName);
159         } else {
160             super.rename(oldName, newName);
161         }
162     }
163 
rename(Name oldName, Name newName)164     public void rename(Name oldName, Name newName) throws NamingException {
165         if (LdapURL.hasQueryComponents(oldName.get(0))) {
166             throw new InvalidNameException(oldName.toString());
167         } else if (LdapURL.hasQueryComponents(newName.get(0))) {
168             throw new InvalidNameException(newName.toString());
169         } else {
170             super.rename(oldName, newName);
171         }
172     }
173 
list(String name)174     public NamingEnumeration<NameClassPair> list(String name)
175             throws NamingException {
176         if (LdapURL.hasQueryComponents(name)) {
177             throw new InvalidNameException(name);
178         } else {
179             return super.list(name);
180         }
181     }
182 
list(Name name)183     public NamingEnumeration<NameClassPair> list(Name name)
184             throws NamingException {
185         if (LdapURL.hasQueryComponents(name.get(0))) {
186             throw new InvalidNameException(name.toString());
187         } else {
188             return super.list(name);
189         }
190     }
191 
listBindings(String name)192     public NamingEnumeration<Binding> listBindings(String name)
193             throws NamingException {
194         if (LdapURL.hasQueryComponents(name)) {
195             throw new InvalidNameException(name);
196         } else {
197             return super.listBindings(name);
198         }
199     }
200 
listBindings(Name name)201     public NamingEnumeration<Binding> listBindings(Name name)
202             throws NamingException {
203         if (LdapURL.hasQueryComponents(name.get(0))) {
204             throw new InvalidNameException(name.toString());
205         } else {
206             return super.listBindings(name);
207         }
208     }
209 
destroySubcontext(String name)210     public void destroySubcontext(String name) throws NamingException {
211         if (LdapURL.hasQueryComponents(name)) {
212             throw new InvalidNameException(name);
213         } else {
214             super.destroySubcontext(name);
215         }
216     }
217 
destroySubcontext(Name name)218     public void destroySubcontext(Name name) throws NamingException {
219         if (LdapURL.hasQueryComponents(name.get(0))) {
220             throw new InvalidNameException(name.toString());
221         } else {
222             super.destroySubcontext(name);
223         }
224     }
225 
createSubcontext(String name)226     public Context createSubcontext(String name) throws NamingException {
227         if (LdapURL.hasQueryComponents(name)) {
228             throw new InvalidNameException(name);
229         } else {
230             return super.createSubcontext(name);
231         }
232     }
233 
createSubcontext(Name name)234     public Context createSubcontext(Name name) throws NamingException {
235         if (LdapURL.hasQueryComponents(name.get(0))) {
236             throw new InvalidNameException(name.toString());
237         } else {
238             return super.createSubcontext(name);
239         }
240     }
241 
lookupLink(String name)242     public Object lookupLink(String name) throws NamingException {
243         if (LdapURL.hasQueryComponents(name)) {
244             throw new InvalidNameException(name);
245         } else {
246             return super.lookupLink(name);
247         }
248     }
249 
lookupLink(Name name)250     public Object lookupLink(Name name) throws NamingException {
251         if (LdapURL.hasQueryComponents(name.get(0))) {
252             throw new InvalidNameException(name.toString());
253         } else {
254             return super.lookupLink(name);
255         }
256     }
257 
getNameParser(String name)258     public NameParser getNameParser(String name) throws NamingException {
259         if (LdapURL.hasQueryComponents(name)) {
260             throw new InvalidNameException(name);
261         } else {
262             return super.getNameParser(name);
263         }
264     }
265 
getNameParser(Name name)266     public NameParser getNameParser(Name name) throws NamingException {
267         if (LdapURL.hasQueryComponents(name.get(0))) {
268             throw new InvalidNameException(name.toString());
269         } else {
270             return super.getNameParser(name);
271         }
272     }
273 
composeName(String name, String prefix)274     public String composeName(String name, String prefix)
275         throws NamingException {
276         if (LdapURL.hasQueryComponents(name)) {
277             throw new InvalidNameException(name);
278         } else if (LdapURL.hasQueryComponents(prefix)) {
279             throw new InvalidNameException(prefix);
280         } else {
281             return super.composeName(name, prefix);
282         }
283     }
284 
composeName(Name name, Name prefix)285     public Name composeName(Name name, Name prefix) throws NamingException {
286         if (LdapURL.hasQueryComponents(name.get(0))) {
287             throw new InvalidNameException(name.toString());
288         } else if (LdapURL.hasQueryComponents(prefix.get(0))) {
289             throw new InvalidNameException(prefix.toString());
290         } else {
291             return super.composeName(name, prefix);
292         }
293     }
294 
getAttributes(String name)295     public Attributes getAttributes(String name) throws NamingException {
296         if (LdapURL.hasQueryComponents(name)) {
297             throw new InvalidNameException(name);
298         } else {
299             return super.getAttributes(name);
300         }
301     }
302 
getAttributes(Name name)303     public Attributes getAttributes(Name name) throws NamingException  {
304         if (LdapURL.hasQueryComponents(name.get(0))) {
305             throw new InvalidNameException(name.toString());
306         } else {
307             return super.getAttributes(name);
308         }
309     }
310 
getAttributes(String name, String[] attrIds)311     public Attributes getAttributes(String name, String[] attrIds)
312         throws NamingException {
313         if (LdapURL.hasQueryComponents(name)) {
314             throw new InvalidNameException(name);
315         } else {
316             return super.getAttributes(name, attrIds);
317         }
318     }
319 
getAttributes(Name name, String[] attrIds)320     public Attributes getAttributes(Name name, String[] attrIds)
321         throws NamingException {
322         if (LdapURL.hasQueryComponents(name.get(0))) {
323             throw new InvalidNameException(name.toString());
324         } else {
325             return super.getAttributes(name, attrIds);
326         }
327     }
328 
modifyAttributes(String name, int mod_op, Attributes attrs)329     public void modifyAttributes(String name, int mod_op, Attributes attrs)
330         throws NamingException {
331         if (LdapURL.hasQueryComponents(name)) {
332             throw new InvalidNameException(name);
333         } else {
334             super.modifyAttributes(name, mod_op, attrs);
335         }
336     }
337 
modifyAttributes(Name name, int mod_op, Attributes attrs)338     public void modifyAttributes(Name name, int mod_op, Attributes attrs)
339         throws NamingException {
340         if (LdapURL.hasQueryComponents(name.get(0))) {
341             throw new InvalidNameException(name.toString());
342         } else {
343             super.modifyAttributes(name, mod_op, attrs);
344         }
345     }
346 
modifyAttributes(String name, ModificationItem[] mods)347     public void modifyAttributes(String name, ModificationItem[] mods)
348         throws NamingException {
349         if (LdapURL.hasQueryComponents(name)) {
350             throw new InvalidNameException(name);
351         } else {
352             super.modifyAttributes(name, mods);
353         }
354     }
355 
modifyAttributes(Name name, ModificationItem[] mods)356     public void modifyAttributes(Name name, ModificationItem[] mods)
357         throws NamingException  {
358         if (LdapURL.hasQueryComponents(name.get(0))) {
359             throw new InvalidNameException(name.toString());
360         } else {
361             super.modifyAttributes(name, mods);
362         }
363     }
364 
bind(String name, Object obj, Attributes attrs)365     public void bind(String name, Object obj, Attributes attrs)
366         throws NamingException {
367         if (LdapURL.hasQueryComponents(name)) {
368             throw new InvalidNameException(name);
369         } else {
370             super.bind(name, obj, attrs);
371         }
372     }
373 
bind(Name name, Object obj, Attributes attrs)374     public void bind(Name name, Object obj, Attributes attrs)
375         throws NamingException {
376         if (LdapURL.hasQueryComponents(name.get(0))) {
377             throw new InvalidNameException(name.toString());
378         } else {
379             super.bind(name, obj, attrs);
380         }
381     }
382 
rebind(String name, Object obj, Attributes attrs)383     public void rebind(String name, Object obj, Attributes attrs)
384         throws NamingException {
385         if (LdapURL.hasQueryComponents(name)) {
386             throw new InvalidNameException(name);
387         } else {
388             super.rebind(name, obj, attrs);
389         }
390     }
391 
rebind(Name name, Object obj, Attributes attrs)392     public void rebind(Name name, Object obj, Attributes attrs)
393         throws NamingException {
394         if (LdapURL.hasQueryComponents(name.get(0))) {
395             throw new InvalidNameException(name.toString());
396         } else {
397             super.rebind(name, obj, attrs);
398         }
399     }
400 
createSubcontext(String name, Attributes attrs)401     public DirContext createSubcontext(String name, Attributes attrs)
402         throws NamingException {
403         if (LdapURL.hasQueryComponents(name)) {
404             throw new InvalidNameException(name);
405         } else {
406             return super.createSubcontext(name, attrs);
407         }
408     }
409 
createSubcontext(Name name, Attributes attrs)410     public DirContext createSubcontext(Name name, Attributes attrs)
411         throws NamingException {
412         if (LdapURL.hasQueryComponents(name.get(0))) {
413             throw new InvalidNameException(name.toString());
414         } else {
415             return super.createSubcontext(name, attrs);
416         }
417     }
418 
getSchema(String name)419     public DirContext getSchema(String name) throws NamingException {
420         if (LdapURL.hasQueryComponents(name)) {
421             throw new InvalidNameException(name);
422         } else {
423             return super.getSchema(name);
424         }
425     }
426 
getSchema(Name name)427     public DirContext getSchema(Name name) throws NamingException {
428         if (LdapURL.hasQueryComponents(name.get(0))) {
429             throw new InvalidNameException(name.toString());
430         } else {
431             return super.getSchema(name);
432         }
433     }
434 
getSchemaClassDefinition(String name)435     public DirContext getSchemaClassDefinition(String name)
436         throws NamingException {
437         if (LdapURL.hasQueryComponents(name)) {
438             throw new InvalidNameException(name);
439         } else {
440             return super.getSchemaClassDefinition(name);
441         }
442     }
443 
getSchemaClassDefinition(Name name)444     public DirContext getSchemaClassDefinition(Name name)
445         throws NamingException {
446         if (LdapURL.hasQueryComponents(name.get(0))) {
447             throw new InvalidNameException(name.toString());
448         } else {
449             return super.getSchemaClassDefinition(name);
450         }
451     }
452 
453     // divert the search operation when the LDAP URL has query components
search(String name, Attributes matchingAttributes)454     public NamingEnumeration<SearchResult> search(String name,
455         Attributes matchingAttributes)
456         throws NamingException {
457 
458         if (LdapURL.hasQueryComponents(name)) {
459             return searchUsingURL(name);
460         } else {
461             return super.search(name, matchingAttributes);
462         }
463     }
464 
465     // divert the search operation when name has a single component
search(Name name, Attributes matchingAttributes)466     public NamingEnumeration<SearchResult> search(Name name,
467         Attributes matchingAttributes)
468         throws NamingException {
469         if (name.size() == 1) {
470             return search(name.get(0), matchingAttributes);
471         } else if (LdapURL.hasQueryComponents(name.get(0))) {
472             throw new InvalidNameException(name.toString());
473         } else {
474             return super.search(name, matchingAttributes);
475         }
476     }
477 
478     // divert the search operation when the LDAP URL has query components
search(String name, Attributes matchingAttributes, String[] attributesToReturn)479     public NamingEnumeration<SearchResult> search(String name,
480         Attributes matchingAttributes,
481         String[] attributesToReturn)
482         throws NamingException {
483 
484         if (LdapURL.hasQueryComponents(name)) {
485             return searchUsingURL(name);
486         } else {
487             return super.search(name, matchingAttributes, attributesToReturn);
488         }
489     }
490 
491     // divert the search operation when name has a single component
search(Name name, Attributes matchingAttributes, String[] attributesToReturn)492     public NamingEnumeration<SearchResult> search(Name name,
493         Attributes matchingAttributes,
494         String[] attributesToReturn)
495         throws NamingException {
496 
497         if (name.size() == 1) {
498             return search(name.get(0), matchingAttributes, attributesToReturn);
499         } else if (LdapURL.hasQueryComponents(name.get(0))) {
500             throw new InvalidNameException(name.toString());
501         } else {
502             return super.search(name, matchingAttributes, attributesToReturn);
503         }
504     }
505 
506     // divert the search operation when the LDAP URL has query components
search(String name, String filter, SearchControls cons)507     public NamingEnumeration<SearchResult> search(String name,
508         String filter,
509         SearchControls cons)
510         throws NamingException {
511 
512         if (LdapURL.hasQueryComponents(name)) {
513             return searchUsingURL(name);
514         } else {
515             return super.search(name, filter, cons);
516         }
517     }
518 
519     // divert the search operation when name has a single component
search(Name name, String filter, SearchControls cons)520     public NamingEnumeration<SearchResult> search(Name name,
521         String filter,
522         SearchControls cons)
523         throws NamingException {
524 
525         if (name.size() == 1) {
526             return search(name.get(0), filter, cons);
527         } else if (LdapURL.hasQueryComponents(name.get(0))) {
528             throw new InvalidNameException(name.toString());
529         } else {
530             return super.search(name, filter, cons);
531         }
532     }
533 
534     // divert the search operation when the LDAP URL has query components
search(String name, String filterExpr, Object[] filterArgs, SearchControls cons)535     public NamingEnumeration<SearchResult> search(String name,
536         String filterExpr,
537         Object[] filterArgs,
538         SearchControls cons)
539         throws NamingException {
540 
541         if (LdapURL.hasQueryComponents(name)) {
542             return searchUsingURL(name);
543         } else {
544             return super.search(name, filterExpr, filterArgs, cons);
545         }
546     }
547 
548     // divert the search operation when name has a single component
search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons)549     public NamingEnumeration<SearchResult> search(Name name,
550         String filterExpr,
551         Object[] filterArgs,
552         SearchControls cons)
553         throws NamingException {
554 
555         if (name.size() == 1) {
556             return search(name.get(0), filterExpr, filterArgs, cons);
557         } else if (LdapURL.hasQueryComponents(name.get(0))) {
558             throw new InvalidNameException(name.toString());
559         } else {
560             return super.search(name, filterExpr, filterArgs, cons);
561         }
562     }
563 
564     // Search using the LDAP URL in name.
565     // LDAP URL query components override the search arguments.
searchUsingURL(String name)566     private NamingEnumeration<SearchResult> searchUsingURL(String name)
567         throws NamingException {
568 
569         LdapURL url = new LdapURL(name);
570 
571         ResolveResult res = getRootURLContext(name, myEnv);
572         DirContext ctx = (DirContext)res.getResolvedObj();
573         try {
574             return ctx.search(res.getRemainingName(),
575                               setFilterUsingURL(url),
576                               setSearchControlsUsingURL(url));
577         } finally {
578             ctx.close();
579         }
580     }
581 
582     /*
583      * Initialize a String filter using the LDAP URL filter component.
584      * If filter is not present in the URL it is initialized to its default
585      * value as specified in RFC-2255.
586      */
setFilterUsingURL(LdapURL url)587     private static String setFilterUsingURL(LdapURL url) {
588 
589         String filter = url.getFilter();
590 
591         if (filter == null) {
592             filter = "(objectClass=*)"; //default value
593         }
594         return filter;
595     }
596 
597     /*
598      * Initialize a SearchControls object using LDAP URL query components.
599      * Components not present in the URL are initialized to their default
600      * values as specified in RFC-2255.
601      */
setSearchControlsUsingURL(LdapURL url)602     private static SearchControls setSearchControlsUsingURL(LdapURL url) {
603 
604         SearchControls cons = new SearchControls();
605         String scope = url.getScope();
606         String attributes = url.getAttributes();
607 
608         if (scope == null) {
609             cons.setSearchScope(SearchControls.OBJECT_SCOPE); //default value
610         } else {
611             if (scope.equals("sub")) {
612                 cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
613             } else if (scope.equals("one")) {
614                 cons.setSearchScope(SearchControls.ONELEVEL_SCOPE);
615             } else if (scope.equals("base")) {
616                 cons.setSearchScope(SearchControls.OBJECT_SCOPE);
617             }
618         }
619 
620         if (attributes == null) {
621             cons.setReturningAttributes(null); //default value
622         } else {
623             StringTokenizer tokens = new StringTokenizer(attributes, ",");
624             int count = tokens.countTokens();
625             String[] attrs = new String[count];
626             for (int i = 0; i < count; i ++) {
627                 attrs[i] = tokens.nextToken();
628             }
629             cons.setReturningAttributes(attrs);
630         }
631         return cons;
632     }
633 }
634