Search code examples
apachespring-securityproxytomcat7remember-me

Apache proxy does not recover session correctly by remember-me token after the session expires


Why dont work correctly the user session when this expires after recover remember-me cookie?

I have a peculiar error with I enable the remember-me option in Spring Security. When the session expire, I can navigate for the rest of my web pages, but the logout, and the others POST methods produce a error in server. They doesnt work, because my controllers recive a GET method instead of POST. I dont understand why.

First, I have a Apache httpd serve working as proxy, with ProxyPass configuration. I deployed my .war as ROOT.war because I want to access to my domain www.example.com without indicates the app name (on others words, I dont want indicates www.example.com/appName)

I has read a lot of documentation about this case, and my configuration in virtal host has the following lines:

ProxyRequests Off
<Proxy *>
    Order deny,allow
    Allow from all
</Proxy>

ProxyPass / http://example.com:9080/
ProxyPassReverse / http://example.com:9080/

<Location />
    Order allow,deny
    Allow from all
</Location>

#FIX For Spring Security
RewriteEngine on
RewriteRule ^/(.*)$ http://example.com:9080/$1 [P,L]

The fix for Spring Scurity directives are neccessary for post methods after normal authentication using form.

The problem

Before the JSSESIONID cookie expires, I can use the application correctly: I can logout, I can use other method post, etc...no problems here. But when session expires, anything is broked. I can move through the web pages, access to information, and never I am redirect to login page for authentication (I understand that the remember-me cockie works), but if I use a POST method, I get a problem: my controllers refuse the request because recives a GET method.

I tested the app into same enviroment, but disabled remember-me configuration in security-context.xml, deploy ROOT.war, and test the app when session expires... and..... I am redirect to login page correctly.

In local tomcat (without, apache proxy), my webapp work correctly in both configuration: with remember-me and without remember-me.

security-context.xml

<bean id="csrfSecurityRequestMatcher" class="com.XXX.YYY.config.CsrfSecurityRequestMatcher"></bean>

<security:form-login 
            authentication-success-handler-ref="customAuthenticationSuccessHandler"
            authentication-failure-url="/login?error"
            login-page="/login"
            password-parameter="lgPassword" 
            username-parameter="lgUsername" />

        <security:logout
            success-handler-ref="customLogoutSuccessHandler" 
            logout-url="/logout"
            invalidate-session="true" />

        <security:csrf
            request-matcher-ref="csrfSecurityRequestMatcher" 
            disabled="false" />

        <security:remember-me
            user-service-ref="customUserDetailsService"
            token-repository-ref="customPersistentTokenRepository"
            remember-me-parameter="lgRememberMe"
            remember-me-cookie="TRMMBRM" 
            token-validity-seconds="7776000" />

        <security:session-management>
            <security:concurrency-control 
                max-sessions="1"
                expired-url="/login" />
        </security:session-management>

web.xml (config more important for this case in my opinion...)

...
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
...
<filter>
    <display-name>springSecurityFilterChain</display-name>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- Session Configuration-->
<session-config>
    <session-timeout>1</session-timeout> <!-- (in minutes (1 min for test) --> 
</session-config>

  • JVM Version: 1.8.0_151-b12
  • Spring MVC 4.3.5.RELEASE
  • Spring Security 4.2.1.RELEASE
  • Apache/2.4.6 (CentOS)
  • Apache Tomcat/7.0.76

I have enable CSRF token too for methods, and filters request because avoid proccess paypal methods. Configuration in security-spring.xml

CsrfSecurityRequestMatcher.java (I dont know if this is important for this problem -> ignore if this is not neccessary)

package com.XXX.YYY.config;

import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

public class CsrfSecurityRequestMatcher implements RequestMatcher {
    private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");

    // Deshabilitamos la protección CSRF de las siguientes URLs:
    private AntPathRequestMatcher[] requestMatchers = { new AntPathRequestMatcher("/paypal/**") };

    @Override
    public boolean matches(HttpServletRequest request) {          
        if(allowedMethods.matcher(request.getMethod()).matches()){
            return false;
        }

        // Si la peticion coincide con el patrón a ignorar deshabilitamos la protección CSRF
        for (AntPathRequestMatcher rm : requestMatchers) {
          if (rm.matches(request)) { return false; }
        }

        return true;
    }
}

Solution

  • I resolved this problem finally:

    1. Link to similar problem: Spring Security: invalid-session-url versus logout-success-url
    2. Official documentation of Spring security: https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ns-session-mgmt
    3. Looking note[8] https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ftn.d0e1047

    [8] If you are running your application behind a proxy, you may also be able to remove the session cookie by configuring the proxy server.

    <LocationMatch "/tutorial/j_spring_security_logout">
    Header always set Set-Cookie "JSESSIONID=;Path=/tutorial;Expires=Thu, 01 Jan 1970 00:00:00 GMT"
    </LocationMatch>