Jelajahi Sumber

No RequestMatcher After AnyRequest

Don't allow any type of RequestMatchers
after any request by throwing IllegalStateException

Fixes: gh-6359
Ankur Pathak 6 tahun lalu
induk
melakukan
8e6bcc1c35

+ 15 - 3
config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 import org.springframework.security.web.util.matcher.AnyRequestMatcher;
 import org.springframework.security.web.util.matcher.RegexRequestMatcher;
 import org.springframework.security.web.util.matcher.RequestMatcher;
+import org.springframework.util.Assert;
 import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
 
 import java.util.ArrayList;
@@ -39,6 +40,7 @@ import java.util.List;
  * @param <C> The object that is returned or Chained after creating the RequestMatcher
  *
  * @author Rob Winch
+ * @author Ankur Pathak
  * @since 3.2
  */
 public abstract class AbstractRequestMatcherRegistry<C> {
@@ -48,6 +50,8 @@ public abstract class AbstractRequestMatcherRegistry<C> {
 
 	private ApplicationContext context;
 
+	private boolean anyRequestConfigured = false;
+
 	protected final void setApplicationContext(ApplicationContext context) {
 		this.context = context;
 	}
@@ -67,7 +71,10 @@ public abstract class AbstractRequestMatcherRegistry<C> {
 	 * @return the object that is chained after creating the {@link RequestMatcher}
 	 */
 	public C anyRequest() {
-		return requestMatchers(ANY_REQUEST);
+		Assert.state(!this.anyRequestConfigured, "Can't configure anyRequest after itself");
+		C configurer = requestMatchers(ANY_REQUEST);
+		this.anyRequestConfigured = true;
+		return configurer;
 	}
 
 	/**
@@ -97,6 +104,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
 	 * @return the object that is chained after creating the {@link RequestMatcher}
 	 */
 	public C antMatchers(HttpMethod method, String... antPatterns) {
+		Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
 		return chainRequestMatchers(RequestMatchers.antMatchers(method, antPatterns));
 	}
 
@@ -111,6 +119,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
 	 * @return the object that is chained after creating the {@link RequestMatcher}
 	 */
 	public C antMatchers(String... antPatterns) {
+		Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
 		return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
 	}
 
@@ -160,7 +169,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
 	 */
 	protected final List<MvcRequestMatcher> createMvcMatchers(HttpMethod method,
 			String... mvcPatterns) {
-
+		Assert.state(!this.anyRequestConfigured, "Can't configure mvcMatchers after anyRequest");
 		ObjectPostProcessor<Object> opp = this.context.getBean(ObjectPostProcessor.class);
 		if (!this.context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
 			throw new NoSuchBeanDefinitionException("A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME +" of type " + HandlerMappingIntrospector.class.getName()
@@ -195,6 +204,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
 	 * @return the object that is chained after creating the {@link RequestMatcher}
 	 */
 	public C regexMatchers(HttpMethod method, String... regexPatterns) {
+		Assert.state(!this.anyRequestConfigured, "Can't configure regexMatchers after anyRequest");
 		return chainRequestMatchers(RequestMatchers.regexMatchers(method, regexPatterns));
 	}
 
@@ -209,6 +219,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
 	 * @return the object that is chained after creating the {@link RequestMatcher}
 	 */
 	public C regexMatchers(String... regexPatterns) {
+		Assert.state(!this.anyRequestConfigured, "Can't configure regexMatchers after anyRequest");
 		return chainRequestMatchers(RequestMatchers.regexMatchers(regexPatterns));
 	}
 
@@ -221,6 +232,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
 	 * @return the object that is chained after creating the {@link RequestMatcher}
 	 */
 	public C requestMatchers(RequestMatcher... requestMatchers) {
+		Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest");
 		return chainRequestMatchers(Arrays.asList(requestMatchers));
 	}
 

+ 122 - 0
config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java

@@ -0,0 +1,122 @@
+/*
+ * Copyright 2002-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.config.annotation.web;
+
+import org.junit.Test;
+
+import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.mock.web.MockServletContext;
+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.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+
+/**
+ * Tests for {@link AbstractRequestMatcherRegistry}.
+ *
+ * @author Ankur Pathak
+ */
+public class AbstractRequestMatcherRegistryAnyMatcherTests{
+
+	@EnableWebSecurity
+	static class AntMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter {
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.authorizeRequests()
+				.anyRequest().authenticated()
+				.antMatchers("/demo/**").permitAll();
+
+		}
+	}
+
+	@Test(expected = BeanCreationException.class)
+	public void antMatchersCanNotWorkAfterAnyRequest(){
+		loadConfig(AntMatchersAfterAnyRequestConfig.class);
+	}
+
+	@EnableWebSecurity
+	static class MvcMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter {
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.authorizeRequests()
+				.anyRequest().authenticated()
+				.mvcMatchers("/demo/**").permitAll();
+
+		}
+	}
+
+	@Test(expected = BeanCreationException.class)
+	public void mvcMatchersCanNotWorkAfterAnyRequest() {
+		loadConfig(MvcMatchersAfterAnyRequestConfig.class);
+	}
+
+	@EnableWebSecurity
+	static class RegexMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter {
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.authorizeRequests()
+				.anyRequest().authenticated()
+				.regexMatchers(".*").permitAll();
+
+		}
+	}
+
+	@Test(expected = BeanCreationException.class)
+	public void regexMatchersCanNotWorkAfterAnyRequest() {
+		loadConfig(RegexMatchersAfterAnyRequestConfig.class);
+	}
+
+	@EnableWebSecurity
+	static class AnyRequestAfterItselfConfig extends WebSecurityConfigurerAdapter {
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.authorizeRequests()
+				.anyRequest().authenticated()
+				.anyRequest().permitAll();
+
+		}
+	}
+
+	@Test(expected = BeanCreationException.class)
+	public void anyRequestCanNotWorkAfterItself() {
+		loadConfig(AnyRequestAfterItselfConfig.class);
+	}
+
+	@EnableWebSecurity
+	static class RequestMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter {
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.authorizeRequests()
+				.anyRequest().authenticated()
+				.requestMatchers(new AntPathRequestMatcher("/**")).permitAll();
+
+		}
+	}
+
+	@Test(expected = BeanCreationException.class)
+	public void requestMatchersCanNotWorkAfterAnyRequest() {
+		loadConfig(RequestMatchersAfterAnyRequestConfig.class);
+	}
+
+	private void loadConfig(Class<?>... configs) {
+		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
+		context.setAllowCircularReferences(false);
+		context.register(configs);
+		context.setServletContext(new MockServletContext());
+		context.refresh();
+	}
+}