2011-08-19 50 views
5

我們正在使用spring security在我們的應用程序中通過LDAP對用戶進行身份驗證。認證部分正常工作,但授權部分不工作。如何使用Spring安全性從Active Directory LDAP填充LDAP授權?

我們無法從LDAP中檢索用戶的角色。

從書「春季安全3」彼得Mularien

「這是因爲活動目錄存儲組成員作爲 屬性用戶的LDAP條目自己。開箱(截至發佈時間), Spring Security不提供可配置爲支持典型Active Directory LDAP樹結構的 的LdapAuthoritiesPopulator。「

下面是我的spring-security配置文件。

<?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:context="http://www.springframework.org/schema/context" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
          http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"> 

     <http use-expressions="true" > 
     <intercept-url pattern="/resources/**" filters="none" /> 
     <intercept-url pattern="/login" access="permitAll"/> 
     <intercept-url pattern="/**" access="isAuthenticated()" /> 
     <form-login login-page="/login" 
        default-target-url="/home" 
        always-use-default-target="true" 
        authentication-failure-url="/login?login_error=1" /> 
     <logout invalidate-session="true" 
       logout-success-url="/" 
       logout-url="/logout"/> 
    </http> 

    <authentication-manager alias="ldapAuthenticationManager"> 
     <authentication-provider ref="ldapAuthenticationProvider"/> 
    </authentication-manager> 

    <beans:bean id="ldapAuthenticationProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider"> 
     <beans:constructor-arg ref="ldapBindAuthenticator"/> 
     <beans:constructor-arg ref="ldapAuthoritiesPopulator"/> 
     <beans:property name="userDetailsContextMapper" ref="ldapUserDetailsContextMapper"/> 
    </beans:bean> 

    <beans:bean id="ldapServer" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource"> 
     <!-- MS Active Directory --> 
     <beans:constructor-arg value="ldap://localhost:389/dc=myOrg,dc=net"/> 
     <beans:property name="userDn" value="admin"/> 
     <beans:property name="password" value="admin"/> 
     <beans:property name="baseEnvironmentProperties"> 
      <beans:map> 
       <beans:entry key="java.naming.referral" value="follow" /> 
      </beans:map> 
     </beans:property> 
    </beans:bean> 

    <beans:bean id="ldapBindAuthenticator" class="org.springframework.security.ldap.authentication.BindAuthenticator"> 
     <beans:constructor-arg ref="ldapServer"/> 
     <beans:property name="userSearch" ref="ldapSearchBean"/> 
    </beans:bean> 

    <beans:bean id="ldapSearchBean" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch"> 
     <!-- MS Active Directory --> 
     <!-- user-search-base; relative to base of configured context source --> 
     <beans:constructor-arg value="ou=Software OU"/> 
     <!-- user-search-filter --> 
     <beans:constructor-arg value="(sAMAccountName={0})"/> 
     <beans:constructor-arg ref="ldapServer"/> 
    </beans:bean> 

    <beans:bean id="ldapAuthoritiesPopulator" class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator"> 
     <beans:constructor-arg ref="ldapServer" /> 
     <beans:constructor-arg value="" /> 
     <beans:property name="groupSearchFilter" value="(sAMAccountName={0})"/> 
     <beans:property name="groupRoleAttribute" value="memberOf" /> 
     <beans:property name="rolePrefix" value=""/> 
     <beans:property name="searchSubtree" value="true"/> 
     <beans:property name="convertToUpperCase" value="false"/> 
     <beans:property name="ignorePartialResultException" value="true"/> 
    </beans:bean> 

    <beans:bean class="org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper" id="ldapUserDetailsContextMapper"/> 

</beans:beans> 

請幫忙。

+0

代碼中缺少什麼?接受提供的解決方案/超鏈接是一回事,但指出缺少的部分對於幫助其他人(例如我)完全相同的問題會很好。感謝您分享您的詳細解決方案。 –

+1

@CharlesMorin我意識到我的答案是低標準的,對不起。爲AD添加了我們的Spring配置。 –

+0

@MarcelStör謝謝。你在使用什麼應用程序服務器?我試圖在JBoss AS 7.2上做同樣的事情,但沒有取得任何成功。將看看你的配置。 –

回答

2

你可能想看看這裏:https://jira.springsource.org/browse/SEC-876。儘管此代碼貢獻被拒絕,並有合理的答案,但可能會給您提示。

我們採用以下配置:

的Spring XML

<bean id="ldapUserService" class="MyUserDetailService"> 
    <constructor-arg ref="ldapUserSearch"/> 
    <constructor-arg ref="ldapAuthoritiesPopulator"/> 
</bean> 
<bean id="ldapUserSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch"> 
    <constructor-arg value="OU=FOO-Accounts,OU=FOO,OU=OU-GLOBAL"/> <!-- user search base, RELATIVE TO SERVER CONTEXT (URL & base of configured LDAP server)! --> 
    <constructor-arg value="(sAMAccountName={0})"/> <!-- user search filter --> 
    <constructor-arg ref="ldapServer"/> 
</bean> 
<bean id="ldapAuthoritiesPopulator" class="MyLdapAuthoritiesPopulator"> 
    <constructor-arg ref="ldapServer" /> 
    <constructor-arg value="=OU=SomeFooBar,OU=FOO-Global-Security,OU=FOO-Groups,OU=FOO,OU=OU-GLOBAL" /> <!-- group search base, RELATIVE TO SERVER CONTEXT (URL & base of configured LDAP server)! --> 
    <constructor-arg ref="roleMappings"/> 
    <property name="groupRoleAttribute" value="cn" /> 
    <property name="groupSearchFilter" value="(member={0})" /> 
</bean> 

填充器

有很多的專有代碼,我不能分享,因爲我們的客戶有額外的信息AD我們需要提取。我刪除了這個問題,因爲它不關心這個問題。因此,這段代碼不會編譯。

public class MyLdapAuthoritiesPopulator extends DefaultLdapAuthoritiesPopulator { 

    /** 
    * Prefix assigned by Spring Security to each group/role from LDAP. 
    */ 
    public static final String AUTHORITY_ROLE_PREFIX = "ROLE_"; 

    private Properties roleMappings; 
    private Properties invertedRoleMappings; 

    /** 
    * 
    * @param contextSource supplies the contexts used to search for user roles. 
    * @param groupSearchBase if this is an empty string the search will be performed from the root DN 
    * of the context factory. If null, no search will be performed. 
    * @param roleMappings maps logical (internal) role names to names as delivered by LDAP 
    */ 
    @SuppressWarnings("deprecation") 
    public MyLdapAuthoritiesPopulator(final ContextSource contextSource, 
     final String groupSearchBase, 
     final Properties roleMappings) { 
    super(contextSource, groupSearchBase); 
    setConvertToUpperCase(false); 
    setRolePrefix(""); 
    this.roleMappings = roleMappings; 
    this.invertedRoleMappings = invertRoleMappings(); 
    logger.info("Processing LDAP roles based on the following mapping: {}.", roleMappings); 
    } 

    ..... 

    @Override 
    public Set<GrantedAuthority> getGroupMembershipRoles(final String userDn, final String username) { 
    final Set<GrantedAuthority> effectiveGroupMembershipRoles = super.getGroupMembershipRoles(
     userDn, username); 
    return mapEffectiveRolesToApplicationRoles(effectiveGroupMembershipRoles); 
    } 

    /** 
    * Maps effective LDAP roles such as 'foo_boston_dispatcher' or 'foo_boston_readonly' to 
    * FOO internal roles. The internal role (i.e. the {@link GrantedAuthority}) is a combination 
    * of the 'ROLE_' prefix and a {@link Role} enum value. ......... 
    */ 
    Set<GrantedAuthority> mapEffectiveRolesToApplicationRoles(final Set<GrantedAuthority> effectiveGroupMembershipRoles) { 
    logger.info("Processing effective roles from LDAP: {}.", effectiveGroupMembershipRoles); 
    final Set<GrantedAuthority> internalRoles = new HashSet<GrantedAuthority>(); 
    final List<String> effectiveRoleNames = extractRoleNamesFrom(effectiveGroupMembershipRoles); 
    final List<String> unmappedGroupMembershipRoles = new ArrayList<String>(); 
    ...... 
    // in a method invoked here we do something like internalRoles.add(new GrantedAuthority(AUTHORITY_ROLE_PREFIX + role)); 
    ...... 
    logger.info("Created internal roles {}.", internalRoles); 
    logger.trace(
     "The following group membership roles were not mapped to an internal equivalent: {}", 
     unmappedGroupMembershipRoles); 
    return internalRoles; 
    } 

    ...... 

    private List<String> extractRoleNamesFrom(final Collection<GrantedAuthority> authorities) { 
    final List<String> authorityNames = new ArrayList<String>(authorities.size()); 
    for (GrantedAuthority authority : authorities) { 
     authorityNames.add(authority.getAuthority()); 
    } 
    return authorityNames; 
    } 
} 
+0

你介意分享你的MyLdapAuthoritiesPopulator類嗎?謝謝。 –