Authentication 如何配置Spring安全身份验证以处理复杂的Active Directory/LDAP帐户树?
(上下文:我是一名经验丰富的程序员,但对LDAP、AD和Spring还不熟悉。) 我们是一家Windows商店,因此所有身份验证都是通过Active Directory完成的。我们正在尝试集成一个用Java编写的第三方产品,因此它使用Spring Security进行所有身份验证。到目前为止,一切都很好——他们以前做过这种集成,网上有很多关于如何设置的东西 问题是,我们的AD设置有点复杂:特别是,我们的用户帐户存在于AD/LDAP树的各个节点中。为了给出一个简化的示例,假设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树如下所示:
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程序是不可行的。)
非常感谢您提供的任何指导…如果可行,您可以尝试从域根目录进行搜索,但这可能会导致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="(&(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");