RequestCache ignores multipart requests

Fixes gh-7060
This commit is contained in:
Rob Winch 2019-08-15 09:21:03 -05:00
commit 71444ff5dc
2 changed files with 31 additions and 12 deletions

View File

@ -142,22 +142,12 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
return null; return null;
} }
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private RequestMatcher createDefaultSavedRequestMatcher(H http) { private RequestMatcher createDefaultSavedRequestMatcher(H http) {
ContentNegotiationStrategy contentNegotiationStrategy = http
.getSharedObject(ContentNegotiationStrategy.class);
if (contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
RequestMatcher notFavIcon = new NegatedRequestMatcher(new AntPathRequestMatcher( RequestMatcher notFavIcon = new NegatedRequestMatcher(new AntPathRequestMatcher(
"/**/favicon.*")); "/**/favicon.*"));
MediaTypeRequestMatcher jsonRequest = new MediaTypeRequestMatcher(
contentNegotiationStrategy, MediaType.APPLICATION_JSON);
jsonRequest.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
RequestMatcher notJson = new NegatedRequestMatcher(jsonRequest);
RequestMatcher notXRequestedWith = new NegatedRequestMatcher( RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest")); new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
@ -169,9 +159,21 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
matchers.add(0, getRequests); matchers.add(0, getRequests);
} }
matchers.add(notFavIcon); matchers.add(notFavIcon);
matchers.add(notJson); matchers.add(notMatchingMediaType(http, MediaType.APPLICATION_JSON));
matchers.add(notXRequestedWith); matchers.add(notXRequestedWith);
matchers.add(notMatchingMediaType(http, MediaType.MULTIPART_FORM_DATA));
return new AndRequestMatcher(matchers); return new AndRequestMatcher(matchers);
} }
private RequestMatcher notMatchingMediaType(H http, MediaType mediaType) {
ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);
if (contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
MediaTypeRequestMatcher mediaRequest = new MediaTypeRequestMatcher(contentNegotiationStrategy, mediaType);
mediaRequest.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
return new NegatedRequestMatcher(mediaRequest);
}
} }

View File

@ -26,6 +26,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpSession; import org.springframework.mock.web.MockHttpSession;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.security.config.annotation.ObjectPostProcessor; import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@ -47,6 +48,7 @@ import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
/** /**
@ -264,6 +266,21 @@ public class RequestCacheConfigurerTests {
.andExpect(redirectedUrl("/")); .andExpect(redirectedUrl("/"));
} }
// SEC-7060
@Test
public void postWhenRequestIsMultipartThenPostAuthenticationRedirectsToRoot() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
MockMultipartFile aFile = new MockMultipartFile("aFile", "A_FILE".getBytes());
MockHttpSession session = (MockHttpSession)
this.mvc.perform(multipart("/upload")
.file(aFile))
.andReturn().getRequest().getSession();
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
@EnableWebSecurity @EnableWebSecurity
static class RequestCacheDisabledConfig extends WebSecurityConfigurerAdapter { static class RequestCacheDisabledConfig extends WebSecurityConfigurerAdapter {
@Override @Override