jndi LDAPS定制HostnameVerifier和TrustManager [英] jndi LDAPS custom HostnameVerifier and TrustManager

查看:262
本文介绍了jndi LDAPS定制HostnameVerifier和TrustManager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We are writing an application that shall connect to different LDAP servers. For each server we may only accept a certain certificate. The hostname in that certificate shall not matter. This is easy, when we use LDAP and STARTTLS, because we can use StartTlsResponse.setHostnameVerifier(..-) and use StartTlsResponse.negotiate(...) with a matching SSLSocketFactory. However we also need to support LDAPS connections. Java supports this natively, but only if the server certificate is trusted by the default java keystore. While we could replace that, we still cannot use different keystores for different servers.

现有的连接代码如下:

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,但是如何传递信息呢?

We could add out own CustomSocketFactory, but how to pass information to that?

推荐答案

对于其他人也有同样的问题:我发现了一个非常丑陋的解决方案:

For others have the same problem: I found a very ugly solution for my case:

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在这里应该更加灵活...

Not nice, but it works. JNDI should be more flexible here...

这篇关于jndi LDAPS定制HostnameVerifier和TrustManager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆