001: /*
002: * Copyright 1999-2002 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.jndi.ldap;
027:
028: import javax.naming.*;
029: import javax.naming.directory.*;
030: import javax.naming.spi.*;
031: import java.net.URL;
032: import java.net.MalformedURLException;
033: import java.io.UnsupportedEncodingException;
034: import java.util.StringTokenizer;
035: import com.sun.jndi.toolkit.url.Uri;
036: import com.sun.jndi.toolkit.url.UrlUtil;
037:
038: /*
039: * Extract components of an LDAP URL.
040: *
041: * The format of an LDAP URL is defined in RFC 2255 as follows:
042: *
043: * ldapurl = scheme "://" [hostport] ["/"
044: * [dn ["?" [attributes] ["?" [scope]
045: * ["?" [filter] ["?" extensions]]]]]]
046: * scheme = "ldap"
047: * attributes = attrdesc *("," attrdesc)
048: * scope = "base" / "one" / "sub"
049: * dn = distinguishedName from Section 3 of [1]
050: * hostport = hostport from Section 5 of RFC 1738 [5]
051: * attrdesc = AttributeDescription from Section 4.1.5 of [2]
052: * filter = filter from Section 4 of [4]
053: * extensions = extension *("," extension)
054: * extension = ["!"] extype ["=" exvalue]
055: * extype = token / xtoken
056: * exvalue = LDAPString from section 4.1.2 of [2]
057: * token = oid from section 4.1 of [3]
058: * xtoken = ("X-" / "x-") token
059: *
060: * For example,
061: *
062: * ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US
063: * ldap://host.com:6666/o=IMC,c=US??sub?(cn=Babs%20Jensen)
064: *
065: * This class also supports ldaps URLs.
066: */
067:
068: final public class LdapURL extends Uri {
069:
070: private boolean useSsl = false;
071: private String DN = null;
072: private String attributes = null;
073: private String scope = null;
074: private String filter = null;
075: private String extensions = null;
076:
077: /**
078: * Creates an LdapURL object from an LDAP URL string.
079: */
080: public LdapURL(String url) throws NamingException {
081:
082: super ();
083:
084: try {
085: init(url); // scheme, host, port, path, query
086: useSsl = scheme.equalsIgnoreCase("ldaps");
087:
088: if (!(scheme.equalsIgnoreCase("ldap") || useSsl)) {
089: throw new MalformedURLException("Not an LDAP URL: "
090: + url);
091: }
092:
093: parsePathAndQuery(); // DN, attributes, scope, filter, extensions
094:
095: } catch (MalformedURLException e) {
096: NamingException ne = new NamingException(
097: "Cannot parse url: " + url);
098: ne.setRootCause(e);
099: throw ne;
100: } catch (UnsupportedEncodingException e) {
101: NamingException ne = new NamingException(
102: "Cannot parse url: " + url);
103: ne.setRootCause(e);
104: throw ne;
105: }
106: }
107:
108: /**
109: * Returns true if the URL is an LDAPS URL.
110: */
111: public boolean useSsl() {
112: return useSsl;
113: }
114:
115: /**
116: * Returns the LDAP URL's distinguished name.
117: */
118: public String getDN() {
119: return DN;
120: }
121:
122: /**
123: * Returns the LDAP URL's attributes.
124: */
125: public String getAttributes() {
126: return attributes;
127: }
128:
129: /**
130: * Returns the LDAP URL's scope.
131: */
132: public String getScope() {
133: return scope;
134: }
135:
136: /**
137: * Returns the LDAP URL's filter.
138: */
139: public String getFilter() {
140: return filter;
141: }
142:
143: /**
144: * Returns the LDAP URL's extensions.
145: */
146: public String getExtensions() {
147: return extensions;
148: }
149:
150: /**
151: * Given a space-separated list of LDAP URLs, returns an array of strings.
152: */
153: public static String[] fromList(String urlList)
154: throws NamingException {
155:
156: String[] urls = new String[(urlList.length() + 1) / 2];
157: int i = 0; // next available index in urls
158: StringTokenizer st = new StringTokenizer(urlList, " ");
159:
160: while (st.hasMoreTokens()) {
161: urls[i++] = st.nextToken();
162: }
163: String[] trimmed = new String[i];
164: System.arraycopy(urls, 0, trimmed, 0, i);
165: return trimmed;
166: }
167:
168: /**
169: * Derermines whether an LDAP URL has query components.
170: */
171: public static boolean hasQueryComponents(String url) {
172: return (url.lastIndexOf('?') != -1);
173: }
174:
175: /*
176: * Assembles an LDAP or LDAPS URL string from its components.
177: * If "host" is an IPv6 literal, it may optionally include delimiting
178: * brackets.
179: */
180: static String toUrlString(String host, int port, String dn,
181: boolean useSsl) {
182:
183: try {
184: String h = (host != null) ? host : "";
185: if ((h.indexOf(':') != -1) && (h.charAt(0) != '[')) {
186: h = "[" + h + "]"; // IPv6 literal
187: }
188: String p = (port != -1) ? (":" + port) : "";
189: String d = (dn != null) ? ("/" + UrlUtil.encode(dn, "UTF8"))
190: : "";
191:
192: return useSsl ? "ldaps://" + h + p + d : "ldap://" + h + p
193: + d;
194: } catch (UnsupportedEncodingException e) {
195: // UTF8 should always be supported
196: throw new IllegalStateException(
197: "UTF-8 encoding unavailable");
198: }
199: }
200:
201: /*
202: * Parses the path and query components of an URL and sets this
203: * object's fields accordingly.
204: */
205: private void parsePathAndQuery() throws MalformedURLException,
206: UnsupportedEncodingException {
207:
208: // path begins with a '/' or is empty
209:
210: if (path.equals("")) {
211: return;
212: }
213:
214: DN = path.startsWith("/") ? path.substring(1) : path;
215: if (DN.length() > 0) {
216: DN = UrlUtil.decode(DN, "UTF8");
217: }
218:
219: // query begins with a '?' or is null
220:
221: if (query == null) {
222: return;
223: }
224:
225: int qmark2 = query.indexOf('?', 1);
226:
227: if (qmark2 < 0) {
228: attributes = query.substring(1);
229: return;
230: } else if (qmark2 != 1) {
231: attributes = query.substring(1, qmark2);
232: }
233:
234: int qmark3 = query.indexOf('?', qmark2 + 1);
235:
236: if (qmark3 < 0) {
237: scope = query.substring(qmark2 + 1);
238: return;
239: } else if (qmark3 != qmark2 + 1) {
240: scope = query.substring(qmark2 + 1, qmark3);
241: }
242:
243: int qmark4 = query.indexOf('?', qmark3 + 1);
244:
245: if (qmark4 < 0) {
246: filter = query.substring(qmark3 + 1);
247: } else {
248: if (qmark4 != qmark3 + 1) {
249: filter = query.substring(qmark3 + 1, qmark4);
250: }
251: extensions = query.substring(qmark4 + 1);
252: if (extensions.length() > 0) {
253: extensions = UrlUtil.decode(extensions, "UTF8");
254: }
255: }
256: if (filter != null && filter.length() > 0) {
257: filter = UrlUtil.decode(filter, "UTF8");
258: }
259: }
260:
261: /*
262: public static void main(String[] args) throws Exception {
263:
264: LdapURL url = new LdapURL(args[0]);
265:
266: System.out.println("Example LDAP URL: " + url.toString());
267: System.out.println(" scheme: " + url.getScheme());
268: System.out.println(" host: " + url.getHost());
269: System.out.println(" port: " + url.getPort());
270: System.out.println(" DN: " + url.getDN());
271: System.out.println(" attrs: " + url.getAttributes());
272: System.out.println(" scope: " + url.getScope());
273: System.out.println(" filter: " + url.getFilter());
274: System.out.println(" extens: " + url.getExtensions());
275: System.out.println("");
276: }
277: */
278: }
|