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 }