簡體   English   中英

來自Java JNDI連接的LDAP錯誤49

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM