--- old/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtxFactory.java 2017-11-29 17:13:34.376978827 +0000 +++ new/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtxFactory.java 2017-11-29 17:13:34.264978310 +0000 @@ -25,12 +25,11 @@ package com.sun.jndi.ldap; -import java.util.Hashtable; -import java.util.Vector; -import java.util.Enumeration; +import java.util.*; import javax.naming.*; import javax.naming.directory.*; +import javax.naming.ldap.LdapDnsProviderResult; import javax.naming.spi.ObjectFactory; import javax.naming.spi.InitialContextFactory; import javax.naming.ldap.Control; @@ -158,41 +157,74 @@ } 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 + { + try { + LdapDnsProviderResult r = + LdapDnsProviderService.getInstance().lookupEndpoints(url, env); + LdapCtx ctx = null; + NamingException lastException = null; + + /* + * Prior to this change we had been assuming that the url.getDN() + * should be converted to a domain name via + * ServiceLocator.mapDnToDomainName(url.getDN()) + * + * However this is incorrect as we can't assume that the supplied + * url.getDN() is the same as the dns domain for the directory + * server. + * + * This means that we depend on the dnsProvider to return both + * the list of urls of individual hosts from which we attempt to + * create an LdapCtx from *AND* the domain name that they serve + * + * In order to do this the dnsProvider must return an + * {@link LdapDnsProviderResult}. + * + */ + for (String u : r.getEndpoints()) { + try { + ctx = getLdapCtxFromUrl( + r.getDomainName(), new LdapURL(u), env); + } catch (NamingException e) { + // try the next element + lastException = e; + } + } + + if (lastException != null) { + throw lastException; + } + + if (ctx == null) { + // we have resolved them, but they are not valid + throw new NamingException("Could not resolve a valid ldap host"); + } - } else { - ctx = new LdapCtx(dn, host, port, env, ldapUrl.useSsl()); // Record the URL that created the context - ((LdapCtx)ctx).setProviderUrl(url); + ctx.setProviderUrl(url); + return ctx; + } catch (NamingException e) { + // getDnsUrls(url, env) may throw a NamingException, which there is + // no need to wrap. + throw e; + } catch (Exception e) { + NamingException ex = new NamingException(); + ex.setRootCause(e); + throw ex; } + } + + private static LdapCtx getLdapCtxFromUrl(String domain, + LdapURL url, + Hashtable env) + throws NamingException + { + String dn = url.getDN(); + String host = url.getHost(); + int port = url.getPort(); + LdapCtx ctx = new LdapCtx(dn, host, port, env, url.useSsl()); + ctx.setDomainName(domain); return ctx; } @@ -202,19 +234,17 @@ * 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 ex = null; + for (String u : urls) { try { - return getUsingURL(urls[i], env); - } catch (AuthenticationException e) { - throw e; + return getUsingURL(u, env); } catch (NamingException e) { - ne = e; + ex = e; } } - throw ne; + throw ex; } /**