2012-02-22 10 views
3

我々は異なるLDAPサーバーに接続しなければならないアプリケーションを書いています。各サーバーについて、特定の証明書のみを受け入れることができます。その証明書のホスト名は重要ではありません。 StartTlsResponse.setHostnameVerifier(..-)を使用し、と一致するStartTlsResponse.negotiate(...)を使用できるため、LDAPとSTARTTLSを使用すると簡単です。しかし、LDAPS接続もサポートする必要があります。 Javaはこれをネイティブにサポートしていますが、サーバー証明書がデフォルトのJavaキーストアによって信頼されている場合のみです。これを置き換えることはできますが、サーバーごとに異なるキーストアを使用することはできません。JNDI LDAPSカスタムのHostnameVerifierとのTrustManager

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を追加することもできますが、どのように情報を渡すために、次のよう

既存の接続コードはありますか?

答えて

3

は同じ問題を抱えている。このようにそれを使用して

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は、私は上記の私のリストにこのコード行を持って

+0

...についての一票を心配するつもりはありませんあなたが書いたことが間違っているとは決して言わなかった。ちょうどその情報が私の質問ですでに言及されていて、決してその質問を解決するのに全く役立たなかった。だから私は落ち込んだ。それがダウン投票の正当な理由でないなら、私はそのダウンワードを削除しますが、EJPのupvote(これは私のdownvoteをクリアする唯一の手段です)は残っていて無駄な答えを投票するので、私はしません。 – Bruno

+0

...だから基本的に、あなたはあなたがdownvotedてきたと述べてきた私の答え、の継続中に右であるあなた自身の答えを生産してきた –

+0

私が言ったように、編集する前に十分に公正ですが、OpenJDKコードの理由を示す答えを得ると、静的メンバー(これまで行っていたもの)やJDNIなどを使用しない限り、それはあなたの質問に対する答えの点だと思います。そして、自分の答えを受け入れました。これは、私が提案した線に沿ってはっきりとしていました。私はdownvoteについてはあまり気にしませんし、あなた自身の答えを受け入れたという事実は気にしません(あなたが 'ThreadLocal'でより具体的だからです)。私はちょうどdownvoting + downvoted答え奇妙から派生した自分の答えを受け入れるを見つける。 – Bruno

1

あなたは自分のSSLSocketFactoryサブクラスの名前を渡し、"Using Custom Sockets" section of the Java LDAP/SSL guideで説明したように、"java.naming.ldap.factory.socket"のenvプロパティに名前の完全修飾を渡す必要があります。

env.put("java.naming.ldap.factory.socket", "example.CustomSocketFactory"); 

あなたはこのクラスに特定の引数を渡すことはできません、 com.sun.jndi.ldap.Connection.createSocket(...)でインスタンス化を参照してください。

Class socketFactoryClass = Obj.helper.loadClass(socketFactory); 
Method getDefault = 
    socketFactoryClass.getMethod("getDefault", new Class[]{}); 
Object factory = getDefault.invoke(null, new Object[]{}); 

あなたは追加のパラメータが必要な場合、あなたは(通常は理想的な)おそらく静的メンバまたはJNDIを使用する必要があります。

私の知る限り、残念ながら、この実装でldaps://を使用するときに任意のホスト名の検証があるようには思えません。あなたがトラストマネージャー内の1つの明示的な証明書だけを信頼する場合、これはとにかくホスト名検証の欠如を補うものでなければなりません。他人のために

+0

...ここでは、より柔軟であるべきです。しかし、クラス名を指定できるのは特定のインスタンスではないため、そのクラスに引数を渡すことはできません。これが私の必要です。あなたはその質問を読んだのですか?もしそうなら、私はどこでより詳細にすべきか教えてください。 –

+0

@SteffenHeil、申し訳ありませんが、私はあまりにも早く答えました、私は詳細を追加しました。 – Bruno

+0

Upvoted原因不明のdownvote – EJP