【问题标题】:AD authentication with one LDAP failed but passed with another LDAP一个 LDAP 的 AD 身份验证失败,但另一个 LDAP 通过
【发布时间】:2019-06-07 02:59:34
【问题描述】:

从以下网站,我找到了执行 java AD 身份验证的代码。

http://java2db.com/jndi-ldap-programming/solution-to-sslhandshakeexception

以下是代码:

MySSLSocketFactory.java

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.SecureRandom;

import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

public class MySSLSocketFactory extends SSLSocketFactory {
    private SSLSocketFactory socketFactory;
    public MySSLSocketFactory() {
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, new TrustManager[]{new DummyTrustmanager()}, new SecureRandom());
            socketFactory = ctx.getSocketFactory();
        } catch (Exception ex) {
            ex.printStackTrace(System.err);
        }
    }
    public static SocketFactory getDefault() {
        return new MySSLSocketFactory();
    }
    @Override
    public String[] getDefaultCipherSuites() {
        return socketFactory.getDefaultCipherSuites();
    }
    @Override
    public String[] getSupportedCipherSuites() {
        return socketFactory.getSupportedCipherSuites();
    }
    @Override
    public Socket createSocket(Socket socket, String string, int num, boolean bool) throws IOException {
        return socketFactory.createSocket(socket, string, num, bool);
    }
    @Override
    public Socket createSocket(String string, int num) throws IOException, UnknownHostException {
        return socketFactory.createSocket(string, num);
    }
    @Override
    public Socket createSocket(String string, int num, InetAddress netAdd, int i)
            throws IOException, UnknownHostException {
        return socketFactory.createSocket(string, num, netAdd, i);
    }
    @Override
    public Socket createSocket(InetAddress netAdd, int num) throws IOException {
        return socketFactory.createSocket(netAdd, num);
    }
    @Override
    public Socket createSocket(InetAddress netAdd1, int num, InetAddress netAdd2, int i) throws IOException {
        return socketFactory.createSocket(netAdd1, num, netAdd2, i);
    }
}

DummyTrustmanager.java

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

public class DummyTrustmanager implements X509TrustManager {
    public void checkClientTrusted(X509Certificate[] cert, String string) throws CertificateException
    {
    }
    public void checkServerTrusted(X509Certificate[] cert, String string) throws CertificateException
    {
    }
    public X509Certificate[] getAcceptedIssuers()
    {
    return new java.security.cert.X509Certificate[0];
    }

}

TestAD.java

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

public class TestAD {

    public static void main(String[] args) {
        try {
            //String url = "ldaps://abc.company.com:636";
            String url = "ldaps://xyz.group.com:636";
            String conntype = "simple";
            // String id = "abc@abc.company.com";
            String id = "xyz.group.com";
            //String password = "abcpassword";
            String password = "xyzpassword";
            Hashtable<String, String> environment = new Hashtable<String, String>();
            environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
            environment.put(Context.PROVIDER_URL, url);
            environment.put("java.naming.ldap.factory.socket", "MySSLSocketFactory");
            environment.put(Context.SECURITY_AUTHENTICATION, conntype);
            environment.put(Context.SECURITY_PRINCIPAL, id);
            environment.put(Context.SECURITY_CREDENTIALS, password);
            DirContext ldapContext = new InitialDirContext(environment);
            System.out.println("Bind successful");
        } catch (Exception exception) {
            exception.printStackTrace();
        }

    }
}

我的公司有几个子公司,他们有自己的 LDAP。当我针对我公司 ABC 的 LDAP 运行 TestAD 时,它运行良好。但是当我针对子公司 XYZ 的 LDAP 运行它时,我得到了以下异常:

javax.naming.CommunicationException: simple bind failed: xyz.group.com:636
[Root exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching xyz.group.com found.]
        at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:219)
        at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2791)
        at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:319)
        at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:192)
        at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:210)
        at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:153)
        at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:83)
        at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
        at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
        at javax.naming.InitialContext.init(InitialContext.java:244)
        at javax.naming.InitialContext.<init>(InitialContext.java:216)
        at javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:101)
        at TestAD.main(TestAD.java:26)
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching xyz.group.com found.
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1946)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
        at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:931)
        at sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
        at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
        at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
        at com.sun.jndi.ldap.Connection.run(Connection.java:877)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.security.cert.CertificateException: No subject alternative DNS name matching xyz.group.com found.
        at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:214)
        at sun.security.util.HostnameChecker.match(HostnameChecker.java:96)
        at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:459)
        at sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(SSLContextImpl.java:1125)
        at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:1092)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)
        ... 12 more

失败的原因可能是什么?我没有将 ABC 或 XYZ 的证书导入我的信任库。为什么它适用于 ABC 但不适用于 XYZ?会不会是 XYZ 期待我的证书?

【问题讨论】:

  • 补充一下,我可以远程登录到 xyz.group.com 636,所以连接不是问题。
  • 从“java.security.cert.CertificateException: No subject alternative DNS name matching xyz.group.com found”异常中反映的情况来看,您的应用程序中使用的证书中不存在 DNS“xyz.group.com”的主题备用名称。请确保您使用的是其他 AD 环境信任的证书进行通信。
  • 您的意思是“一个 LDAP server 失败,但另一个 LDAP server 通过了”? LDAP 是一个协议,而不是一个东西。
  • @user207421 大声笑.. 希望协议是正确的? ;) 在这里(再次)感谢您的贡献(居高临下的态度)。

标签: java active-directory ldap


【解决方案1】:

这是由端点识别算法引起的,它会检查配置中的主机名是否与远程 LDAPS TLS 服务器证书中的主机名匹配,并且这些主机名是否有效。

鉴于此错误No subject alternative DNS name matching xyz.group.com found,一定是“xyz.group.com”与您的 ldap 服务器证书不匹配,而“abc.company.com”则匹配。

Java 8u181 在 core-libs/javax.naming 中带来了一些变化,并更新了安全 LDAP 连接的处理方式(参见release note):

端点识别已启用 LDAPS 连接。

为了提高 LDAPS(基于 TLS 的安全 LDAP)连接的稳健性, 默认情况下已启用端点识别算法。

请注意,在某些情况下,某些应用程序可能 以前能够成功连接到 LDAPS 服务器可能没有 不再能够这样做。此类应用程序可以,如果他们认为 适当,使用新系统禁用端点识别 属性:com.sun.jndi.ldap.object.disableEndpointIdentification

定义此系统属性(或将其设置为 true)以禁用端点 识别算法。

禁用端点识别算法是一种解决方法,长期的解决方案是修复服务器证书,使其与“xyz.group.com”主机名匹配。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-20
    • 2020-04-14
    • 2015-04-19
    • 2016-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多