001: /*
002: * Copyright 1999-2006 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 java.util.Hashtable;
029: import java.util.Vector;
030: import java.util.Enumeration;
031: import java.net.MalformedURLException;
032:
033: import javax.naming.*;
034: import javax.naming.directory.*;
035: import javax.naming.spi.ObjectFactory;
036: import javax.naming.spi.InitialContextFactory;
037: import javax.naming.ldap.Control;
038:
039: import com.sun.jndi.url.ldap.ldapURLContextFactory;
040:
041: final public class LdapCtxFactory implements ObjectFactory,
042: InitialContextFactory {
043: /**
044: * The type of each address in an LDAP reference.
045: */
046: public final static String ADDRESS_TYPE = "URL";
047:
048: // ----------------- ObjectFactory interface --------------------
049:
050: public Object getObjectInstance(Object ref, Name name,
051: Context nameCtx, Hashtable<?, ?> env) throws Exception {
052:
053: if (!isLdapRef(ref)) {
054: return null;
055: }
056: ObjectFactory factory = new ldapURLContextFactory();
057: String[] urls = getURLs((Reference) ref);
058: return factory.getObjectInstance(urls, name, nameCtx, env);
059: }
060:
061: // ----------------- InitialContext interface --------------------
062:
063: public Context getInitialContext(Hashtable<?, ?> envprops)
064: throws NamingException {
065:
066: try {
067: String providerUrl = (envprops != null) ? (String) envprops
068: .get(Context.PROVIDER_URL) : null;
069:
070: // If URL not in environment, use defaults
071: if (providerUrl == null) {
072: return new LdapCtx("", LdapCtx.DEFAULT_HOST,
073: LdapCtx.DEFAULT_PORT, envprops, false);
074: }
075:
076: // Extract URL(s)
077: String[] urls = LdapURL.fromList(providerUrl);
078:
079: if (urls.length == 0) {
080: throw new ConfigurationException(Context.PROVIDER_URL
081: + " property does not contain a URL");
082: }
083:
084: // Generate an LDAP context
085: return getLdapCtxInstance(urls, envprops);
086:
087: } catch (LdapReferralException e) {
088:
089: if (envprops != null
090: && "throw".equals(envprops.get(Context.REFERRAL))) {
091: throw e;
092: }
093:
094: Control[] bindCtls = (envprops != null) ? (Control[]) envprops
095: .get(LdapCtx.BIND_CONTROLS)
096: : null;
097:
098: return (LdapCtx) e.getReferralContext(envprops, bindCtls);
099: }
100: }
101:
102: /**
103: * Returns true if argument is an LDAP reference.
104: */
105: private static boolean isLdapRef(Object obj) {
106:
107: if (!(obj instanceof Reference)) {
108: return false;
109: }
110: String this ClassName = LdapCtxFactory.class.getName();
111: Reference ref = (Reference) obj;
112:
113: return this ClassName.equals(ref.getFactoryClassName());
114: }
115:
116: /**
117: * Returns the URLs contained within an LDAP reference.
118: */
119: private static String[] getURLs(Reference ref)
120: throws NamingException {
121:
122: int size = 0; // number of URLs
123: String[] urls = new String[ref.size()];
124:
125: Enumeration addrs = ref.getAll();
126: while (addrs.hasMoreElements()) {
127: RefAddr addr = (RefAddr) addrs.nextElement();
128:
129: if ((addr instanceof StringRefAddr)
130: && addr.getType().equals(ADDRESS_TYPE)) {
131:
132: urls[size++] = (String) addr.getContent();
133: }
134: }
135: if (size == 0) {
136: throw (new ConfigurationException(
137: "Reference contains no valid addresses"));
138: }
139:
140: // Trim URL array down to size.
141: if (size == ref.size()) {
142: return urls;
143: }
144: String[] urls2 = new String[size];
145: System.arraycopy(urls, 0, urls2, 0, size);
146: return urls2;
147: }
148:
149: // ------------ Utilities used by other classes ----------------
150:
151: public static DirContext getLdapCtxInstance(Object urlInfo,
152: Hashtable env) throws NamingException {
153:
154: if (urlInfo instanceof String) {
155: return getUsingURL((String) urlInfo, env);
156: } else if (urlInfo instanceof String[]) {
157: return getUsingURLs((String[]) urlInfo, env);
158: } else {
159: throw new IllegalArgumentException(
160: "argument must be an LDAP URL String or array of them");
161: }
162: }
163:
164: private static DirContext getUsingURL(String url, Hashtable env)
165: throws NamingException {
166: DirContext ctx = null;
167: LdapURL ldapUrl = new LdapURL(url);
168: String dn = ldapUrl.getDN();
169: String host = ldapUrl.getHost();
170: int port = ldapUrl.getPort();
171: String[] hostports;
172: String domainName = null;
173:
174: // handle a URL with no hostport (ldap:/// or ldaps:///)
175: // locate the LDAP service using the URL's distinguished name
176: if (host == null
177: && port == -1
178: && dn != null
179: && (domainName = ServiceLocator.mapDnToDomainName(dn)) != null
180: && (hostports = ServiceLocator.getLdapService(
181: domainName, env)) != null) {
182: // Generate new URLs that include the discovered hostports.
183: // Reuse the original URL scheme.
184: String scheme = ldapUrl.getScheme() + "://";
185: String[] newUrls = new String[hostports.length];
186: String query = ldapUrl.getQuery();
187: String urlSuffix = ldapUrl.getPath()
188: + (query != null ? query : "");
189: for (int i = 0; i < hostports.length; i++) {
190: newUrls[i] = scheme + hostports[i] + urlSuffix;
191: }
192: ctx = getUsingURLs(newUrls, env);
193: // Associate the derived domain name with the context
194: ((LdapCtx) ctx).setDomainName(domainName);
195:
196: } else {
197: ctx = new LdapCtx(dn, host, port, env, ldapUrl.useSsl());
198: // Record the URL that created the context
199: ((LdapCtx) ctx).setProviderUrl(url);
200: }
201: return ctx;
202: }
203:
204: /*
205: * Try each URL until one of them succeeds.
206: * If all URLs fail, throw one of the exceptions arbitrarily.
207: * Not pretty, but potentially more informative than returning null.
208: */
209: private static DirContext getUsingURLs(String[] urls, Hashtable env)
210: throws NamingException {
211: NamingException ne = null;
212: DirContext ctx = null;
213: for (int i = 0; i < urls.length; i++) {
214: try {
215: return getUsingURL(urls[i], env);
216: } catch (AuthenticationException e) {
217: throw e;
218: } catch (NamingException e) {
219: ne = e;
220: }
221: }
222: throw ne;
223: }
224:
225: /**
226: * Used by Obj and obj/RemoteToAttrs too so must be public
227: */
228: public static Attribute createTypeNameAttr(Class cl) {
229: Vector v = new Vector(10);
230: String[] types = getTypeNames(cl, v);
231: if (types.length > 0) {
232: BasicAttribute tAttr = new BasicAttribute(
233: Obj.JAVA_ATTRIBUTES[Obj.TYPENAME]);
234: for (int i = 0; i < types.length; i++) {
235: tAttr.add(types[i]);
236: }
237: return tAttr;
238: }
239: return null;
240: }
241:
242: private static String[] getTypeNames(Class currentClass, Vector v) {
243:
244: getClassesAux(currentClass, v);
245: Class[] members = currentClass.getInterfaces();
246: for (int i = 0; i < members.length; i++) {
247: getClassesAux(members[i], v);
248: }
249: String[] ret = new String[v.size()];
250: int i = 0;
251: for (java.util.Enumeration e = v.elements(); e
252: .hasMoreElements();) {
253: ret[i++] = (String) e.nextElement();
254: }
255: return ret;
256: }
257:
258: private static void getClassesAux(Class currentClass, Vector v) {
259: if (!v.contains(currentClass.getName())) {
260: v.addElement(currentClass.getName());
261: }
262: currentClass = currentClass.getSuperclass();
263:
264: while (currentClass != null) {
265: getTypeNames(currentClass, v);
266: currentClass = currentClass.getSuperclass();
267: }
268: }
269: }
|