LDAP:如何使用连接详细信息进行用户身份验证

10

我无法通过LDAP验证用户。我有以下细节:

URL=ldap://10.10.10.10:389 
LDAP BASE:DC=lab2,DC=ins 
LDAP Bind Account: CN=Ldap Bind,OU=Service Accounts,OU=TECH,DC=lab2,DC=ins 
LDAP Bind Account Pw: secret 
我可以使用上述详细信息搜索值,但如何使用用户名和密码验证用户?
如果您遵循我的先前问题,那么您将了解我成功连接到LDAP服务器,但无法对其进行身份验证。
要进行身份验证的用户:
user: someusername
password: somepwd

我无法使用密码 'somepwd' 连接到 LDAP 服务器,而且我应该如何使用 someusername。我能够使用 sAMAccountName 搜索给定的用户。


1
你是否有正确的密码?它是否能在像JXplorer这样的客户端上工作? - dbrin
@DmitryB 我能用 'secret' 连接到服务器,但不能用 'somepwd' 连接。 - Himanshu Yadav
那么在哪里以及如何使用给定的输入用户密码?在这种情况下是“somepwd”。 - Himanshu Yadav
如果我理解你的问题,你想使用LdapTemplate.authenticate()。或者你的问题是首先创建LDAP上下文吗? - jiggy
4个回答

24

这是我从各个地方找到的东西的混合体。如果您不想使用UnboundID SDK,它应该可以让您走上正确的道路。这不是生产质量,如果您的商店支持SSL,请在此处添加SSL内容。

public static Boolean validateLogin(String userName, String userPassword) {
    Hashtable<String, String> env = new Hashtable<String, String>();


    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, "ldap://" + LDAP_SERVER + ":" + LDAP_SERVER_PORT + "/" + LDAP_BASE_DN);

    // To get rid of the PartialResultException when using Active Directory
    env.put(Context.REFERRAL, "follow");

    // Needed for the Bind (User Authorized to Query the LDAP server) 
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    env.put(Context.SECURITY_PRINCIPAL, LDAP_BIND_DN);
    env.put(Context.SECURITY_CREDENTIALS, LDAP_BIND_PASSWORD);

    DirContext ctx;
    try {
       ctx = new InitialDirContext(env);
    } catch (NamingException e) {
       throw new RuntimeException(e);
    }

    NamingEnumeration<SearchResult> results = null;

    try {
       SearchControls controls = new SearchControls();
       controls.setSearchScope(SearchControls.SUBTREE_SCOPE); // Search Entire Subtree
       controls.setCountLimit(1);   //Sets the maximum number of entries to be returned as a result of the search
       controls.setTimeLimit(5000); // Sets the time limit of these SearchControls in milliseconds

       String searchString = "(&(objectCategory=user)(sAMAccountName=" + userName + "))";

       results = ctx.search("", searchString, controls);

       if (results.hasMore()) {

           SearchResult result = (SearchResult) results.next();
           Attributes attrs = result.getAttributes();
           Attribute dnAttr = attrs.get("distinguishedName");
           String dn = (String) dnAttr.get();

           // User Exists, Validate the Password

           env.put(Context.SECURITY_PRINCIPAL, dn);
           env.put(Context.SECURITY_CREDENTIALS, userPassword);

           new InitialDirContext(env); // Exception will be thrown on Invalid case
           return true;
       } 
       else 
           return false;

    } catch (AuthenticationException e) { // Invalid Login

        return false;
    } catch (NameNotFoundException e) { // The base context was not found.

        return false;
    } catch (SizeLimitExceededException e) {
        throw new RuntimeException("LDAP Query Limit Exceeded, adjust the query to bring back less records", e);
    } catch (NamingException e) {
       throw new RuntimeException(e);
    } finally {

       if (results != null) {
          try { results.close(); } catch (Exception e) { /* Do Nothing */ }
       }

       if (ctx != null) {
          try { ctx.close(); } catch (Exception e) { /* Do Nothing */ }
       }
    }
}

2
这是我目前看到的最佳解决方案,我特别在寻找绑定到LDAP服务器后对用户进行身份验证。 - likeToCode
这个在连接池中使用安全吗? - bdrx
这段代码很棒,帮了我很多忙。但需要注意的是,我们必须设置一个基本DN来进行搜索,将ctx.search的第一个参数从空字符串替换为我们的基本DN。我怀疑现在几乎所有的LDAP提供商都需要这样做,所以在使用这段代码时要注意这一点。 - Dave McGinnis

8

LDAP连接最初是匿名的。要更改连接的授权状态,请使用BIND请求。BIND请求有两种形式,即“简单”或“SASL”。 “简单”BIND请求需要一个可分辨名称和密码。BIND请求应通过安全连接传输,或者通过使用StartTLS扩展请求将非安全连接升级为安全连接。

使用UnboundID LDAP SDK:

// exception handling not shown
LDAPConnection ldapConnection = new LDAPConnection(hostname,port);
BindRequest bindRequest = new SimpleBindRequest(username,password);
BindResult bindResult = ldapConnection.bind(bindRequest);
if(bindResult.getResultCode().equals(ResultCode.SUCCESS)) {
   /// successful authentication
}
ldapConnection.close();

由于客户的限制,我无法使用UnboundID LDAP SDK。是否有其他方法可以实现它? - Himanshu Yadav
1
对于SimpleBindRequest的构造函数,您应该提供DN,而不是用户名。 - tharinduwijewardane

1

我们有几个JNDI示例可能会有所帮助。

BasicJNDISearch.java是最基本的示例,使用命令行输入。

public BasicJNDISearch(String[] args)
{
super();

try
{
    BasicJNDISearch.doBasicSearch(args);
}
catch (Exception ex)
{
    ex.printStackTrace();
}
}

/**
 * 
 * @param stid
 *            String - Standard ID (uid)
 * @throws Exception
 *             -
 */
public static void doBasicSearch(String[] args) throws Exception
{
System.out.println("Performing LDAP Search with:");
System.out.println("    ldapHostName = " + args[0]);
System.out.println("        ldapPort = " + args[1]);
System.out.println("          bindDn = " + args[2]);
System.out.println("       bindDnPwd = " + args[3]);
System.out.println("      searchBase = " + args[4]);
System.out.println("          filter = (" + args[5] + "=" + args[6] + ")");
System.out.println("          Scope: = SUBTREE_SCOPE");

DirContext ctx = getDirContext(args[0], args[1], args[2], args[3]);
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
// ignore attribute name case
// matchAttrs.put(new BasicAttribute(args[5], args[6]));
String filter = "(" + args[5] + "=" + args[6] + ")";
// Search for objects with those matching attributes
NamingEnumeration<?> answer = ctx.search(args[4], filter, constraints);
formatResults(answer);
ctx.close();
}

0

你可以试试这个,我用过了,有效的。

public static Boolean validateLogin(String userName, String userPassword) {
    Hashtable<String, String> env = new Hashtable<String, String>();


    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, "ldap://" + LDAP_SERVER + ":" + LDAP_SERVER_PORT + "/" + LDAP_BASE_DN);
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    env.put(Context.SECURITY_PRINCIPAL, userName + "@" + LDAP_SERVER);
    env.put(Context.SECURITY_CREDENTIALS, userPassword);

    DirContext ctx;
    try {
       ctx = new InitialDirContext(env); //throw exception, if username-password not correct
       return true;
    } catch (Exception e) {
        return false;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接