瀏覽代碼

Disable XMLHttpRequest for formLogin entry point

Previously the following:

http http://localhost:8080/user \
  "X-Requested-With:XMLHttpRequest" "Accept:text/plain"

Produced a 302 instead of a 401

Fixes gh-3887
Rob Winch 9 年之前
父節點
當前提交
66858e22ad

+ 13 - 2
config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractAuthenticationFilterConfigurer.java

@@ -15,6 +15,7 @@
  */
 package org.springframework.security.config.annotation.web.configurers;
 
+import java.util.Arrays;
 import java.util.Collections;
 
 import javax.servlet.http.HttpServletRequest;
@@ -37,7 +38,10 @@ import org.springframework.security.web.authentication.SimpleUrlAuthenticationFa
 import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
 import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
 import org.springframework.security.web.util.matcher.RequestMatcher;
+import org.springframework.security.web.util.matcher.AndRequestMatcher;
 import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
+import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
 import org.springframework.web.accept.ContentNegotiationStrategy;
 import org.springframework.web.accept.HeaderContentNegotiationStrategy;
 
@@ -243,10 +247,17 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
 		if (contentNegotiationStrategy == null) {
 			contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
 		}
-		MediaTypeRequestMatcher preferredMatcher = new MediaTypeRequestMatcher(
+
+		MediaTypeRequestMatcher mediaMatcher = new MediaTypeRequestMatcher(
 				contentNegotiationStrategy, MediaType.APPLICATION_XHTML_XML,
 				new MediaType("image", "*"), MediaType.TEXT_HTML, MediaType.TEXT_PLAIN);
-		preferredMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
+		mediaMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
+
+		RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
+				new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
+
+		RequestMatcher preferredMatcher = new AndRequestMatcher(Arrays.asList(notXRequestedWith, mediaMatcher));
+
 		exceptionHandling.defaultAuthenticationEntryPointFor(
 				postProcess(authenticationEntryPoint), preferredMatcher);
 	}

+ 13 - 2
config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerTests.groovy

@@ -93,7 +93,18 @@ class ExceptionHandlingConfigurerTests extends BaseSpringSpec {
 		then:
 			def entryPoints = delegateEntryPoint.entryPoints.keySet() as List
 			entryPoints[0].requestMatchers[1].contentNegotiationStrategy.class == HeaderContentNegotiationStrategy
-			entryPoints[1].contentNegotiationStrategy.class == HeaderContentNegotiationStrategy
+			entryPoints[1].requestMatchers[1].contentNegotiationStrategy.class == HeaderContentNegotiationStrategy
+	}
+
+	def "401 for text/plain and X-Requested-With:XMLHttpRequest"() {
+		setup:
+			loadConfig(HttpBasicAndFormLoginEntryPointsConfig)
+		when:
+			request.addHeader("Accept", MediaType.TEXT_PLAIN_VALUE)
+			request.addHeader("X-Requested-With", "XMLHttpRequest")
+			springSecurityFilterChain.doFilter(request,response,chain)
+		then:
+			response.status == HttpServletResponse.SC_UNAUTHORIZED
 	}
 
 	@EnableWebSecurity
@@ -126,7 +137,7 @@ class ExceptionHandlingConfigurerTests extends BaseSpringSpec {
 			DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
 		then:
 			def entryPoints = delegateEntryPoint.entryPoints.keySet() as List
-			entryPoints[0].contentNegotiationStrategy == OverrideContentNegotiationStrategySharedObjectConfig.CNS
+			entryPoints[0].requestMatchers[1].contentNegotiationStrategy == OverrideContentNegotiationStrategySharedObjectConfig.CNS
 			entryPoints[1].requestMatchers[1].contentNegotiationStrategy == OverrideContentNegotiationStrategySharedObjectConfig.CNS
 	}