【发布时间】: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);
错误是“初始化目录上下文失败:
它在我运行时返回第二个服务器证书
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