--- old/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtxFactory.java 2017-01-25 16:14:21.198435926 +0000 +++ new/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtxFactory.java 2017-01-25 16:14:21.070435069 +0000 @@ -25,9 +25,14 @@ package com.sun.jndi.ldap; +import java.lang.reflect.Constructor; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Hashtable; +import java.util.List; import java.util.Vector; import java.util.Enumeration; +import java.util.function.BiFunction; import javax.naming.*; import javax.naming.directory.*; @@ -158,42 +163,61 @@ } private static DirContext getUsingURL(String url, Hashtable env) - throws NamingException { - DirContext ctx = null; - LdapURL ldapUrl = new LdapURL(url); - String dn = ldapUrl.getDN(); - String host = ldapUrl.getHost(); - int port = ldapUrl.getPort(); - String[] hostports; - String domainName = null; - - // handle a URL with no hostport (ldap:/// or ldaps:///) - // locate the LDAP service using the URL's distinguished name - if (host == null && - port == -1 && - dn != null && - (domainName = ServiceLocator.mapDnToDomainName(dn)) != null && - (hostports = ServiceLocator.getLdapService(domainName, env)) - != null) { - // Generate new URLs that include the discovered hostports. - // Reuse the original URL scheme. - String scheme = ldapUrl.getScheme() + "://"; - String[] newUrls = new String[hostports.length]; - String query = ldapUrl.getQuery(); - String urlSuffix = ldapUrl.getPath() + (query != null ? query : ""); - for (int i = 0; i < hostports.length; i++) { - newUrls[i] = scheme + hostports[i] + urlSuffix; - } - ctx = getUsingURLs(newUrls, env); - // Associate the derived domain name with the context - ((LdapCtx)ctx).setDomainName(domainName); + throws NamingException + { + NamingException ne = new NamingException(); + DirContext ctx; + try { + List urls = getDnsUrls(url, env); + if (urls.size() == 0) { + String factory; + if (env.contains(LdapCtx.DNS_PROVIDER)) { + factory = (String) env.get(LdapCtx.DNS_PROVIDER); + } else { + factory = "com.sun.jndi.ldap.DefaultDnsProvider"; + } + throw new NamingException( + factory + " was unable to resolve a valid ldap url"); + } - } else { - ctx = new LdapCtx(dn, host, port, env, ldapUrl.useSsl()); - // Record the URL that created the context - ((LdapCtx)ctx).setProviderUrl(url); + for (String u : urls) { + LdapURL ldapUrl = new LdapURL(u); + String dn = ldapUrl.getDN(); + String host = ldapUrl.getHost(); + int port = ldapUrl.getPort(); + ctx = new LdapCtx(dn, host, port, env, ldapUrl.useSsl()); + // Record the URL that created the context + ((LdapCtx) ctx).setProviderUrl(u); + return ctx; + } + } catch (Exception e) { + ne.setRootCause(e); } - return ctx; + throw ne; + } + + @SuppressWarnings("unchecked") + private static List getDnsUrls(String url, Hashtable env) + throws Exception + { + BiFunction, List> dnsProvider = null; + + if (env.containsKey(LdapCtx.DNS_PROVIDER)) { + PrivilegedAction act = + Thread.currentThread()::getContextClassLoader; + ClassLoader cl = AccessController.doPrivileged(act); + Class cls = Class.forName( + (String) env.get(LdapCtx.DNS_PROVIDER), true, cl); + Constructor ctor = cls.getConstructor(); + dnsProvider = + (BiFunction, List>) ctor.newInstance(); + } + + if (dnsProvider == null) { + dnsProvider = new DefaultLdapDnsProvider(); + } + + return dnsProvider.apply(url, env); } /* @@ -202,12 +226,18 @@ * Not pretty, but potentially more informative than returning null. */ private static DirContext getUsingURLs(String[] urls, Hashtable env) - throws NamingException { - NamingException ne = null; - DirContext ctx = null; - for (int i = 0; i < urls.length; i++) { + throws NamingException + { + NamingException ne = new NamingException(); + DirContext ctx; + for (String u : urls) { try { - return getUsingURL(urls[i], env); + ctx = getUsingURL(u, env); + LdapURL ldapUrl = new LdapURL(u); + // Associate the derived domain name with the context + ((LdapCtx) ctx).setDomainName( + ServiceLocator.mapDnToDomainName(ldapUrl.getDN())); + return ctx; } catch (AuthenticationException e) { throw e; } catch (NamingException e) {