Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Authentication 如何配置Spring安全身份验证以处理复杂的Active Directory/LDAP帐户树?_Authentication_Active Directory_Spring Security - Fatal编程技术网

Authentication 如何配置Spring安全身份验证以处理复杂的Active Directory/LDAP帐户树?

Authentication 如何配置Spring安全身份验证以处理复杂的Active Directory/LDAP帐户树?,authentication,active-directory,spring-security,Authentication,Active Directory,Spring Security,(上下文:我是一名经验丰富的程序员,但对LDAP、AD和Spring还不熟悉。) 我们是一家Windows商店,因此所有身份验证都是通过Active Directory完成的。我们正在尝试集成一个用Java编写的第三方产品,因此它使用Spring Security进行所有身份验证。到目前为止,一切都很好——他们以前做过这种集成,网上有很多关于如何设置的东西 问题是,我们的AD设置有点复杂:特别是,我们的用户帐户存在于AD/LDAP树的各个节点中。为了给出一个简化的示例,假设LDAP树如下所示:

(上下文:我是一名经验丰富的程序员,但对LDAP、AD和Spring还不熟悉。)

我们是一家Windows商店,因此所有身份验证都是通过Active Directory完成的。我们正在尝试集成一个用Java编写的第三方产品,因此它使用Spring Security进行所有身份验证。到目前为止,一切都很好——他们以前做过这种集成,网上有很多关于如何设置的东西

问题是,我们的AD设置有点复杂:特别是,我们的用户帐户存在于AD/LDAP树的各个节点中。为了给出一个简化的示例,假设LDAP树如下所示:

DC=my-domain,DC=com
+ CN=Users
++ CN=user1,CN=Users,DC=my-domain,DC=com
+ CN=Staff
++ CN=user2,CN=Staff,DC=my-domain,DC=com
问题是,我找到的所有示例都允许我对user1或user2进行身份验证,但不能同时对两者进行身份验证。也就是说,以下XML片段将用于根据“组”下定义的角色对user1进行身份验证:


但这不会验证user2,因为他与用户搜索库不匹配。相反,我可以将用户搜索库更改为
CN=Staff,DC=mydomain,DC=com
,这对user2有效,但对user1无效

因此,问题是,我如何使这个搜索对分散在AD/LDAP树中的用户帐户起作用?我可以想象两种可能性,但我还没有想到如何做到这一点:

  • 一方面,如果我能让用户搜索库多值化,那么我的问题就可以简单而正确地解决了:我只需要把所有可能找到用户帐户的位置都放进去。到目前为止,我所有的尝试都遇到了这样或那样的错误,但我仍在尝试

  • OTOH,搜索有子树范围。我可以在交互式LDAP工具中看到,搜索可以是单层的,也可以是子树的。据我所知,Spring out the box是在做单水平测试。我可以看到底层的filterbasedapusersearch类有一个setSearchSubtree()方法,它看起来像我想要的,但是我找不到从XML中将其设置为true的方法。(现在,让我们假设更改底层Java程序是不可行的。)

第一种选择是理想的,因为它可能更有效,但如果这不可能,第二种是,我怀疑我们可以让它工作

我怀疑第二种方法可能使用thorny bean hackery,但我对bean几乎一无所知,所以我不想自己涉入那些灌木丛。有谁有好的食谱可以推荐吗


非常感谢您提供的任何指导…

如果可行,您可以尝试从域根目录进行搜索,但这可能会导致AD出现问题

或者,使用显式可能是最好的选择。您可以将自定义的
LdapUserSearch
实现注入到
BindAuthenticator
bean中,该bean在所有必要的位置下进行搜索。如果您查看文档中的示例,它将显示一个
filterbasedapusersearch
配置。您可以使用其中的几个,也可以自己从头开始实现接口。以下是一个快速破解示例:

public class CustomLdapSearch implements LdapUserSearch {
    public static final String SAM_FILTER="(&(sAMAccountName={0})(objectclass=user))"

    final LdapUserSearch users;
    final LdapUserSearch staff;

    public CustomLdapSearch(BaseLdapPathContextSource contextSource) {
        users = new FilterBasedLdapUserSearch("CN=Users,DC=my-domain,DC=com", SAM_FILTER, contextSource);
        staff = new FilterBasedLdapUserSearch("CN=Staff,DC=my-domain,DC=com", SAM_FILTER, contextSource);

    }

    public DirContextOperations searchForUser(String username) {
        try {
            return users.searchForUser(username);
        } catch(UsernameNotFoundException e) {
            return staff.searchForUser(username);
        }
    }
}
然后将
BindAuthenticator
配置更改为:

<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
 <constructor-arg ref="contextSource"/>
 <property name="userSearch" ref="customSearch"/>
</bean>

<bean id="customSearch" class="CustomLdapSearch">
 <constructor-arg ref="contextSource"/>
</bean>

我使用FilterBasedLdapUserSearch对spring-security-2.0.x做了类似的操作,其中用户分布在多个节点上:

<bean id="ldapUserSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
    <constructor-arg value=""/> <!-- optional sub-tree here -->
    <constructor-arg value="(&amp;(sAMAccountName={0})(objectclass=user))"/>
    <constructor-arg ref="contextSource"/>
</bean>


<bean id="ldapAuthProvider"
      class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
    <constructor-arg>
        <bean class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
            <constructor-arg ref="contextSource"/>
            <property name="userSearch" ref="ldapUserSearch"/>
        </bean>
    </constructor-arg>
    <property name="userDetailsContextMapper" ref="userDetailsContextMapper"/>
</bean>


<bean id="contextSource"
      class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
    <constructor-arg value="ldap://localhost:10389/CN=Users,DC=my-domain,DC=com"/>
<!-- you may or may not need to connect with an account that can search -->
    <!--<property name="userDn" value="uid=admin,ou=system"/>-->
    <!--<property name="password" value="secret"/>-->
</bean>

我通过使用带有空字符串值的searchBase解决了这个问题(这使用根作为searchBase,就像prule的答案一样),但是我还必须将属性“reference”设置为“follow”,否则我会得到PartialResultException

DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(...);
contextSource.setReferral("follow");

这个答案很有帮助,但也有问题。例如:当“用户”和“员工”应该是LdapUserSearch时,您将它们声明为LdapSearch。您还声明了它们为final,但没有将它们设置为任何值。谢谢,我已经更新了代码。字段在构造函数中设置。
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(...);
contextSource.setReferral("follow");