java - jndi LDAPS 自定义 HostnameVerifier 和 TrustManager

标签 java ssl ldap jndi jsse

我们正在编写一个应连接到不同 LDAP 服务器的应用程序。对于每个服务器,我们可能只接受特定的证书。该证书中的主机名无关紧要。这很容易,当我们使用 LDAP 和 STARTTLS 时,因为我们可以使用 StartTlsResponse.setHostnameVerifier(..-) 并使用 StartTlsResponse.negotiate(...) 与匹配SSLSocketFactory。然而,我们还需要支持 LDAPS 连接。 Java native 支持此功能,但前提是服务器证书受到默认 java keystore 的信任。虽然我们可以替换它,但我们仍然不能为不同的服务器使用不同的 keystore 。

现有连接代码如下:

Hashtable<String,String> env = new Hashtable<String,String>();
env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
env.put( Context.PROVIDER_URL, ( encryption == SSL ? "ldaps://" : "ldap://" ) + host + ":" + port );
if ( encryption == SSL ) {
    // env.put( "java.naming.ldap.factory.socket", "CustomSocketFactory" );
}
ctx = new InitialLdapContext( env, null );
if ( encryption != START_TLS )
    tls = null;
else {
    tls = (StartTlsResponse) ctx.extendedOperation( new StartTlsRequest() );
    tls.setHostnameVerifier( hostnameVerifier );
    tls.negotiate( sslContext.getSocketFactory() );
}

我们可以添加自己的CustomSocketFactory,但是如何向它传递信息呢?

最佳答案

对于其他有同样问题的人:我为我的案例找到了一个非常丑陋的解决方案:

import javax.net.SocketFactory;

public abstract class ThreadLocalSocketFactory
  extends SocketFactory
{

  static ThreadLocal<SocketFactory> local = new ThreadLocal<SocketFactory>();

  public static SocketFactory getDefault()
  {
    SocketFactory result = local.get();
    if ( result == null )
      throw new IllegalStateException();
    return result;
  }

  public static void set( SocketFactory factory )
  {
    local.set( factory );
  }

  public static void remove()
  {
    local.remove();
  }

}

像这样使用它:

env.put( "java.naming.ldap.factory.socket", ThreadLocalSocketFactory.class.getName() );
ThreadLocalSocketFactory.set( sslContext.getSocketFactory() );
try {
  ctx = new InitialLdapContext( env, null );
} finally {
  ThreadLocalSocketFactory.remove();
}

不太好,但它有效。 JNDI 应该在这里更灵活...

关于java - jndi LDAPS 自定义 HostnameVerifier 和 TrustManager,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9394864/

相关文章:

java - 如何根据用户输入使用 for 循环从数组打印字符串

java - 使用 java 客户端上传 Azure Web 作业

ssl - 如何在 WebSphere Liberty 8.5.5.6 中启用 TLSv1.2?

powershell - 如何根据组扩展属性获取用户所属的所有组

active-directory - LDAP 查询以列出用户所属的所有组?

java - 如何在 Java 中对 Exchange Web 服务连接使用 LDAP 身份验证?

java - 将嵌入式插件 jar 文件添加到项目中

java - 如何在Grails编译中解决NoClassDefFoundError?

java - 从 Weblogic 服务器到 IIS SSL 服务的 x509 客户端身份验证(无法加载服务器信任的 CA java.lang.NullPointerException)

ruby-on-rails - 在 Heroku 上使用 Thin 和 SSL 的 Rails 应用程序(Procfile)