java 连接 ldap 报错

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 连接 ldap 报错相关的知识,希望对你有一定的参考价值。

这个项目要求验证域用户,我就是用连接ldap来验证,但是总是报错
LDAP:error code 49 - 80090308: DSID - 0C0903AA,comment: AcceptSecuritycontext error ,data 525,v1772
我的代码如下:
String BASEDN = "dc=combatelecom,dc=com";
Hashtable env = new Hashtable();env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");env.put(Context.PROVIDER_URL,"ldap://10.10.0.13:389/"+BASEDN);env.put(Context.SECURITY_AUTHENTICATION,"simple");env.put(Context.SECURITY_PRINCIPAL,"cn=" + username);//1env.put(Context.SECURITY_CREDENTIALS,password);//2DirContext ctx = new InitialDirContext(env);如果屏蔽1和2两行就能连接成功,但是一带上我自己的账号和密码就报错求大神解救我啊!!!!!!!!!!!!

应该是用户名写的不对,env.put(Context.SECURITY_PRINCIPAL,"cn=" + username);
这里面应该写用户的全路径名,比如cn=xxxxx,dc=combatelecom,dc=com
说白了就是你怎么从根节点找到的用户,把用户节点的dn拷贝出来就行了
另外那个URL部分写成env.put(Context.PROVIDER_URL,"ldap://10.10.0.13:389")追问

这些都试过
不行的

参考技术A 个人意见,不一定正确,互相研究一下。
感谢这一行写的不对
env.put(Context.PROVIDER_URL,"ldap://10.10.0.13:389/"+BASEDN)

应该env.put(Context.PROVIDER_URL,"ldap://10.10.0.13:389/")
至于BASEDN写到哪里暂不是很清楚,但觉得不应该跟URL写在一起。追问

不行的,带不带BASEDN都不行,匿名创建InitialDirContext(env)是可以的
一旦戴上账号和密码就报账号或密码错误
不知道是否是账号或密码要经过处理才行

参考技术B 那就是用户的dn写得不正确,或用户名、密码写得不对。

根据你的实际环境,写正确的就好了追问

DN在匿名登录时是成功的
用户名和密码保证是正确的
是不是其他问题?

追答

username 怎么写的,有BASEDN吗,如果没有添加试试。

追问

username是直接的用户名,username+","+BASEDN这样也试过,不行

有没有办法连接 ldaps 并忽略 java 中的证书?

【中文标题】有没有办法连接 ldaps 并忽略 java 中的证书?【英文标题】:is there a way to connect with ldaps and ignore certificates in java? 【发布时间】:2020-12-28 19:42:00 【问题描述】:

我在 tomcat 上有一个带有 ldap 的应用程序 java,我可以毫无问题地进行身份验证。现在,我的公司要在 ldap 上插入 ssl 层,所以我需要使用 ldaps。有什么建议可以忽略来自 ldaps 服务器的证书和信任证书?

这是我的适用于 ldap 的代码

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

//need a default user to be able to do query on 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);

//ensures that objectSID attribute values
//will be returned as a byte[] instead of a 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());

  // 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);
 


所以我决定用这个来改变我以前的 ldap 代码:

public LdapContext getLDAPContext() throws NamingException

    SSLFix.execute();
    
    
    final String ldapAdServer = "ldaps://my_ldap_url:3269";
    final String ldapSearchBase = "ldap_search_base";
    
//need a default user to be able to do query on 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);

    //ensures that objectSID attribute values
    //will be returned as a byte[] instead of a String
    env.put("java.naming.ldap.attributes.binary", "objectSID");
    
    LdapContext ctx = new InitialLdapContext(env,null);
    
    return ctx;

但是当我为 ldaps 执行控制时,我得到这个错误:

javax.naming.CommunicationException:简单绑定失败:[根异常是 javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX 路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效认证路径]

【问题讨论】:

如果您的公司想要 SSL,大概他们希望它是安全的,而您所要求的会破坏它。如果 LDAP 服务器有 CA 签名的证书,您就没有问题要解决,如果您确实有问题,可以解决 CA 签名的证书。 【参考方案1】:

您必须将“LDAP-CA 证书”导入您的 Java 虚拟机。 为此,您可以运行:keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -alias ldap-CA -import -file ldap-ca-crt.pem

如果你的证书是好的。您的所有客户端(网络浏览器或移动 SO)在使用您的应用程序时都不会出现问题。

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

【讨论】:

你只需要导入链中最顶层的证书,而不是整个链。【参考方案2】:

我不知道你的环境,但是你可以添加我不知道你的环境,但是你可以将已经发布了 LDAP 证书的 CA 证书添加到你系统的受信任的 CA 中吗?

通过这种方式,您可以增强应用程序的安全性,否则使用 LDAP 几乎没有用处。

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

如果应用安装在域的计算机上,您可以共享 CA 证书并抛出组策略规则。你可以看到the Microsoft documentation。域中的每个证书都必须由受信任的 CA 发布。

如果您不能接受此证书,请使用answer 中的选项 2。

【讨论】:

【参考方案3】:

感谢大家的回复。我决定创建 X509TrustManager 和 SSLSocketFactory,因此允许所有证书。我以这种方式解决了我的问题

【讨论】:

【参考方案4】:

您可以创建自定义 X509TrustManager 或 SSLSocketFactory。

在https://***.com/a/4615497/88122找到这两个例子

【讨论】:

以上是关于java 连接 ldap 报错的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法连接 ldaps 并忽略 java 中的证书?

通过 Java 到 LDAP 的 SSL 连接 [重复]

Java Ldap单点登录,如何获取Ldap server的证书

在Linux上的备用连接上抛出SunCertPathBuilderException的LDAP连接

JAVA连接LDAP(Windows AD)验证时,密码为空验证通过的问题?

LDAP在JAVA中如何模糊查询