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