java - Spring Security Active Directory 身份验证但在获取用户数据时抛出异常

标签 java spring-security spring-ldap

我可以使用提供的凭据创建 DirContext。因此,我似乎正在连接到 ldap 服务器并验证凭据,但稍后我们会对从这些凭据获取的上下文进行 .search。这里失败了。除了显示我如何验证凭据正常工作的代码以及似乎失败的代码之外,我还包含了我的 spring 安全配置。

Spring 安全配置

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/security 
                http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <http pattern="/ui/login" security="none"></http>
    <http pattern="/styles" security="none"/>


        <http use-expressions="true">



          <intercept-url pattern="/views/*" access="isAuthenticated()" />
          <intercept-url pattern="/database/upload" access="isAuthenticated()" />
          <intercept-url pattern="/database/save" access="isAuthenticated()" />
          <intercept-url pattern="/database/list" access="isAuthenticated()" />
          <intercept-url pattern="/database/delete" access="isAuthenticated()" />

          <intercept-url pattern="/project/*" access="isAuthenticated()" />
          <intercept-url pattern="/file/*" access="isAuthenticated()" />
          <intercept-url pattern="/amazon/*" access="isAuthenticated()" />
          <intercept-url pattern="/python/*" access="isAuthenticated()" />
          <intercept-url pattern="/r/*" access="isAuthenticated()" />
          <intercept-url pattern="/project/*" access="isAuthenticated()" />
          <intercept-url pattern="/image/*" access="isAuthenticated()" />
          <intercept-url pattern="/shell/*" access="isAuthenticated()" />

          <intercept-url pattern="/register" access="hasRole('ROLE_ADMIN')" />
          <intercept-url pattern="/user/save" access="hasRole('ROLE_ADMIN')" />
          <intercept-url pattern="/user/userAdministrator" access="hasRole('ROLE_ADMIN')" />          
          <intercept-url pattern="/user/list" access="isAuthenticated()" />
          <intercept-url pattern="/user/archive" access="isAuthenticated()" />




    <form-login login-page="/login" default-target-url="/views/main" 
             authentication-failure-url="/loginfailed"/>
        <logout logout-success-url="/login" />


    </http>



<beans:bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">

<beans:constructor-arg value="simplead.blazingdb.com" />
<beans:constructor-arg value="ldap://simplead.blazingdb.com/" />

</beans:bean>

<authentication-manager alias="authenticationManager" erase-credentials="true">
<authentication-provider ref="ldapAuthProvider">
</authentication-provider>
</authentication-manager>




</beans:beans>  

来自 ActiveDirectoryLdapAuthenticationProvider

@Override
    protected DirContextOperations    doAuthentication(UsernamePasswordAuthenticationToken auth) {
    String username = auth.getName();
    String password = (String)auth.getCredentials();

    DirContext ctx = bindAsUser(username, password);

    try {
        return searchForUser(ctx, username);

    } catch (NamingException e) {
        logger.error("Failed to locate directory entry for authenticated user: " + username, e);
        throw badCredentials();
    } finally {
        LdapUtils.closeContext(ctx);
    }
    }

只要我传递正确的凭据,它就会正常返回;如果我发送错误的凭据,它就会失败,所以我知道我们已经做到了这一点。

问题出在 SpringSecurityLdapTemplate 内部

public static DirContextOperations searchForSingleEntryInternal(DirContext ctx, SearchControls searchControls,
        String base, String filter, Object[] params) throws NamingException {
    final DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
    final DistinguishedName searchBaseDn = new DistinguishedName(base);
    final NamingEnumeration<SearchResult> resultsEnum = ctx.search(searchBaseDn, filter, params, searchControls);

    if (logger.isDebugEnabled()) {
        logger.debug("Searching for entry under DN '" + ctxBaseDn
                + "', base = '" + searchBaseDn + "', filter = '" + filter + "'");
    }

    Set<DirContextOperations> results = new HashSet<DirContextOperations>();
    try {
        while (resultsEnum.hasMore()) {
            SearchResult searchResult = resultsEnum.next();
            // Work out the DN of the matched entry
            DistinguishedName dn = new DistinguishedName(new CompositeName(searchResult.getName()));

            if (base.length() > 0) {
                dn.prepend(searchBaseDn);
            }

            if (logger.isDebugEnabled()) {
                logger.debug("Found DN: " + dn);
            }
            results.add(new DirContextAdapter(searchResult.getAttributes(), dn, ctxBaseDn));
        }
    } catch (PartialResultException e) {
        LdapUtils.closeEnumeration(resultsEnum);
        logger.info("Ignoring PartialResultException");
    }

    if (results.size() == 0) {
        throw new IncorrectResultSizeDataAccessException(1, 0);
    }

    if (results.size() > 1) {
        throw new IncorrectResultSizeDataAccessException(1, results.size());
    }

    return results.iterator().next();
    }

具体而言,我认为以下行是我遇到问题的地方。当我们期望返回 1 时,我们得到了大小为 0 的返回值,因此它抛出了一个错误,整个过程失败了。

final NamingEnumeration<SearchResult> resultsEnum = ctx.search(searchBaseDn, filter, params, searchControls);

每当我们尝试执行 resultsEnum.hasMore() 时,我们都会捕获 PartialResultsException。

我正在尝试找出为什么会出现这种情况。我正在使用 Amazon Simple 目录服务(由 Samba 支持的服务,而不是 MSFT 版本)。我对 LDAP 和 Active Directory 非常陌生,因此如果我的问题格式不正确,请让我知道我需要添加哪些信息。

最佳答案

在方法 searchForUser 中,调用方法 SpringSecurityLdapTemplate.searchForSingleEntryInternal,其中传递了一个对象数组。数组的第一个对象与 username@domain 相关。第二个是用户名本身。因此,当您在 ActiveDirectory 中搜索 (&(objectClass=user)(sAMAccountName={0})) 时,您将 username@domain 作为属性传递给搜索的参数 {0}。您只需像这样传递搜索过滤器: (&(objectClass=用户)(sAMAccountName={1}))

编辑:

我假设您已将 searchFilter 传递给 ActiveDirectoryLdapAuthenticationProvider 对象。如果还没有,您必须这样做。

关于java - Spring Security Active Directory 身份验证但在获取用户数据时抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41249099/

相关文章:

Spring Boot/Spring Security AuthenticationEntryPoint 未执行

使用用户名或电子邮件的Spring Security

java - 如何在 WebSphere 中的受信任证书 keystore 中安装证书?

java - Hadoop循环 reducer

spring-security - gradle测试挂起,用于带有嵌入式ldap服务器的 Spring 安全性测试

java - 如何使用 Spring Boot 嵌入式 ldap 服务器向 LDIF 文件添加条目

ldap - Spring ldapTemplate : how to lookup fully qualified DN with configured base DN?

java - 是否 hibernate 分离对象的默认乐观锁定?

java - 错误类型3 : Activity Class {…} does not exist in Eclipse

java - java中读取XML标签,代码优化