*使用完整的工作解决方案检查以下答案
我因Java LDAP连接问题而陷入困境。
这是我连接LDAP服务器的方法:
public boolean authenticate(String user, String password) {
StringBuilder url = new StringBuilder("ldap://");
url.append("10.0.0.1");
url.append(":");
url.append(389);
StringBuilder securityPrincipal = new StringBuilder("uid=");
securityPrincipal.append(user);
securityPrincipal.append(",");
securityPrincipal.append("dc=XXXXX,dc=YYY,dc=ZZ");
Hashtable<String, String> env;
env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url.toString());
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, securityPrincipal.toString());
env.put(Context.SECURITY_CREDENTIALS, password);
System.out.println(url);
System.out.println(securityPrincipal.toString());
try {
ldap = new InitialLdapContext(env, null);
} catch (NamingException e) {
e.printStackTrace();
return false;
}
return true;
}
出于安全和公开原因,我为XXXXX,YYY和ZZ省略了“dc”并更改了LDAP服务器的IP。
我在PHP软件(GLPI)中使用了相同的组合,它就像一个魅力。但是,为了GOD的缘故,Java无法接受这个LDAP配置,总是给我这个错误:
javax.naming.AuthenticationException: [LDAP: error code 49 - Invalid Credentials]
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(Unknown Source)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(Unknown Source)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(Unknown Source)
完整的dn就是这样:
uid=tiagoadami,dc=XXXXX,dc=YYY,dc=ZZ
变量用户填充“tiagoadami”,变量“argument”填充纯文本密码。
这很烦人。我的密码是正确的,我正在使用用户名“tiagoadami”和密码对每个应用程序进行身份验证。我现在没有选择了。任何人都可以帮助我吗?
答案 0 :(得分:0)
我很高兴得到所有评论的人的帮助。没有你的帮助,我会被困住。我发现LDAP服务器不允许仅与基本DN绑定。
在绝望的尝试之后,我可以使用树的完整路径进行连接:
uid=tiagoadami,ou=proto,ou=serv,ou=user,ou=collab,ou=all,dc=XXXXX,dc=YYY,dc=ZZ
而不是:
uid=tiagoadami,dc=XXXXX,dc=YYY,dc=ZZ
Sooooooooo looooooooong ... 这两个类我能够解决 ALL 我的LDAP问题。我将它们更改为在树内搜索并获得给定UID的完整DN。在这里,他们适合任何有同样问题的人:
<强> TrustAllCertificatesSSLSocketFactory.java 强>
package com.adamiworks.commonutils.ldap;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* This class accept all SSL Certificates even if it can assure its
* Certification Institute.
*
* DO NOT USE AT PRODUCTION ENVIRONMENTS
*
* @author Tiago J. Adami
*
*/
public class TrustAllCertificatesSSLSocketFactory extends SocketFactory {
private SocketFactory socketFactory;
public TrustAllCertificatesSSLSocketFactory() {
try {
SSLContext ctx = SSLContext.getInstance("SSL");
ctx.init(null, new TrustManager[] { new AllCertificatesTrustManager() }, new SecureRandom());
socketFactory = ctx.getSocketFactory();
} catch (Exception ex) {
ex.printStackTrace(System.err); /* handle exception */
}
}
public static SocketFactory getDefault() {
return new TrustAllCertificatesSSLSocketFactory();
}
@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);
}
private class AllCertificatesTrustManager 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];
}
}
}
<强> LdapUtils.java 强>
package com.adamiworks.commonutils.ldap;
import java.util.Hashtable;
import java.util.Properties;
import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
/**
* Authenticates with LDAP Servers. Just using a single UID this class goes deep
* inside the user's tree and find the full DN for the given UID. It also allows
* to connect to servers when you don't have the certificate yet... but use this
* feature at your own risk!
*
* @author Tiago J. Adami
*
*/
public class LdapUtils {
private InitialDirContext ldap;
private String host;
private int port;
private boolean useSSL;
private boolean ignoreCertificates;
private String basedn;
public InitialDirContext getLdap() {
return ldap;
}
public boolean isIgnoreCertificates() {
return ignoreCertificates;
}
public void setIgnoreCertificates(boolean ignoreCertificates) {
this.ignoreCertificates = ignoreCertificates;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public String getBasedn() {
return basedn;
}
public boolean isUseSSL() {
return useSSL;
}
public void setUseSSL(boolean useSSL) {
this.useSSL = useSSL;
}
/**
* Default constructor
*
* @param host
* @param port
* @param basedn
* @param useSSL
* @param ignoreCertificates
*/
public LdapUtils(String host, int port, String basedn, boolean useSSL, boolean ignoreCertificates) {
super();
this.host = host;
this.port = port;
this.useSSL = useSSL;
this.basedn = basedn;
this.ignoreCertificates = ignoreCertificates;
}
/**
* Authenticates an user and password from LDAP credentials;
*
* @param uid
* @param password
* @return
* @throws NamingException
*/
public boolean authenticate(String uid, String password) {
try {
String url = getUrl();
String dn = this.getDnByUid(uid);
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, dn);
env.put(Context.SECURITY_CREDENTIALS, password);
if (this.useSSL) {
env.put(Context.SECURITY_PROTOCOL, "ssl");
}
if (this.useSSL && this.ignoreCertificates) {
env.put("java.naming.ldap.factory.socket", "com.adamiworks.commonutils.ldap.TrustAllCertificatesSSLSocketFactory");
}
ldap = new InitialDirContext(env);
} catch (AuthenticationException e) {
e.printStackTrace();
return false;
} catch (NamingException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* Returns the url based on SSL or not
*
* @return
*/
private String getUrl() {
StringBuilder url = new StringBuilder();
url.append(this.useSSL ? "ldaps://" : "ldap://");
url.append(host);
url.append(":");
url.append(port);
return url.toString();
}
/**
* Returns the url based on SSL or not
*
* @return
*/
private String getUrlWithoutSsl() {
StringBuilder url = new StringBuilder();
url.append("ldap://");
url.append(host);
return url.toString();
}
/**
* Return LDAP authentication modes allowed by the server
*
* @param url
* @return
* @throws NamingException
*/
public Attributes getLdapAuths() throws NamingException {
// Create initial context
DirContext ctx = new InitialDirContext();
// Read supportedSASLMechanisms from root DSE
Attributes attrs = ctx.getAttributes(this.getUrl(), new String[] { "supportedSASLMechanisms" });
System.out.println(attrs);
return attrs;
}
/**
* Returns the full DN (distinct name) for a given UID
*
* @param uid
* the UID name of the user
* @return full tree path of LDAP
* @throws NamingException
*/
@SuppressWarnings("rawtypes")
public String getDnByUid(String uid) throws NamingException {
String url = this.getUrlWithoutSsl() + "/" + this.basedn;
Hashtable<String, Object> env = new Hashtable<String, Object>(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url);
String ret = "uid=" + uid;
DirContext ctx = null;
try {
// Create initial context
ctx = new InitialDirContext(env);
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration answer = ctx.search("", "(uid=" + uid + ")", controls);
while (answer.hasMore()) {
SearchResult sr = (SearchResult) answer.next();
ret = sr.getNameInNamespace();
break;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// Close the context when we're done
ctx.close();
}
System.out.println("FULL DN: " + ret);
return ret;
}
}