Apache Shiro LDAP配置(2步验证)

时间:2016-09-23 12:07:29

标签: java ldap shiro

我正在使用以下内容处理Web应用程序:

  • Apache Shiro 1.2.4
  • Tomcat 8
  • Java 8

我正在尝试通过LDAP领域对用户进行身份验证。

我使用以下值测试了使用JXplorer的登录:

  • BaseND:ou =学生,ou =用户,o =数据
  • UserDN / BindDN:cn = {my distinguished name},ou = students,ou = users,o = data
  • JXplorer还有我导入的证书

现在我的问题:

我必须对不是基于GET而是基于cn的用户进行身份验证。 然而,这不会起作用。

我公司的LDAP-Admin建议的工作流程:

我有一个系统用户(据我所知)应该连接到LDAP服务器,根据给定的uid搜索用户并返回该用户的uid

在第二步中,应该可以使用cn对用户进行身份验证,就像在JXplorer中完成(成功)一样。

对于我的测试LDAP,我的shiro.ini配置看起来像这样(不是我现在想要验证的那个)

cn

我现在面临的问题是,我找不到有关如何配置shiro.ini文件的信息,以便从上面算出建议的工作流程。

问题#1

我可以使用标准ldapRealm = org.apache.shiro.realm.ldap.JndiLdapRealm ldapRealm.userDnTemplate = cn={0},ou=People,dc=maxcrc,dc=com ldapRealm.contextFactory.url = ldap://localhost:389 (我该如何配置它)?特别是对于证书的整合,我找不到合适的东西。

问题#2

我是否需要为此“2步验证”创建自定义JndiLdapRealm,这样的Realm看起来如何?

1 个答案:

答案 0 :(得分:1)

我找到了一个解决方案,那就是从getUserDN()

重载JndiLdapRealm方法

现在看起来像这样:

/**
* Addition to standard shiro code
* User logs in with his {@link principal} (username) but login needs to be performed with his cn instead
* The addition is an ldap query to get the users cn from the ldap server and store it (instead of the given principal) in the return String
* @return UserDN with user uid (cn) instead of principal (username)
*/
@Override
protected String getUserDn( final String principal ) throws IllegalArgumentException, IllegalStateException {

    if (!StringUtils.hasText(principal)) {
        throw new IllegalArgumentException("User principal cannot be null or empty for User DN construction.");
    }
    String prefix = getUserDnPrefix();
    String suffix = getUserDnSuffix();
    if (prefix == null && suffix == null) {
        log.debug("userDnTemplate property has not been configured, indicating the submitted " +
                  "AuthenticationToken's principal is the same as the User DN.  Returning the method argument " +
                  "as is.");
        return principal;
    }

    int prefixLength = prefix != null ? prefix.length() : 0;
    int suffixLength = suffix != null ? suffix.length() : 0;
    StringBuilder sb = new StringBuilder(prefixLength + principal.length() + suffixLength);
    if (prefixLength > 0) {
        sb.append(prefix);
    }

    /*############################################################################################
    * ADDITION TO STANDARD SHIRO CODE 
    * User logs in with his {@link principal} (username) but login needs to be performed with his cn instead
    *    => translate username to cn
    */
    AppSettings_Controler settings = Startup.getAppSettingsControler();
    LDAP_Manager ldap_manager = new LDAP_Manager();
    LdapContext ctx = ldap_manager.getLdapConnection();
    String user_uid = "";

    SearchControls constraints = new SearchControls();
    constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
    String[] attrIDs = {"cn"};
    constraints.setReturningAttributes(attrIDs);
    NamingEnumeration answer = null;

    try{
        answer = ctx.search(settings.get_ldap_search_dn_1(), settings.get_ldap_uname_field_name_1() + "=" + principal, constraints);
        if (answer.hasMore()) {
            Attributes attrs = ((SearchResult) answer.next()).getAttributes();
            user_uid = attrs.get("cn").toString().substring(attrIDs[0].length() + 2);
        } else {
            throw new Exception("Invalid User");
        }
    } catch (Exception ex) {
        // Error Handling & Fallback to my second LDAP-Server
        try{
            answer = ctx.search(settings.get_ldap_search_dn_2(), settings.get_ldap_uname_field_name_2() + "=" + principal, constraints);
            if (answer.hasMore()) {
                Attributes attrs = ((SearchResult) answer.next()).getAttributes();
                user_uid = attrs.get("cn").toString().substring(attrIDs[0].length() + 2);
            } else {
                throw new Exception("Invalid User");
            }
        }catch (Exception exe) {
            // Error Handling
        }
    }
    try {
        ctx.close();
    } catch (NamingException ex) {
        JndiLdapRealm_custom_error_logger.error("getUserDn(); Fehler beim schließen: ", ex);
    }
    //############################################################################################

    //############################################################################################
    // Shiro Standard Code -> add principal to String
    //sb.append(principal);
    /*############################################################################################

    /*############################################################################################
    * ALTERED CODE
    * Instead -> Add user's cn to String   
    */
    sb.append(user_uid);
    //############################################################################################

    if (suffixLength > 0) {
        sb.append(suffix);
    }
    return sb.toString();
}

此添加执行LDAP-Query以根据提供的用户名获取用户uid(cn)。这样,登录就可以与用户一起输入我的应用程序的LDAP-Username,并遵循上述工作流程。

如果您有任何建议或意见,请不要犹豫,将它们发布在这里;)