[英]LDAP Error 49 from Java JNDI Connection
*在完整的解決方案下檢查答案*
我被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)中使用了相同的組合,它的工作原理很吸引人。 但是,出於上帝的考慮,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”和密碼對每個應用程序進行身份驗證。 我現在沒有選擇了。 誰能幫我?
我很高興為所有發表評論的人提供幫助。 沒有您的幫助,我將陷於困境。 我發現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 ... 通過這兩個類,我能夠解決我所有的 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;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.