View Javadoc
1   /*
2    * Copyright (c) 1999, 2002, 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.ldap;
27  
28  import javax.naming.*;
29  import javax.naming.directory.*;
30  import javax.naming.spi.*;
31  import java.net.URL;
32  import java.net.MalformedURLException;
33  import java.io.UnsupportedEncodingException;
34  import java.util.StringTokenizer;
35  import com.sun.jndi.toolkit.url.Uri;
36  import com.sun.jndi.toolkit.url.UrlUtil;
37  
38  /*
39   * Extract components of an LDAP URL.
40   *
41   * The format of an LDAP URL is defined in RFC 2255 as follows:
42   *
43   *     ldapurl    = scheme "://" [hostport] ["/"
44   *                  [dn ["?" [attributes] ["?" [scope]
45   *                  ["?" [filter] ["?" extensions]]]]]]
46   *     scheme     = "ldap"
47   *     attributes = attrdesc *("," attrdesc)
48   *     scope      = "base" / "one" / "sub"
49   *     dn         = distinguishedName from Section 3 of [1]
50   *     hostport   = hostport from Section 5 of RFC 1738 [5]
51   *     attrdesc   = AttributeDescription from Section 4.1.5 of [2]
52   *     filter     = filter from Section 4 of [4]
53   *     extensions = extension *("," extension)
54   *     extension  = ["!"] extype ["=" exvalue]
55   *     extype     = token / xtoken
56   *     exvalue    = LDAPString from section 4.1.2 of [2]
57   *     token      = oid from section 4.1 of [3]
58   *     xtoken     = ("X-" / "x-") token
59   *
60   * For example,
61   *
62   *     ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US
63   *     ldap://host.com:6666/o=IMC,c=US??sub?(cn=Babs%20Jensen)
64   *
65   * This class also supports ldaps URLs.
66   */
67  
68  final public class LdapURL extends Uri {
69  
70      private boolean useSsl = false;
71      private String DN = null;
72      private String attributes = null;
73      private String scope = null;
74      private String filter = null;
75      private String extensions = null;
76  
77      /**
78       * Creates an LdapURL object from an LDAP URL string.
79       */
80      public LdapURL(String url) throws NamingException {
81  
82          super();
83  
84          try {
85              init(url); // scheme, host, port, path, query
86              useSsl = scheme.equalsIgnoreCase("ldaps");
87  
88              if (! (scheme.equalsIgnoreCase("ldap") || useSsl)) {
89                  throw new MalformedURLException("Not an LDAP URL: " + url);
90              }
91  
92              parsePathAndQuery(); // DN, attributes, scope, filter, extensions
93  
94          } catch (MalformedURLException e) {
95              NamingException ne = new NamingException("Cannot parse url: " + url);
96              ne.setRootCause(e);
97              throw ne;
98          } catch (UnsupportedEncodingException e) {
99              NamingException ne = new NamingException("Cannot parse url: " + url);
100             ne.setRootCause(e);
101             throw ne;
102         }
103     }
104 
105     /**
106      * Returns true if the URL is an LDAPS URL.
107      */
108     public boolean useSsl() {
109         return useSsl;
110     }
111 
112     /**
113      * Returns the LDAP URL's distinguished name.
114      */
115     public String getDN() {
116         return DN;
117     }
118 
119     /**
120      * Returns the LDAP URL's attributes.
121      */
122     public String getAttributes() {
123         return attributes;
124     }
125 
126     /**
127      * Returns the LDAP URL's scope.
128      */
129     public String getScope() {
130         return scope;
131     }
132 
133     /**
134      * Returns the LDAP URL's filter.
135      */
136     public String getFilter() {
137         return filter;
138     }
139 
140     /**
141      * Returns the LDAP URL's extensions.
142      */
143     public String getExtensions() {
144         return extensions;
145     }
146 
147     /**
148      * Given a space-separated list of LDAP URLs, returns an array of strings.
149      */
150     public static String[] fromList(String urlList) throws NamingException {
151 
152         String[] urls = new String[(urlList.length() + 1) / 2];
153         int i = 0;              // next available index in urls
154         StringTokenizer st = new StringTokenizer(urlList, " ");
155 
156         while (st.hasMoreTokens()) {
157             urls[i++] = st.nextToken();
158         }
159         String[] trimmed = new String[i];
160         System.arraycopy(urls, 0, trimmed, 0, i);
161         return trimmed;
162     }
163 
164     /**
165      * Derermines whether an LDAP URL has query components.
166      */
167     public static boolean hasQueryComponents(String url) {
168         return (url.lastIndexOf('?') != -1);
169     }
170 
171     /*
172      * Assembles an LDAP or LDAPS URL string from its components.
173      * If "host" is an IPv6 literal, it may optionally include delimiting
174      * brackets.
175      */
176     static String toUrlString(String host, int port, String dn, boolean useSsl)
177         {
178 
179         try {
180             String h = (host != null) ? host : "";
181             if ((h.indexOf(':') != -1) && (h.charAt(0) != '[')) {
182                 h = "[" + h + "]";          // IPv6 literal
183             }
184             String p = (port != -1) ? (":" + port) : "";
185             String d = (dn != null) ? ("/" + UrlUtil.encode(dn, "UTF8")) : "";
186 
187             return useSsl ? "ldaps://" + h + p + d : "ldap://" + h + p + d;
188         } catch (UnsupportedEncodingException e) {
189             // UTF8 should always be supported
190             throw new IllegalStateException("UTF-8 encoding unavailable");
191         }
192     }
193 
194     /*
195      * Parses the path and query components of an URL and sets this
196      * object's fields accordingly.
197      */
198     private void parsePathAndQuery() throws MalformedURLException,
199         UnsupportedEncodingException {
200 
201         // path begins with a '/' or is empty
202 
203         if (path.equals("")) {
204             return;
205         }
206 
207         DN = path.startsWith("/") ? path.substring(1) : path;
208         if (DN.length() > 0) {
209             DN = UrlUtil.decode(DN, "UTF8");
210         }
211 
212         // query begins with a '?' or is null
213 
214         if (query == null) {
215             return;
216         }
217 
218         int qmark2 = query.indexOf('?', 1);
219 
220         if (qmark2 < 0) {
221             attributes = query.substring(1);
222             return;
223         } else if (qmark2 != 1) {
224             attributes = query.substring(1, qmark2);
225         }
226 
227         int qmark3 = query.indexOf('?', qmark2 + 1);
228 
229         if (qmark3 < 0) {
230             scope = query.substring(qmark2 + 1);
231             return;
232         } else if (qmark3 != qmark2 + 1) {
233             scope = query.substring(qmark2 + 1, qmark3);
234         }
235 
236         int qmark4 = query.indexOf('?', qmark3 + 1);
237 
238         if (qmark4 < 0) {
239             filter = query.substring(qmark3 + 1);
240         } else {
241             if (qmark4 != qmark3 + 1) {
242                 filter = query.substring(qmark3 + 1, qmark4);
243             }
244             extensions = query.substring(qmark4 + 1);
245             if (extensions.length() > 0) {
246                 extensions = UrlUtil.decode(extensions, "UTF8");
247             }
248         }
249         if (filter != null && filter.length() > 0) {
250             filter = UrlUtil.decode(filter, "UTF8");
251         }
252     }
253 
254 /*
255     public static void main(String[] args) throws Exception {
256 
257         LdapURL url = new LdapURL(args[0]);
258 
259         System.out.println("Example LDAP URL: " + url.toString());
260         System.out.println("  scheme: " + url.getScheme());
261         System.out.println("    host: " + url.getHost());
262         System.out.println("    port: " + url.getPort());
263         System.out.println("      DN: " + url.getDN());
264         System.out.println("   attrs: " + url.getAttributes());
265         System.out.println("   scope: " + url.getScope());
266         System.out.println("  filter: " + url.getFilter());
267         System.out.println("  extens: " + url.getExtensions());
268         System.out.println("");
269     }
270 */
271 }