Session problem: Apache (Proxy) + Tomcat 7 + Spring Security + Remember-Me cookie

0

Why does the user session not work correctly when it expires and is retrieved by the existing remember-me cookie?

I have a strange error when I enabled the option to remember-me in Spring Security. When the session expires it does not redirect me to the login form as it should be normal, but it allows me to browse the rest of the pages without problem, except when doing some action that implodes a POST method (including the logout), in which case the controllers they throw an error indicating that the GET request is not accepted. Why if the method is a POST it comes as GET?

First of all, I have an Apache Server running as a proxy, using the ProxyPass directives. I have deployed my .war application as ROOT.war in order to avoid context problems and be able to access my portal through the main domain ( www.example.com ) without having that indicate the subdomain of the name of my application, in other words, without having to indicate www.example.com/appName.

I have read a lot of information about similar problems and I have been correcting many related things, and the current configuration of my VirtualHost contains 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 are currently necessary because without them, I can not use any post method even if the session has not expired yet.

The problem

Before JSESIONID expires, I can use the application correctly: I can logout, use POST methods, etc ... Without any problems. But when the session expires, something stops working correctly . From this moment I can continue browsing the portal, access information (even closing the browser, and reopening it (it is not the active session of the browser) and in no time redirects me to the login page. the remember-me cookie is functioning correctly in principle, and is able to recover the session and keep the user identified, BUT if I try to use a POST method the controllers reject the request stating that they do not support the GET method (which is correct for that I have indicated that I only work with POST. Why does a GET arrive after the session expires, if before that a POST arrived correctly?

I have tested the application in the same environment but removing the remember-me configuration from the security-context.xml. I display the ROOT.war and when the session expires, it correctly redirects me to the login page as it should happen.

On the other hand, on my local tomcat server (without the apache working as a proxy) the application works correctly with both remember-me and without it. Any idea what could be happening?

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 (I have some listeners and filters that I do not know if they could affect ...)

...
<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 also have the CSRF token enabled for the POST methods, and I am also filtering the requests that the CSRF handles to avoid dealing with the paypal ones. I do not know if it is relevant asiíq eu I put it, and otherwise ignore this part. (Configuration in security-spring.xml)

CsrfSecurityRequestMatcher.java

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;
    }
}
    
asked by Yeray Ventura Garcia 22.11.2017 в 15:11
source

1 answer

0

In case anyone finds it useful someday, I solved the problem based on the following:

  • Link to a similar problem: link

  • Official Spring Security documentation: link

  • See note 8 link

  •   

    [8] If you are running your application behind a proxy, you may also   Be able to remove the cookie session 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>
    

    I still had to delete the JSESSIONID mainly after the logout.

        
    answered by 26.11.2017 / 21:20
    source