Spring Security 3不适用于JDK 1.7

时间:2012-03-20 05:07:27

标签: spring-security ldap java-7

我在Spring MVC项目中使用经过LDAP身份验证的Spring Security 3。 它工作正常,直到我需要将我的项目部署到其他环境并将JDK的版本从1.6更改为1.7。

下面是我的spring安全配置文件和示例代码:

1)security-application-Context.xml

    <?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns:s="http://www.springframework.org/schema/security"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    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">

    <s:http use-expressions="true">     
        <s:intercept-url pattern="/auth/**" access="permitAll" />
        <s:intercept-url pattern="/css/**" access="permitAll" />
        <s:intercept-url pattern="/image/**" access="permitAll" />
        <s:intercept-url pattern="/scripts/**" access="permitAll" />        

        <s:intercept-url pattern="/**" access="hasRole('GENERAL_USER')" />

        <s:form-login login-page="/auth/login.html" 
                      default-target-url="/welcome.html"  
                      authentication-failure-url="/auth/login.html?error=1" /> 

        <s:access-denied-handler error-page="/auth/denied.html"/>   

        <s:logout invalidate-session="true" logout-success-url="/auth/logoutSuccess.html"/>                         
    </s:http>

    <s:authentication-manager>
        <s:authentication-provider ref="ldapAuthProvider" />
    </s:authentication-manager>

    <bean 
        id="contextSource"
        class="org.springframework.security.ldap.DefaultSpringSecurityContextSource" 
        scope="singleton">
        <constructor-arg
            value="ldap://ldapurl:389/dc=o,dc=a"  />
            <property name="userDn" value="cn=xxx,cn=users,dc=o,dc=a" />
            <property name="password" value="password" />
            <property name="baseEnvironmentProperties">
                <map>
                    <entry key="java.naming.referral">
                        <value>follow</value>
                    </entry>                    
                </map>
            </property>         
    </bean>

    <bean id="userSearch"
        class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
        <!-- searchBase, searchFilter, contextSource -->
        <constructor-arg index="0" value="" />
        <constructor-arg index="1" value="(sAMAccountName={0})" />
        <constructor-arg index="2" ref="contextSource" />
    </bean> 

    <bean id="ldapAuthProvider"
        class="com.foo.auth.MyLdapAuthenticationProvider">      
        <constructor-arg>     
            <bean     
                class="com.foo.auth.MyLdapAuthenticator">
                <constructor-arg ref="contextSource" />
                <property name="userSearch">
                    <ref bean="userSearch" />
                </property>             
            </bean>
        </constructor-arg>
        <property name="authoritiesPopulator" ref="authoritiesPopulator" />
        <property name="userDetailsContextMapper" ref="userDetailsMapper" />
    </bean>  

    <bean id="authoritiesPopulator" class="com.foo.auth.MyLdapAuthoritiesPopulator">
        <constructor-arg ref="userService" />       
    </bean>     

    <bean id="userService" class="com.foo.auth.MyLdapUserDetailsService">   
        <constructor-arg ref="userSearch" />
        <property name="userDetailsMapper" ref="userDetailsMapper" />
    </bean> 
    <bean id="userDetailsMapper" class="com.foo.auth.MyUserDetailsContextMapper">                    
    </bean>         
</beans>

2)成功登录后会将url重定向到welcome.jsp,在welcome.jsp中,我使用spring security taglib来获取登录用户的全名。 (对于测试,我使用principal来显示整个上下文信息):

<security:authentication property="principal"></security:authentication>    

当使用JDK 1.6时,校长显示:

com.foo.auth.MyUserDetails@3e2d20ec:.........

我可以使用我的自定义UserDetail属性,例如principal.fullName。 当使用JDK 1.7时,校长显示:

 org.springframework.security.ldap.userdetails.LdapUserDetailsImpl@86dae957:... 

它没有获取我的自定义UserDetail对象。所以如果我使用JDKk1.7,我就无法正确获取Spring上下文。

这个问题花了我差不多1周的时间才发现根本原因是JDK版本的问题; - (

有谁知道为什么使用LDAP的Spring安全性在JDK1.7中不起作用?或者我想念配置的东西?

提前谢谢你!

1 个答案:

答案 0 :(得分:1)

问题已解决。 这是因为我的MyLdapAuthenticationProvider扩展了错误的提供者。 我将MyLdapAuthenticationProvider扩展类更改为LdapAuthenticationProvider, 现在JDK 1.6和1.7中的弹簧安全性都很好。

这是我的自定义LdapAuthenticationProvider:

public class MyLdapAuthenticationProvider extends LdapAuthenticationProvider {

private static Logger logger = Logger.getLogger(MyLdapAuthenticationProvider.class);         
private MyLdapAuthenticator authenticator; 
@Autowired
private MyLdapAuthoritiesPopulator authoritiesPopulator;
@Autowired
private MyUserDetailsContextMapper userDetailsContextMapper;

public MyLdapAuthenticationProvider(LdapAuthenticator authenticator) {
    super(authenticator);
    this.authenticator = (MyLdapAuthenticator) authenticator;
}

@Override
protected DirContextOperations doAuthentication(UsernamePasswordAuthenticationToken userToken) {
    try {
        DirContextOperations dirCtx = getAuthenticator().authenticate(userToken);            
        return dirCtx;
    } catch (PasswordPolicyException ppe) {
        throw new LockedException(this.messages.getMessage(ppe.getStatus().getErrorCode(), ppe.getStatus()
                .getDefaultMessage()));
    } catch (UsernameNotFoundException notFound) {            
        throw new BadCredentialsException("User Name Error!");
    } catch (NamingException ldapAccessFailure) {
        throw new AuthenticationServiceException(ldapAccessFailure.getMessage(), ldapAccessFailure);
    }
}

private void setAuthenticator(MyLdapAuthenticator authenticator) {
    Assert.notNull(authenticator, "An LdapAuthenticator must be supplied");
    this.authenticator = authenticator;
}

private MyLdapAuthenticator getAuthenticator() {
    return authenticator;
}

public MyUserDetailsContextMapper getUserDetailsContextMapper() {
    return userDetailsContextMapper;
}

public void setUserDetailsContextMapper(MyUserDetailsContextMapper userDetailsContextMapper) {
    this.userDetailsContextMapper = userDetailsContextMapper;
}

public void setAuthoritiesPopulator(MyLdapAuthoritiesPopulator authoritiesPopulator) {
    this.authoritiesPopulator = authoritiesPopulator;
}

public MyLdapAuthoritiesPopulator getAuthoritiesPopulator() {
    return authoritiesPopulator;
}

}