diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurer.java index cb581c88c5..e6c252dfbf 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurer.java @@ -15,7 +15,9 @@ */ package org.springframework.security.config.annotation.web.configurers; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import org.springframework.http.MediaType; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; @@ -114,12 +116,13 @@ public final class RequestCacheConfigurer> exte return defaultCache; } + @SuppressWarnings("unchecked") private RequestMatcher createDefaultSavedRequestMatcher(H http) { ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class); if(contentNegotiationStrategy == null) { contentNegotiationStrategy = new HeaderContentNegotiationStrategy(); } - RequestMatcher getRequests = new AntPathRequestMatcher("/**", "GET"); + RequestMatcher notFavIcon = new NegatedRequestMatcher(new AntPathRequestMatcher("/**/favicon.ico")); MediaTypeRequestMatcher jsonRequest = new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.APPLICATION_JSON); @@ -127,6 +130,18 @@ public final class RequestCacheConfigurer> exte RequestMatcher notJson = new NegatedRequestMatcher(jsonRequest); RequestMatcher notXRequestedWith = new NegatedRequestMatcher(new RequestHeaderRequestMatcher("X-Requested-With","XMLHttpRequest")); - return new AndRequestMatcher(getRequests, notFavIcon, notJson, notXRequestedWith); + + boolean isCsrfEnabled = http.getConfigurer(CsrfConfigurer.class) != null; + + List matchers = new ArrayList(); + if(isCsrfEnabled) { + RequestMatcher getRequests = new AntPathRequestMatcher("/**", "GET"); + matchers.add(0, getRequests); + } + matchers.add(notFavIcon); + matchers.add(notJson); + matchers.add(notXRequestedWith); + + return new AndRequestMatcher(matchers); } } diff --git a/config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.groovy b/config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.groovy index 270ee6cdd4..0659593487 100644 --- a/config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.groovy +++ b/config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.groovy @@ -102,6 +102,49 @@ class CsrfConfigurerTests extends BaseSpringSpec { } } + def "SEC-2498: Disable CSRF enables RequestCache for any method"() { + setup: + loadConfig(DisableCsrfEnablesRequestCacheConfig) + request.requestURI = '/tosave' + request.method = "POST" + clearCsrfToken() + when: + springSecurityFilterChain.doFilter(request,response,chain) + then: + response.redirectedUrl + when: + super.setupWeb(request.session) + request.method = "POST" + request.servletPath = '/login' + request.parameters['username'] = ['user'] as String[] + request.parameters['password'] = ['password'] as String[] + springSecurityFilterChain.doFilter(request,response,chain) + then: + response.redirectedUrl == 'http://localhost/tosave' + } + + @Configuration + @EnableWebSecurity + static class DisableCsrfEnablesRequestCacheConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .anyRequest().authenticated() + .and() + .formLogin().and() + .csrf().disable() + + } + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth + .inMemoryAuthentication() + .withUser("user").password("password").roles("USER") + } + } + def "SEC-2422: csrf expire CSRF token and session-management invalid-session-url"() { setup: loadConfig(InvalidSessionUrlConfig)