【问题标题】:LDAP user password authentication using JNDI使用 JNDI 的 LDAP 用户密码认证
【发布时间】:2010-08-11 09:05:13
【问题描述】:
public static void main(String[] args)
{
    String INITCTX = "com.sun.jndi.ldap.LdapCtxFactory";
    String MY_HOST = "ldap://Localhost:1389";
    String MGR_DN = "cn=John,ou=Users,o=IT,dc=QuizPortal";
    String MGR_PW = "password";           

    //Identify service provider to use
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, INITCTX);
    env.put(Context.PROVIDER_URL, MY_HOST);
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    env.put(Context.SECURITY_PRINCIPAL, MGR_DN);
    env.put(Context.SECURITY_CREDENTIALS, MGR_PW);

    try
    {
        // Create the initial directory context
        InitialDirContext initialContext = new InitialDirContext(env);

        System.out.println("Context Sucessfully Initialized");
    }
    catch(Exception e)
    {
        System.err.println(e);
    }
}

我想问一下我何时将MGR_DN = "cn=John,ou=Users,o=IT,dc=QuizPortal" 设置为MGR_DN = "uid=103,ou=Users,o=IT,dc=QuizPortal"。基本上是从cn改成uid,会遇到错误

javax.naming.AuthenticationException: [LDAP: error code 49 - Invalid Credentials]

当指定为cn=John 而不是uid=103 时,我已通过身份验证。我不能通过uid指定吗?

【问题讨论】:

    标签: java ldap jndi


    【解决方案1】:

    如果您事先不知道确切的 DN,则应先在 LDAP 目录中进行搜索。这可以或多或少像这样完成(确保你捕获了相关的异常):

    Properties env = new Properties();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, ldapServerUrl);
    env.put(Context.SECURITY_AUTHENTICATION, "none");
    
    SearchControls searchCtrls = new SearchControls();
    searchCtrls.setReturningAttributes(new String[] {});
    searchCtrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    
    String filter = "(&(cn=" + identifier + "))";
    
    DirContext ctx = null;
    ctx = new InitialDirContext(env);
    NamingEnumeration<SearchResult> answer = ctx.search(
       ldapBaseDN, filter, searchCtrls);
    
    String fullDN = null;
    if (answer.hasMore()) {
        fullDN = answer.next().getNameInNamespace();
    
        ctx.close();
        ctx = null;
    
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, fullDN);
        env.put(Context.SECURITY_CREDENTIALS, password);
    
        ctx = new InitialDirContext(env);
        return true;
    }
    // Exception otherwise ...
    

    这里,搜索过滤器是"(&amp;(cn=" + identifier + "))"(例如(&amp;(cn=John))),但您可以改用uid。结果的唯一性取决于 LDAP 服务器的配置。基本 DN 还取决于它的设置方式(在您的示例中可能是 ou=Users,o=IT,dc=QuizPortal)。

    【讨论】:

    • 例如,当您只有 uid 或 cn 时,这只会帮助您获得完整的 DN。通常,某些 LDAP 服务器被配置为具有跨子树的唯一 uid。进行搜索可以帮助您找到合适的用户。例如,如果您已将 LDAP 树组织为具有多个子树(例如 ou=Marketingou=Finances),其中 uid=user1,ou=Marketing,o=MyCompanyuid=user2,ou=Finances,o=MyCompany 并将其配置为使用跨 o=MyCompany 的唯一 uid,您可以使用这种搜索找到具有uid=user1(您需要进行身份验证)的用户的完整DN。
    • 您好,感谢您的分享。现在我对 LDAP 有了更好的理解 :) 顺便说一句,你的代码就像一个魅力。谢谢!
    • 嗨布鲁诺,我想做同样的事情。从 uid 获取 dn 并使用密码对其进行身份验证。我试过你的代码,但它抛出错误“为了执行这个操作,必须在连接上完成成功的绑定。”如何解决这个问题??
    • 注意,请注意此实现可能允许用户使用空密码进行身份验证。见stackoverflow.com/questions/12359831/…。根据 LDAP 服务器的实现,您还需要检查密码变量是否为空。
    • @kaushalpranav 这不是我的想法,8 年后,所以你需要检查一下,但据我记得,第一个 new InitialDirContext(env) 进行搜索,第二个一个(就在return true 之前)进行身份验证。如果身份验证失败,它应该抛出一个异常(因此不会达到 true)。
    【解决方案2】:

    您必须指定 DN 或专有名称。这是用户在目录中绑定的名称。您不能只选择任何属性链。如果您的用户是通过 'cn' 属性绑定的,那么只有 'cn' 属性是 DN 的一部分。

    【讨论】:

    • 哦...谢谢!明白了...想知道为什么它不起作用...谢谢
    • 这取决于 LDAP 目录。有些允许备用命名属性,在这种情况下 uid=103 可能会起作用。而其他人不会。所以这不是一个可靠的方法。
    【解决方案3】:

    看起来像是服务器配置问题。 Here's a similar problem including a solution。基本上你必须指定是使用uid 还是cnldap-authentication.properties 中进行身份验证。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-05
      相关资源
      最近更新 更多