Search code examples
springspring-securityremember-me

Spring Security Remember-me with Ajax login


I have implemented spring security ajax login. .

I defined my own customAuthenticationEntryPoint, authenticationFilter, securityLoginSuccessHandler. It can successfully authenticate the user. However, when I add the remember me part. It does not work. There is no SQL run in the database to insert token into persistent_logins. I do not know if there is anything wrong with my configuration? Please help.

<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:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.2.xsd">

    <http pattern="/resources/**" security="none" />
    <http auto-config="false" use-expressions="true" entry-point-ref="customAuthenticationEntryPoint">

        <intercept-url pattern="/**" access="permitAll" />

        <access-denied-handler error-page="/denied" />

        <logout invalidate-session="true" delete-cookies="JSESSIONID"
            success-handler-ref="securityLogoutSuccessHandler" logout-url="/logout" />

        <custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" />
        <csrf />

        <!-- enable remember me -->
    <remember-me 
        services-ref = "rememberMeServices"
        key = "_spring_security_remember_me" />
    </http>


    <beans:bean id="rememberMeServices"
                class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
        <beans:property name="key" value="_spring_security_remember_me"/>
        <beans:property name="alwaysRemember" value="true"/>
        <beans:property name="tokenRepository" ref="jdbcTokenRepository"/>
        <beans:property name="userDetailsService" ref="userDetailsService"/>
    </beans:bean>


    <beans:bean id="jdbcTokenRepository"
                class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
        <beans:property name="createTableOnStartup" value="false"/>
        <beans:property name="dataSource" ref="dataSource"/>
    </beans:bean>

    <beans:bean id="customAuthenticationEntryPoint"
        class="com.tong.beau.service.security.CustomAuthenticationEntryPoint">
        <beans:property name="loginPageUrl" value="/login" />
        <beans:property name="returnParameterEnabled" value="true" />
        <beans:property name="returnParameterName" value="r" />
    </beans:bean>

    <beans:bean id="authenticationFilter"
        class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
        <beans:property name="authenticationManager" ref="authenticationManager" />
        <beans:property name="filterProcessesUrl" value="/security_check" /><!-- 
            change here if customize form action -->
        <!-- handler are for login with ajax POST -->
        <beans:property name="authenticationFailureHandler"
            ref="securityLoginFailureHandler" />
        <beans:property name="authenticationSuccessHandler"
            ref="securityLoginSuccessHandler" />
        <beans:property name="PasswordParameter" value="password" /><!-- 
            change here for password field name in the form -->
        <beans:property name="UsernameParameter" value="username" /><!-- 
            change here for username field name in the form -->
    </beans:bean>

    <beans:bean id="securityLoginSuccessHandler"
        class="com.tong.beau.service.security.SecurityLoginSuccessHandler">
        <beans:property name="defaultTargetUrl" value="/" />
        <beans:property name="targetUrlParameter" value="return-url"/>
    </beans:bean>

    <beans:bean id="securityLoginFailureHandler"
        class="com.tong.beau.service.security.SecurityLoginFailureHandler">
        <beans:property name="defaultFailureUrl" value="/login/failure" />
    </beans:bean>

    <beans:bean id="securityLogoutSuccessHandler"
        class="com.tong.beau.service.security.SecurityLogoutSuccessHandler">
        </beans:bean>

    <beans:bean id="encoder"
        class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

    <authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref="userDetailsService">
            <password-encoder ref="encoder" />
        </authentication-provider>
    </authentication-manager>
</beans:beans>

Since I implemented my CustomAuthenticationEntryPoint, do I need to handle the remember me service in the entry point?


Solution

  • After looking at the source code of Spring Security 4.0.3, I found out that the default parameter is actually defined as this:

    public static final String DEFAULT_PARAMETER = "remember-me";
    

    So what I did was to edit the front end to send the data with name "remember-me".

    Before Spring Security 4.0.3, the default parameter was _spring_security_remember_me

    That would be worth of mention. The configuration also has some problems.

    My working configuration is as following.

    <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:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util"
        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.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util.xsd">
    
        <http pattern="/resources/**" security="none" />
        <http auto-config="false" use-expressions="true" entry-point-ref="customAuthenticationEntryPoint">
    
            <intercept-url pattern="/**" access="permitAll" />
    
            <access-denied-handler error-page="/denied" />
    
            <logout invalidate-session="true" delete-cookies="JSESSIONID"
                success-handler-ref="securityLogoutSuccessHandler" logout-url="/logout" />
    
            <custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" />
            <custom-filter ref="rememberMeFilter" after="FORM_LOGIN_FILTER" />
            <csrf />
            <remember-me key = "remember-me" services-ref="rememberMeServices"/>
        </http>
    
        <beans:bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
              <beans:constructor-arg ref="authenticationManager"/>
              <beans:constructor-arg ref="rememberMeServices"/>
        </beans:bean>
    
        <beans:bean id="rememberMeServices"
                    class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
              <beans:constructor-arg value="remember-me"/>
              <beans:constructor-arg ref="userDetailsService"/>
              <beans:constructor-arg ref="jdbcTokenRepository"/>
        </beans:bean>
    
        <beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
            <beans:constructor-arg value="remember-me"/>
        </beans:bean>
    
        <beans:bean id="jdbcTokenRepository"
                    class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
            <beans:property name="createTableOnStartup" value="false"/>
            <beans:property name="dataSource" ref="dataSource"/>
        </beans:bean>
    
        <beans:bean id="customAuthenticationEntryPoint"
            class="com.tong.beau.service.security.CustomAuthenticationEntryPoint">
            <beans:property name="loginPageUrl" value="/login" />
            <beans:property name="returnParameterEnabled" value="true" />
            <beans:property name="returnParameterName" value="r" />
        </beans:bean>
    
        <beans:bean id="authenticationFilter"
            class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
    
            <beans:property name="authenticationManager" ref="authenticationManager" />
            <beans:property name="rememberMeServices" ref="rememberMeServices" />
            <beans:property name="filterProcessesUrl" value="/security_check" />
    
            <!-- change here if customize form action -->
            <!-- handler are for login with ajax POST -->
    
            <beans:property name="authenticationFailureHandler"
                ref="securityLoginFailureHandler" />
            <beans:property name="authenticationSuccessHandler"
                ref="securityLoginSuccessHandler" />
            <beans:property name="PasswordParameter" value="password" />
            <!-- change here for password field name in the form -->
            <beans:property name="UsernameParameter" value="username" />
            <!-- change here for username field name in the form -->
        </beans:bean>
    
        <beans:bean id="securityLoginSuccessHandler"
            class="com.tong.beau.service.security.SecurityLoginSuccessHandler">
            <beans:property name="defaultTargetUrl" value="/" />
            <beans:property name="targetUrlParameter" value="return-url"/>
        </beans:bean>
    
        <beans:bean id="securityLoginFailureHandler"
            class="com.tong.beau.service.security.SecurityLoginFailureHandler">
            <beans:property name="defaultFailureUrl" value="/login/failure" />
        </beans:bean>
    
        <beans:bean id="securityLogoutSuccessHandler"
            class="com.tong.beau.service.security.SecurityLogoutSuccessHandler">
            </beans:bean>
    
        <beans:bean id="encoder"
            class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
    
        <authentication-manager alias="authenticationManager">
            <authentication-provider ref="rememberMeAuthenticationProvider"> 
            </authentication-provider>
    
            <authentication-provider user-service-ref="userDetailsService">
                <password-encoder ref="encoder" />
            </authentication-provider>
        </authentication-manager>
    </beans:beans>