【问题标题】:How to tell LDAP SSL server with multiple certificates to return the one that I need?如何告诉具有多个证书的 LDAP SSL 服务器返回我需要的证书?
【发布时间】:2013-11-22 23:50:11
【问题描述】:

我的简单 LDAP java 程序,使用

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");  
env.put(Context.SECURITY_AUTHENTICATION, "simple");  
env.put(Context.SECURITY_PRINCIPAL, <UserDN>);  
env.put(Context.SECURITY_CREDENTIALS, <Password>);  
env.put(Context.SECURITY_PROTOCOL, "ssl");  
env.put(Context.PROVIDER_URL, "ldaps://<host>:636");  

为了使 LDAP SSL 身份验证停止工作,因为在我根本无权访问的服务器上安装了具有相同 CN 但主题中的其他详细信息不同的第二个服务器证书。

当我创建初始上下文时程序失败

new InitialDirContext(env);

错误是“初始化目录上下文失败::636


它在我运行时返回第二个服务器证书

openssl s_client -showcerts -connect <host>:636 </dev/null

这让我相信解决方案将是找到一种方法来告诉服务器使用哪个证书。

我搜索并阅读了很多关于这个主题的文章,我不得不承认我很困惑,我不清楚这些文章是在谈论客户端证书还是服务器证书,或者要采取的措施是用于客户端或服务器端。

在一篇文章中,它说我可以使用带有密钥库路径的自定义 SSLSocketFactory 和

env.put("java.naming.ldap.factory.socket", "com.xxx.MyCustomSSLSocketFactory");

但我不知道服务器上服务器证书密钥库的路径。

在一篇 Microsoft 文章中,它说最好的解决方案是在服务器上仅拥有一个服务器证书,或者将服务器证书放入 Active Directory 域服务 (NTDS\Personal) 证书存储中以进行 LDAPS 通信。但我无权访问服务器,必须在我的 LDAP java 程序中“修复”这个问题。

在另一篇文章中,它说使用服务器名称指示 (SNI) 扩展。

那么有没有一种方法可以指定我想要的服务器证书?还是我的问题出在其他地方?

非常感谢。


这是堆栈跟踪:

javax.naming.ServiceUnavailableException: <host>:636; socket closed
    at com.sun.jndi.ldap.Connection.readReply(Connection.java:419)
    at com.sun.jndi.ldap.LdapClient.ldapBind(LdapClient.java:340)
    at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:192)
    at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2694)
    at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:293)
    at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:175)
    at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:193)
    at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:136)
    at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:66)
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
    at javax.naming.InitialContext.init(InitialContext.java:223)
    at javax.naming.InitialContext.<init>(InitialContext.java:197)
    at javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:82)

当我使用 Jxplorer 运行相同的测试时,它给了我同样的错误。

EJP 指出问题在于证书不受信任是正确的。非常感谢 EJP。

当我在 %JAVA_HOME%/lib/security/cacerts 中安装 CA 证书时,Jxplorer 工作了。我的程序仍然失败。我必须在其中添加这些行才能使其正常工作(但不确定我是否需要所有这些行......):

System.setProperty("javax.net.ssl.keyStore",%JAVA_HOME%/lib/security/cacerts);
System.setProperty("javax.net.ssl.trustStore",%JAVA_HOME%/lib/security/cacerts);
System.setProperty("javax.net.ssl.keyStorePassword=changeit);
System.setProperty("javax.net.ssl.trustStorePassword=changeit);

但由于证书最初不受信任,我只是“强制”我们的服务器信任它,因此这种解决方案是不可接受的。而且我们的服务器和 LDAP 服务器都不是使用 Java 7 运行的。所以 SNI 也出来了!

EJP 提到如果服务器证书具有不同的算法或颁发者,我可以通过限制客户端(我的 web 应用程序)中的密码套件或接受的颁发者来控制服务器证书。这两个证书确实有不同的颁发者,但是,我不知道该怎么做,我也找不到任何东西。

EJP 能否请您详细说明,或指出一些网站...?

【问题讨论】:

  • 请发布整个堆栈跟踪。
  • EJP,再次感谢。不幸的是,没有可用的堆栈跟踪。但是在创建初始上下文时会发生错误:new InitialDirContext(env),并且错误说它无法初始化目录上下文::636
  • 该错误是一个异常,它有一个堆栈跟踪。您必须打印它,然后将其张贴在这里。您可能还必须使用 -Djavax.net.debug=ssl,handshake 运行您的客户端并在此处发布结果。
  • 堆栈跟踪没有写入日志,只有错误信息。并且代码在与外部 LDAP 服务器有连接的服务器中运行,而我的本地机器没有。并且代码被编译成一个由 web 服务调用的 jar。我不能简单地去那里添加代码来写出堆栈跟踪。
  • 那您的问题无法回答,抱歉。你只需要采取这些步骤。

标签: authentication ssl active-directory ldap


【解决方案1】:

如果证书有不同的颁发者,您可以通过控制哪些颁发者在您的信任库中来控制您在客户端获得的证书。如果只有其中一个,那就是您将得到的那个。如果他们都在那里,你会得到运气。请注意,如果您的信任库还包含一个共同的超级发行人,那么这可能是运气。

【讨论】:

  • 非常感谢 EJP。我从程序中删除了 4 java setProperty,删除了不受信任的证书并安装了受信任的证书。它奏效了!我花了很多时间阅读 SSL LDAP 身份验证材料来解决我的问题,我没有遇到任何人提到您的解决方案,但它是如此简单。
【解决方案2】:

如果您在 Microsoft 管理控制台中的证书 - 服务(Active Directory 域服务) - NTDS\个人位置中指定一个且仅一个证书,则结果不是运气。不过,与我读过的 Microsoft 文档相反,似乎需要重新启动域控制器才能使新指定的证书“生效”。

【讨论】:

    猜你喜欢
    • 2013-07-29
    • 2015-07-05
    • 1970-01-01
    • 2020-04-14
    • 1970-01-01
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    • 2020-11-02
    相关资源
    最近更新 更多