0

I have implemented 'Remember Me' functionality in my Spring MVC application using Spring Security 3.1

My security-context.xml looks like this :

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

    <import resource="servlet-context.xml" />
    <security:global-method-security secured-annotations="enabled" />

    <security:http auto-config="true" authentication-manager-ref="am">

    <!-- Restrict URLs based on role -->
    <security:intercept-url pattern="/public/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <security:intercept-url pattern="/resources/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <security:intercept-url pattern="/**" access="ROLE_USER" />

    <!-- Override default login and logout pages -->
    <security:form-login login-page="/public/login" 
                 login-processing-url="/public/loginProcess" 
                 default-target-url="/public/loginSuccess" 
                 authentication-failure-url="/public/login?login_error=1" 
                 always-use-default-target="true" />
    <security:logout logout-url="/public/logout" logout-success-url="/public/login?logout=1" />
    <security:remember-me services-alias="rmService" data-source-ref="dataSource"/>
    <security:custom-filter position="LAST" ref="httpResponseAuthFilter" />
    </security:http>

    <security:authentication-manager id="am">
    <security:authentication-provider >
        <security:password-encoder ref="passwordEncoder" />
        <security:jdbc-user-service data-source-ref="dataSource" />
    </security:authentication-provider>
    </security:authentication-manager>

    <bean id="httpResponseAuthFilter"
    class="mypackage.HttpResponseAuthenticationFilter" >
     <property name="authenticationManager" ref="am"/>
     <property name="rememberMeServices" ref="rmService"></property>
    </bean> 

</beans>

The Filter class is implemented like this :

    public class HttpResponseAuthenticationFilter extends RememberMeAuthenticationFilter {

    @Override
    protected void onSuccessfulAuthentication(final HttpServletRequest request, final HttpServletResponse response,
            final Authentication authResult) {

        super.onSuccessfulAuthentication(request, response, authResult);

        if (authResult != null) {
            // process post authentication logic here..
        }
    }

}

Remember me functionality works fine using the above configuration but while running in eclipse debugger I found that HttpResponseAuthenticationFilter.onSuccessfulAuthentication() doesn't get invoked.

EDIT

After modifying my security-context.xmls and defining the remember-me service using standard Spring beans and referencing the service inside the configuration looks

    <security:http auto-config="true" authentication-manager-ref="am">
    <!-- Restrict URLs based on role -->
    <security:intercept-url pattern="/public/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <security:intercept-url pattern="/resources/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <security:intercept-url pattern="/**" access="ROLE_USER" />

    <!-- Override default login and logout pages -->
    <security:form-login login-page="/public/login" 
                         login-processing-url="/public/loginProcess" 
                         default-target-url="/public/loginSuccess" 
                         authentication-failure-url="/public/login?login_error=1" 
                         always-use-default-target="true" />

    <security:remember-me services-ref="rememberMeService"/>
    <security:logout logout-url="/public/logout" logout-success-url="/public/login?logout=1" />
    <security:custom-filter position="LAST" ref="httpResponseAuthFilter" />
</security:http>

<security:authentication-manager id="am">
    <security:authentication-provider >
        <security:password-encoder ref="passwordEncoder" />
        <security:jdbc-user-service data-source-ref="dataSource" />
    </security:authentication-provider>
    <security:authentication-provider ref="rememberMeAuthenticationProvider" />
</security:authentication-manager>

<bean id="rememberMeAuthenticationProvider" class=
        "org.springframework.security.authentication.RememberMeAuthenticationProvider">
        <property name="key" value="riskAnalysis" /> 
</bean>

<bean id="httpResponseAuthFilter"
    class="mypacakge.HttpResponseAuthenticationFilter" >
     <property name="authenticationManager" ref="am"/>
     <property name="rememberMeServices" ref="rememberMeService"></property>
</bean> 

<bean id="rememberMeService"
    class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
    <property name="userDetailsService" ref="userDetailsService" />
    <property name="key" value="riskAnalysis" />
</bean>

<bean id="userDetailsService"
  class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
    <property name="dataSource" ref="dataSource"/>
</bean>    

Here is what I get in the logs :

*DEBUG: mypackage.HttpResponseAuthenticationFilter - SecurityContextHolder not populated with remember-me token, as it already contained: 'org.springframework.security.authentication.RememberMeAuthenticationToken@303f2184: Principal: org.springframework.security.core.userdetails.User@cb7ea6f6: Username: tarun4; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ADMIN, ROLE_USER'*

So it looks like authentication information is present in the session.

Thanks, Tarun

Tarun Gupta
  • 1,629
  • 1
  • 22
  • 39

1 Answers1

2

The remember-me namespace element already inserts a RememberMeAuthenticationFilter so it will still take precedence over yours, since it comes before it in the filter chain.

If you want to use a custom filter, you should remove the namespace element and use standard Spring beans for the related services. There's an example in the reference manual (Section 11.4.1) which shows the beans needed.

Shaun the Sheep
  • 22,353
  • 1
  • 72
  • 100
  • Could you please review the changes I made to see if it looks fine now. After making the above changes I see debug logs from the Filter class that I added : 'DEBUG: mypackage.HttpResponseAuthenticationFilter - SecurityContextHolder not populated with remember-me token' But I haven't been able to see the control reaching my onSuccessfulAuthentication method. – Tarun Gupta Mar 27 '14 at 05:34
  • Also probably its worth mentioning here that in the [in the reference manual (Section 11.4.1)](http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#remember-me-impls) the package name for RememberMeAuthenticationProvider is mentioned incorrectly as org.springframework.security.authentication.rememberme.RememberMeAuthenticationProvider, the correct package name is org.springframework.security.authentication.RememberMeAuthenticationProvider – Tarun Gupta Mar 27 '14 at 05:42
  • Please add the full log message to your question. Either the token was rejected or the security context already contains an `Authentication` object (take a look at [the code](https://github.com/spring-projects/spring-security/blob/master/web/src/main/java/org/springframework/security/web/authentication/rememberme/RememberMeAuthenticationFilter.java#L142)). – Shaun the Sheep Mar 27 '14 at 13:15