web-dev-qa-db-ja.com

JNDI / LDAP接続の自己署名証明書を受け入れる方法は?

SSL経由でLDAPディレクトリに接続する必要があります。

非実稼働環境では、自己署名証明書を使用しますが、もちろん、次の方法では検証できません。

javax.naming.CommunicationException: simple bind failed: ldapserver:636 [Root exception is javax.net.ssl.SSLHandshakeException: Sun.security.validator.ValidatorException: PKIX path building failed: Sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target]
 at com.Sun.jndi.ldap.LdapClient.authenticate(LdapClient.Java:197)
 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.ldap.InitialLdapContext.<init>(InitialLdapContext.Java:134)

SSL対応接続用のカスタムトラストマネージャー の使用方法は知っていますが、実際の接続を管理していないJNDIAPIに関連して使用する方法がわかりません。つまり、次の標準設定はどこでトラストマネージャーをプラグインできますか?

前もって感謝します。

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.Sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldaps://ldapserver:636");
env.put(Context.SECURITY_PROTOCOL, "ssl");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "myUser");
env.put(Context.SECURITY_CREDENTIALS, "myPassword");
LdapContext ctx = new InitialLdapContext(env, null);
ctx.search (...)
14

JNDIのドキュメントによると、カスタムSSLSocketFactoryを設定することは可能のようです。

http://download.Oracle.com/javase/1.5.0/docs/guide/jndi/jndi-ldap-gl.html#socket

public class MySSLSocketFactory extends SocketFactory {
    private static final AtomicReference<MySSLSocketFactory> defaultFactory = new AtomicReference<>();

    private SSLSocketFactory sf;

    public MySSLSocketFactory() {
        KeyStore keyStore = ... /* Get a keystore containing the self-signed certificate) */
        TrustManagerFactory tmf = TrustManagerFactory.getInstance();
        tmf.init(keyStore);
        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(null, tmf.getTrustManagers(), null);
        sf = ctx.getSocketFactory();
    }

    public static SocketFactory getDefault() {
        final MySSLSocketFactory value = defaultFactory.get();
        if (value == null) {
            defaultFactory.compareAndSet(null, new MySSLSocketFactory());
            return defaultFactory.get();
        }
        return value;
    }

    @Override
    public Socket createSocket(final String s, final int i) throws IOException {
        return sf.createSocket(s, i);
    }

    @Override
    public Socket createSocket(final String s, final int i, final InetAddress inetAddress, final int i1) throws IOException {
        return sf.createSocket(s, i, inetAddress, i1);
    }

    @Override
    public Socket createSocket(final InetAddress inetAddress, final int i) throws IOException {
        return sf.createSocket(inetAddress, i);
    }

    @Override
    public Socket createSocket(final InetAddress inetAddress, final int i, final InetAddress inetAddress1, final int i1) throws IOException {
        return sf.createSocket(inetAddress, i, inetAddress1, i1);
    }
}

このソケットファクトリを使用するように環境を構成します

env.put("Java.naming.ldap.factory.socket", "com.example.MySSLSocketFactory");
22
Jcs

Trustmanagerをオーバーライドすると、任意の証明書を受け入れることができます。

DummyTrustmanager.Java

public class DummyTrustmanager implements X509TrustManager {
    public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
        // do nothing
    }

    public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
        // do nothing
    }

    public X509Certificate[] getAcceptedIssuers() {
        return new Java.security.cert.X509Certificate[0];
    }
}

MySSLSocketFactory.Java

public class MySSLSocketFactory extends SSLSocketFactory {
    private SSLSocketFactory socketFactory;

    public MySSLSocketFactory() {
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, new TrustManager[] { new DummyTrustmanager() }, new SecureRandom());
            socketFactory = ctx.getSocketFactory();
        } catch (Exception ex) {
            ex.printStackTrace(System.err);
            /* handle exception */
        }
    }

    public static SocketFactory getDefault() {
        return new MySSLSocketFactory();
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return socketFactory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return socketFactory.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket socket, String string, int i, boolean bln) throws IOException {
        return socketFactory.createSocket(socket, string, i, bln);
    }

    @Override
    public Socket createSocket(String string, int i) throws IOException, UnknownHostException {
        return socketFactory.createSocket(string, i);
    }

    @Override
    public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException, UnknownHostException {
        return socketFactory.createSocket(string, i, ia, i1);
    }

    @Override
    public Socket createSocket(InetAddress ia, int i) throws IOException {
        return socketFactory.createSocket(ia, i);
    }

    @Override
    public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException {
        return socketFactory.createSocket(ia, i, ia1, i1);
    }
}

Main.Java

public class Main {
    public static void main(String[] args) throws NamingException {
        Hashtable env = new Hashtable(11);
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.Sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, "ldaps://ldapserver:636/");
        env.put(Context.SECURITY_PROTOCOL, "ssl");
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, "myUser");
        env.put(Context.SECURITY_CREDENTIALS, "myPassword");
        env.put("Java.naming.ldap.factory.socket", "ldapsecure.MySSLSocketFactory");
        LdapContext ctx = new InitialLdapContext(env, null);
    }
}
10
sdorra

コードは必要ありません。証明書をテストクライアントのトラストストアに追加するだけです。

このために余分なコードを書かないでください。これは安全ではなく、コードが本番環境にリークするという大きなリスクがあります。あなたは本当にそれを望んでいません。

3
user207421

@Jcsの答えは正しいですが、カスタムTrustManagerを使用したくない場合、およびその特定の自己署名証明書をVM内の他の用途の信頼できるCAにする場合は、次のいずれかを実行できます。

  • この証明書をデフォルトのトラストストア(通常はJREセキュリティディレクトリの下のcacerts)に追加するか、
  • その特定の証明書を含む別の場所(おそらくデフォルトのcacertsのコピーに基づく)に新しいトラストストアを作成し、これをデフォルトのトラストストアとして使用しますが、javax.net.ssl.trustStore*システムプロパティを設定します。
2
Bruno

私が最後にこれを行ってから約5年が経ちましたので、私の答えは少し曖昧になります。しかし、Java.securityで信頼できるプロバイダーを暗示する場合は、/ usr/Java/jre/lib/security /の下にあるはずです。その後、証明書を信頼できるものとして受け入れます。

現時点ではメモにアクセスできませんが、後でメモを掘り下げます

1
Ben__H

JNDIを完全に脇に置いて、someフレームワークはLOCAL SYSTEM LDAP構成を参照します(これは通常/etc/ldap.confなどです)。 LOCALとは、JNDI操作が実行されているシステムを意味します。

少なくともほとんどのLDAP対応LinuxOSの場合、そのようなLDAP構成ファイルの内部には(通常)次のような行があります。

TLS_REQCERT demand

これは、デフォルトのTLS/SSL重要度設定(および最も厳密な設定)です。証明書に問題がある場合(自己署名を含む)、接続が失敗するためです。

'demand'の代わりにさまざまな設定を試すことができます( 'allow'または 'never'で遊んでください)。これが完了したら、操作を再試行して、問題が解決するかどうかを確認します。繰り返しますが、このようなすべてのものがローカルシステム設定を読み取ったり検出したりするわけではありません。する人もいれば、しない人もいます。一見の価値があります。

これがお役に立てば幸いです...

マックス

0
maximum ldap