有没有一种方法在Java中连接LDAPS并忽略证书?

huangapple go评论89阅读模式
英文:

is there a way to connect with ldaps and ignore certificates in java?

问题

以下是翻译好的内容:

我有一个部署在Tomcat上的Java应用程序使用LDAP进行身份验证目前可以正常进行身份验证现在我的公司希望在LDAP上插入SSL层因此我需要使用LDAPS有没有建议可以忽略证书并信任LDAPS服务器的证书

这是我的用于LDAP的代码

final String ldapAdServer = "ldap://my_ldap_url:3268";
final String ldapSearchBase = "Ldap_search_base";

// 需要一个默认用户来能够在AD上执行查询
final String ldapUsername = "username_path_AD";
final String ldapPassword = "password_path_AD";

Hashtable<String, Object> env = new Hashtable<String, Object>();
env.put(Context.SECURITY_AUTHENTICATION, "simple");
if (ldapUsername != null) {
    env.put(Context.SECURITY_PRINCIPAL, ldapUsername);
}
if (ldapPassword != null) {
    env.put(Context.SECURITY_CREDENTIALS, ldapPassword);
}
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapAdServer);

// 确保objectSID属性值将作为byte[]而不是String返回
env.put("java.naming.ldap.attributes.binary", "objectSID");

LdapContext ctx = new InitialLdapContext(env, null);

return ctx;

现在,我尝试创建这个类来信任所有证书:

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class SSLFix {

    public static void execute() {
        TrustManager[] trustAllCerts = new TrustManager[] {
            new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                @Override
                public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                        throws CertificateException {}

                @Override
                public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                        throws CertificateException {}
            }
        };

        SSLContext sc = null;
        try {
            sc = SSLContext.getInstance("SSL");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        try {
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

        // 创建信任所有主机名的HostNameVerifier
        HostnameVerifier validHosts = new HostnameVerifier() {
            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        };
        // 所有主机将被视为有效
        HttpsURLConnection.setDefaultHostnameVerifier(validHosts);
    }
}

因此,我决定使用这个更改过的LDAP代码:

public LdapContext getLDAPContext() throws NamingException {
    SSLFix.execute();

    final String ldapAdServer = "ldaps://my_ldap_url:3269";
    final String ldapSearchBase = "ldap_search_base";

    // 需要一个默认用户来能够在AD上执行查询
    final String ldapUsername = "username_path_AD";
    final String ldapPassword = "password_path_AD";

    Hashtable<String, Object> env = new Hashtable<String, Object>();
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    if (ldapUsername != null) {
        env.put(Context.SECURITY_PRINCIPAL, ldapUsername);
    }
    if (ldapPassword != null) {
        env.put(Context.SECURITY_CREDENTIALS, ldapPassword);
    }
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, ldapAdServer);

    // 确保objectSID属性值将作为byte[]而不是String返回
    env.put("java.naming.ldap.attributes.binary", "objectSID");

    LdapContext ctx = new InitialLdapContext(env, null);

    return ctx;
}

但是当我执行LDAPS的控制时,我获得了以下错误:

javax.naming.CommunicationException: simple bind failed:  [根本异常为 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]
英文:

I have an application java on tomcat with ldap and I can authenticate without problem. Now, my company would to insert ssl layer on ldap, so I need to use ldaps. Any suggestion to ignore certificate and trust certificate from ldaps server?

This is my code that works for ldap

final String ldapAdServer = &quot;ldap://my_ldap_url:3268&quot;;
final String ldapSearchBase = &quot;Ldap_search_base&quot;;
//need a default user to be able to do query on AD
final String ldapUsername = &quot;username_path_AD&quot;;
final String ldapPassword = &quot;password_path_AD&quot;;
Hashtable&lt;String, Object&gt; env = new Hashtable&lt;String, Object&gt;();
env.put(Context.SECURITY_AUTHENTICATION, &quot;simple&quot;);
if(ldapUsername != null) {
env.put(Context.SECURITY_PRINCIPAL, ldapUsername);
}
if(ldapPassword != null) {
env.put(Context.SECURITY_CREDENTIALS, ldapPassword);
}
env.put(Context.INITIAL_CONTEXT_FACTORY, &quot;com.sun.jndi.ldap.LdapCtxFactory&quot;);
env.put(Context.PROVIDER_URL, ldapAdServer);
//ensures that objectSID attribute values
//will be returned as a byte[] instead of a String
env.put(&quot;java.naming.ldap.attributes.binary&quot;, &quot;objectSID&quot;);
LdapContext ctx = new InitialLdapContext(env,null);
return ctx;

now, I tried to create this class to trust all certificates :

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SSLFix {
public static void execute(){
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {}
}
};
SSLContext sc=null;
try {
sc = SSLContext.getInstance(&quot;SSL&quot;);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
try {
sc.init(null, trustAllCerts, new java.security.SecureRandom());
} catch (KeyManagementException e) {
e.printStackTrace();
}
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier validHosts = new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
};
// All hosts will be valid
HttpsURLConnection.setDefaultHostnameVerifier(validHosts);
}
}

and so I decided to change my previous ldap code with this:

public LdapContext getLDAPContext() throws NamingException
{
SSLFix.execute();
final String ldapAdServer = &quot;ldaps://my_ldap_url:3269&quot;;
final String ldapSearchBase = &quot;ldap_search_base&quot;;
//need a default user to be able to do query on AD
final String ldapUsername = &quot;username_path_AD&quot;;
final String ldapPassword = &quot;password_path_AD&quot;;
Hashtable&lt;String, Object&gt; env = new Hashtable&lt;String, Object&gt;();
env.put(Context.SECURITY_AUTHENTICATION, &quot;simple&quot;);
if(ldapUsername != null) {
env.put(Context.SECURITY_PRINCIPAL, ldapUsername);
}
if(ldapPassword != null) {
env.put(Context.SECURITY_CREDENTIALS, ldapPassword);
}
env.put(Context.INITIAL_CONTEXT_FACTORY, &quot;com.sun.jndi.ldap.LdapCtxFactory&quot;);
env.put(Context.PROVIDER_URL, ldapAdServer);
//ensures that objectSID attribute values
//will be returned as a byte[] instead of a String
env.put(&quot;java.naming.ldap.attributes.binary&quot;, &quot;objectSID&quot;);
LdapContext ctx = new InitialLdapContext(env,null);
return ctx;
}

but when I execute the control for ldaps, I obtain this error:

javax.naming.CommunicationException: simple bind failed: [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]

答案1

得分: 4

你必须将“LDAP-CA证书”导入你的Java虚拟机中。要做到这一点,你可以运行:

keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -alias ldap-CA -import -file ldap-ca-crt.pem

如果你的证书有效。所有的客户端(包括Web浏览器或移动操作系统)在使用你的应用时将不会有任何问题。

不要忘记导入你的中间证书或链式证书。(这些证书通常与LDAP-CA证书一起提供)。

英文:

You must import the "LDAP-CA certificate" into your Java virtual machine.<br>
To do this, you can run:<br>
<b>keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -alias ldap-CA -import -file ldap-ca-crt.pem</b>

If your certificate is good. All your clients (web browsers or mobile SO) will have no problem using your application.

Don't forget to import your intermediate certificates or chained certificates.(these certificates usually come together with LDAP-CA certificate)
</pre>

答案2

得分: 0

你可以创建一个自定义的X509TrustManager或SSLSocketFactory。

在https://stackoverflow.com/a/4615497/88122上找到了两者的示例。

英文:

You can create a custom X509TrustManager or SSLSocketFactory.

Found examples of both at https://stackoverflow.com/a/4615497/88122

答案3

得分: 0

我不知道你的环境,但你能否将发布LDAP证书的CA证书添加到系统的受信任CA中呢?

这样可以增强应用程序的安全性,否则使用LDAPs几乎没有任何用处。

我假设域控制器安装了一个CA服务器,LDAP的证书是由它发布的。下载该证书并将其添加到你的环境中。

如果应用程序安装在域计算机上,你可以通过组策略规则共享CA证书。你可以参考微软文档。域中的每个证书必须由受信任的CA发布。

如果你无法接受该证书,请参考这个答案中的选项2。

英文:

I don't know your environment, but can you add the CA certificate that has released the LDAP certificate to your system's trusted CAs?

In this way, you enhance the app security, otherwise is almost useless to use LDAPs.

I suppose that the Domain Controller has a CA server installed and the LDAP's certificate is released by it. Download this certificate and add it to you environment.

If the app is installed on domain's computers, you can share the CA certificate throw a group policy rule. You can see the Microsoft documentation. Each certificate in a domain must be released by a trusted CA.

If you can't accept this certificate use the option 2 from this answer.

答案4

得分: 0

谢谢大家的回应。我决定创建X509TrustManager和SSLSocketFactory,从而允许所有证书。我通过这种方式解决了我的问题。

英文:

thanks all for your response. I decided to create X509TrustManager and SSLSocketFactory, and so allow all certificates. I solved my issue in this way

huangapple
  • 本文由 发表于 2020年9月10日 18:12:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/63827473.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定