Use IgnoredRequestCustomizer to ignore paths
Update `SpringBootWebSecurityConfiguration` to ignore requests by delegating to `IgnoredRequestCustomizer` beans. This allows a single Spring Boot `WebSecurityConfigurer<WebSecurity>` bean to be used which prevents potential exceptions caused by duplicate `@Order` values. Fixes gh-7106
This commit is contained in:
		
							parent
							
								
									d09aafacda
								
							
						
					
					
						commit
						95be208f0f
					
				| 
						 | 
				
			
			@ -26,7 +26,6 @@ import javax.annotation.PostConstruct;
 | 
			
		|||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.ObjectProvider;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.boot.actuate.endpoint.Endpoint;
 | 
			
		||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
 | 
			
		||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
 | 
			
		||||
| 
						 | 
				
			
			@ -42,11 +41,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
 | 
			
		|||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
 | 
			
		||||
import org.springframework.boot.autoconfigure.security.AuthenticationManagerConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.security.IgnoredRequestCustomizer;
 | 
			
		||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.security.SecurityPrerequisite;
 | 
			
		||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
 | 
			
		||||
import org.springframework.boot.autoconfigure.security.SpringBootWebSecurityConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.web.ErrorController;
 | 
			
		||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
 | 
			
		||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
| 
						 | 
				
			
			@ -56,9 +55,7 @@ import org.springframework.context.annotation.Conditional;
 | 
			
		|||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.core.annotation.Order;
 | 
			
		||||
import org.springframework.core.type.AnnotatedTypeMetadata;
 | 
			
		||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
 | 
			
		||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 | 
			
		||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
 | 
			
		||||
import org.springframework.security.config.annotation.web.builders.WebSecurity.IgnoredRequestConfigurer;
 | 
			
		||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 | 
			
		||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +69,6 @@ import org.springframework.security.web.util.matcher.AnyRequestMatcher;
 | 
			
		|||
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
 | 
			
		||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
 | 
			
		||||
import org.springframework.security.web.util.matcher.RequestMatcher;
 | 
			
		||||
import org.springframework.util.ObjectUtils;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -102,9 +98,34 @@ public class ManagementWebSecurityAutoConfiguration {
 | 
			
		|||
			AnyRequestMatcher.INSTANCE);
 | 
			
		||||
 | 
			
		||||
	@Bean
 | 
			
		||||
	@ConditionalOnMissingBean({ IgnoredPathsWebSecurityConfigurerAdapter.class })
 | 
			
		||||
	public IgnoredPathsWebSecurityConfigurerAdapter ignoredPathsWebSecurityConfigurerAdapter() {
 | 
			
		||||
		return new IgnoredPathsWebSecurityConfigurerAdapter();
 | 
			
		||||
	public IgnoredRequestCustomizer managementIgnoredRequestCustomizer(
 | 
			
		||||
			ManagementServerProperties management,
 | 
			
		||||
			ObjectProvider<ManagementContextResolver> contextResolverProvider) {
 | 
			
		||||
		return new ManagementIgnoredRequestCustomizer(management,
 | 
			
		||||
				contextResolverProvider.getIfAvailable());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private class ManagementIgnoredRequestCustomizer implements IgnoredRequestCustomizer {
 | 
			
		||||
 | 
			
		||||
		private final ManagementServerProperties management;
 | 
			
		||||
 | 
			
		||||
		private final ManagementContextResolver contextResolver;
 | 
			
		||||
 | 
			
		||||
		ManagementIgnoredRequestCustomizer(ManagementServerProperties management,
 | 
			
		||||
				ManagementContextResolver contextResolver) {
 | 
			
		||||
			this.management = management;
 | 
			
		||||
			this.contextResolver = contextResolver;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void customize(IgnoredRequestConfigurer configurer) {
 | 
			
		||||
			if (!this.management.getSecurity().isEnabled()) {
 | 
			
		||||
				RequestMatcher requestMatcher = LazyEndpointPathRequestMatcher
 | 
			
		||||
						.getRequestMatcher(this.contextResolver);
 | 
			
		||||
				configurer.requestMatchers(requestMatcher);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Configuration
 | 
			
		||||
| 
						 | 
				
			
			@ -132,80 +153,6 @@ public class ManagementWebSecurityAutoConfiguration {
 | 
			
		|||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get the ignored paths in early
 | 
			
		||||
	@Order(SecurityProperties.IGNORED_ORDER + 1)
 | 
			
		||||
	private static class IgnoredPathsWebSecurityConfigurerAdapter
 | 
			
		||||
			implements WebSecurityConfigurer<WebSecurity> {
 | 
			
		||||
 | 
			
		||||
		@Autowired(required = false)
 | 
			
		||||
		private ErrorController errorController;
 | 
			
		||||
 | 
			
		||||
		@Autowired
 | 
			
		||||
		private SecurityProperties security;
 | 
			
		||||
 | 
			
		||||
		@Autowired
 | 
			
		||||
		private ManagementServerProperties management;
 | 
			
		||||
 | 
			
		||||
		@Autowired(required = false)
 | 
			
		||||
		private ManagementContextResolver contextResolver;
 | 
			
		||||
 | 
			
		||||
		@Autowired(required = false)
 | 
			
		||||
		private ServerProperties server;
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void configure(WebSecurity builder) throws Exception {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void init(WebSecurity builder) throws Exception {
 | 
			
		||||
			if (this.server == null) {
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			IgnoredRequestConfigurer ignoring = builder.ignoring();
 | 
			
		||||
			// The ignores are not cumulative, so to prevent overwriting the defaults
 | 
			
		||||
			// we add them back.
 | 
			
		||||
			Set<String> ignored = new LinkedHashSet<String>(
 | 
			
		||||
					SpringBootWebSecurityConfiguration.getIgnored(this.security));
 | 
			
		||||
			if (ignored.contains("none")) {
 | 
			
		||||
				ignored.remove("none");
 | 
			
		||||
			}
 | 
			
		||||
			if (this.errorController != null) {
 | 
			
		||||
				ignored.add(normalizePath(this.errorController.getErrorPath()));
 | 
			
		||||
			}
 | 
			
		||||
			RequestMatcher requestMatcher = getRequestMatcher();
 | 
			
		||||
			String[] paths = this.server.getPathsArray(ignored);
 | 
			
		||||
			if (!ObjectUtils.isEmpty(paths)) {
 | 
			
		||||
				List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
 | 
			
		||||
				for (String pattern : paths) {
 | 
			
		||||
					matchers.add(new AntPathRequestMatcher(pattern, null));
 | 
			
		||||
				}
 | 
			
		||||
				if (requestMatcher != null) {
 | 
			
		||||
					matchers.add(requestMatcher);
 | 
			
		||||
				}
 | 
			
		||||
				requestMatcher = new OrRequestMatcher(matchers);
 | 
			
		||||
			}
 | 
			
		||||
			if (requestMatcher != null) {
 | 
			
		||||
				ignoring.requestMatchers(requestMatcher);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private RequestMatcher getRequestMatcher() {
 | 
			
		||||
			if (this.management.getSecurity().isEnabled()) {
 | 
			
		||||
				return null;
 | 
			
		||||
			}
 | 
			
		||||
			return LazyEndpointPathRequestMatcher.getRequestMatcher(this.contextResolver);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private String normalizePath(String errorPath) {
 | 
			
		||||
			String result = StringUtils.cleanPath(errorPath);
 | 
			
		||||
			if (!result.startsWith("/")) {
 | 
			
		||||
				result = "/" + result;
 | 
			
		||||
			}
 | 
			
		||||
			return result;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Configuration
 | 
			
		||||
	@ConditionalOnMissingBean(WebSecurityConfiguration.class)
 | 
			
		||||
	@Conditional(WebSecurityEnablerCondition.class)
 | 
			
		||||
| 
						 | 
				
			
			@ -310,9 +257,7 @@ public class ManagementWebSecurityAutoConfiguration {
 | 
			
		|||
			// Permit access to the non-sensitive endpoints
 | 
			
		||||
			requests.requestMatchers(new LazyEndpointPathRequestMatcher(
 | 
			
		||||
					this.contextResolver, EndpointPaths.NON_SENSITIVE)).permitAll();
 | 
			
		||||
			// Restrict the rest to the configured roles
 | 
			
		||||
			List<String> roles = this.management.getSecurity().getRoles();
 | 
			
		||||
			requests.anyRequest().hasAnyRole(roles.toArray(new String[roles.size()]));
 | 
			
		||||
			requests.anyRequest().authenticated();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,12 +28,15 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 | 
			
		|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform;
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 | 
			
		||||
import org.springframework.boot.autoconfigure.security.IgnoredRequestCustomizer;
 | 
			
		||||
import org.springframework.boot.cloud.CloudPlatform;
 | 
			
		||||
import org.springframework.boot.web.client.RestTemplateBuilder;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.core.env.Environment;
 | 
			
		||||
import org.springframework.http.HttpMethod;
 | 
			
		||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
 | 
			
		||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 | 
			
		||||
import org.springframework.web.cors.CorsConfiguration;
 | 
			
		||||
import org.springframework.web.servlet.HandlerInterceptor;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -95,4 +98,20 @@ public class CloudFoundryActuatorAutoConfiguration {
 | 
			
		|||
		return corsConfiguration;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Bean
 | 
			
		||||
	public IgnoredRequestCustomizer cloudFoundryIgnoredRequestCustomizer() {
 | 
			
		||||
		return new CloudFoundryIgnoredRequestCustomizer();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private class CloudFoundryIgnoredRequestCustomizer
 | 
			
		||||
			implements IgnoredRequestCustomizer {
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void customize(WebSecurity.IgnoredRequestConfigurer configurer) {
 | 
			
		||||
			configurer.requestMatchers(
 | 
			
		||||
					new AntPathRequestMatcher("/cloudfoundryapplication/**"));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,7 @@ import java.util.Arrays;
 | 
			
		|||
import org.junit.After;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.mockito.ArgumentCaptor;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
 | 
			
		||||
| 
						 | 
				
			
			@ -29,18 +30,24 @@ import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties
 | 
			
		|||
import org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.security.IgnoredRequestCustomizer;
 | 
			
		||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.test.util.EnvironmentTestUtils;
 | 
			
		||||
import org.springframework.http.HttpMethod;
 | 
			
		||||
import org.springframework.mock.web.MockHttpServletRequest;
 | 
			
		||||
import org.springframework.mock.web.MockServletContext;
 | 
			
		||||
import org.springframework.security.config.annotation.web.builders.WebSecurity.IgnoredRequestConfigurer;
 | 
			
		||||
import org.springframework.security.web.util.matcher.RequestMatcher;
 | 
			
		||||
import org.springframework.test.util.ReflectionTestUtils;
 | 
			
		||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
 | 
			
		||||
import org.springframework.web.cors.CorsConfiguration;
 | 
			
		||||
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
import static org.mockito.Mockito.verify;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests for {@link CloudFoundryActuatorAutoConfiguration}.
 | 
			
		||||
| 
						 | 
				
			
			@ -116,10 +123,9 @@ public class CloudFoundryActuatorAutoConfigurationTests {
 | 
			
		|||
		EnvironmentTestUtils.addEnvironment(this.context, "VCAP_APPLICATION:---",
 | 
			
		||||
				"vcap.application.application_id:my-app-id");
 | 
			
		||||
		this.context.refresh();
 | 
			
		||||
		CloudFoundryEndpointHandlerMapping handlerMapping1 = this.context.getBean(
 | 
			
		||||
		CloudFoundryEndpointHandlerMapping handlerMapping = this.context.getBean(
 | 
			
		||||
				"cloudFoundryEndpointHandlerMapping",
 | 
			
		||||
				CloudFoundryEndpointHandlerMapping.class);
 | 
			
		||||
		CloudFoundryEndpointHandlerMapping handlerMapping = handlerMapping1;
 | 
			
		||||
		Object securityInterceptor = ReflectionTestUtils.getField(handlerMapping,
 | 
			
		||||
				"securityInterceptor");
 | 
			
		||||
		Object interceptorSecurityService = ReflectionTestUtils
 | 
			
		||||
| 
						 | 
				
			
			@ -127,13 +133,24 @@ public class CloudFoundryActuatorAutoConfigurationTests {
 | 
			
		|||
		assertThat(interceptorSecurityService).isNull();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private CloudFoundryEndpointHandlerMapping getHandlerMapping() {
 | 
			
		||||
	@Test
 | 
			
		||||
	public void cloudFoundryPathsIgnoredBySpringSecurity() throws Exception {
 | 
			
		||||
		EnvironmentTestUtils.addEnvironment(this.context, "VCAP_APPLICATION:---",
 | 
			
		||||
				"vcap.application.application_id:my-app-id",
 | 
			
		||||
				"vcap.application.cf_api:http://my-cloud-controller.com");
 | 
			
		||||
				"vcap.application.application_id:my-app-id");
 | 
			
		||||
		this.context.refresh();
 | 
			
		||||
		return this.context.getBean("cloudFoundryEndpointHandlerMapping",
 | 
			
		||||
				CloudFoundryEndpointHandlerMapping.class);
 | 
			
		||||
		IgnoredRequestCustomizer customizer = (IgnoredRequestCustomizer) this.context
 | 
			
		||||
				.getBean("cloudFoundryIgnoredRequestCustomizer");
 | 
			
		||||
		IgnoredRequestConfigurer configurer = mock(IgnoredRequestConfigurer.class);
 | 
			
		||||
		customizer.customize(configurer);
 | 
			
		||||
		ArgumentCaptor<RequestMatcher> requestMatcher = ArgumentCaptor
 | 
			
		||||
				.forClass(RequestMatcher.class);
 | 
			
		||||
		verify(configurer).requestMatchers(requestMatcher.capture());
 | 
			
		||||
		RequestMatcher matcher = requestMatcher.getValue();
 | 
			
		||||
		MockHttpServletRequest request = new MockHttpServletRequest();
 | 
			
		||||
		request.setServletPath("/cloudfoundryapplication/my-path");
 | 
			
		||||
		assertThat(matcher.matches(request)).isTrue();
 | 
			
		||||
		request.setServletPath("/some-other-path");
 | 
			
		||||
		assertThat(matcher.matches(request)).isFalse();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -152,4 +169,13 @@ public class CloudFoundryActuatorAutoConfigurationTests {
 | 
			
		|||
				.isFalse();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private CloudFoundryEndpointHandlerMapping getHandlerMapping() {
 | 
			
		||||
		EnvironmentTestUtils.addEnvironment(this.context, "VCAP_APPLICATION:---",
 | 
			
		||||
				"vcap.application.application_id:my-app-id",
 | 
			
		||||
				"vcap.application.cf_api:http://my-cloud-controller.com");
 | 
			
		||||
		this.context.refresh();
 | 
			
		||||
		return this.context.getBean("cloudFoundryEndpointHandlerMapping",
 | 
			
		||||
				CloudFoundryEndpointHandlerMapping.class);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012-2016 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.boot.autoconfigure.security;
 | 
			
		||||
 | 
			
		||||
import org.springframework.security.config.annotation.web.builders.WebSecurity.IgnoredRequestConfigurer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Customizer that can be implemented by beans to configure paths that need to be ignored
 | 
			
		||||
 * by Spring Boot's default Spring Security configuration.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Madhura Bhave
 | 
			
		||||
 * @since 1.5.0
 | 
			
		||||
 */
 | 
			
		||||
public interface IgnoredRequestCustomizer {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Customize the provided {@link IgnoredRequestConfigurer}.
 | 
			
		||||
	 * @param configurer the configurer to customize
 | 
			
		||||
	 */
 | 
			
		||||
	void customize(IgnoredRequestConfigurer configurer);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ import java.util.List;
 | 
			
		|||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.beans.factory.ObjectProvider;
 | 
			
		||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +41,7 @@ import org.springframework.security.config.annotation.authentication.builders.Au
 | 
			
		|||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
 | 
			
		||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 | 
			
		||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
 | 
			
		||||
import org.springframework.security.config.annotation.web.builders.WebSecurity.IgnoredRequestConfigurer;
 | 
			
		||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 | 
			
		||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
 | 
			
		||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +49,9 @@ import org.springframework.security.config.annotation.web.configurers.HeadersCon
 | 
			
		|||
import org.springframework.security.web.AuthenticationEntryPoint;
 | 
			
		||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
 | 
			
		||||
import org.springframework.security.web.header.writers.HstsHeaderWriter;
 | 
			
		||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 | 
			
		||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
 | 
			
		||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
 | 
			
		||||
import org.springframework.security.web.util.matcher.RequestMatcher;
 | 
			
		||||
import org.springframework.util.ObjectUtils;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
| 
						 | 
				
			
			@ -94,8 +97,17 @@ public class SpringBootWebSecurityConfiguration {
 | 
			
		|||
 | 
			
		||||
	@Bean
 | 
			
		||||
	@ConditionalOnMissingBean({ IgnoredPathsWebSecurityConfigurerAdapter.class })
 | 
			
		||||
	public IgnoredPathsWebSecurityConfigurerAdapter ignoredPathsWebSecurityConfigurerAdapter() {
 | 
			
		||||
		return new IgnoredPathsWebSecurityConfigurerAdapter();
 | 
			
		||||
	public IgnoredPathsWebSecurityConfigurerAdapter ignoredPathsWebSecurityConfigurerAdapter(
 | 
			
		||||
			List<IgnoredRequestCustomizer> customizers) {
 | 
			
		||||
		return new IgnoredPathsWebSecurityConfigurerAdapter(customizers);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Bean
 | 
			
		||||
	public IgnoredRequestCustomizer defaultIgnoredRequestsCustomizer(
 | 
			
		||||
			ServerProperties server, SecurityProperties security,
 | 
			
		||||
			ObjectProvider<ErrorController> errorController) {
 | 
			
		||||
		return new DefaultIgnoredRequestCustomizer(server, security,
 | 
			
		||||
				errorController.getIfAvailable());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static void configureHeaders(HeadersConfigurer<?> configurer,
 | 
			
		||||
| 
						 | 
				
			
			@ -146,14 +158,12 @@ public class SpringBootWebSecurityConfiguration {
 | 
			
		|||
	private static class IgnoredPathsWebSecurityConfigurerAdapter
 | 
			
		||||
			implements WebSecurityConfigurer<WebSecurity> {
 | 
			
		||||
 | 
			
		||||
		@Autowired(required = false)
 | 
			
		||||
		private ErrorController errorController;
 | 
			
		||||
		private final List<IgnoredRequestCustomizer> customizers;
 | 
			
		||||
 | 
			
		||||
		@Autowired
 | 
			
		||||
		private SecurityProperties security;
 | 
			
		||||
 | 
			
		||||
		@Autowired
 | 
			
		||||
		private ServerProperties server;
 | 
			
		||||
		IgnoredPathsWebSecurityConfigurerAdapter(
 | 
			
		||||
				List<IgnoredRequestCustomizer> customizers) {
 | 
			
		||||
			this.customizers = customizers;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void configure(WebSecurity builder) throws Exception {
 | 
			
		||||
| 
						 | 
				
			
			@ -161,15 +171,56 @@ public class SpringBootWebSecurityConfiguration {
 | 
			
		|||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void init(WebSecurity builder) throws Exception {
 | 
			
		||||
			for (IgnoredRequestCustomizer customizer : this.customizers) {
 | 
			
		||||
				customizer.customize(builder.ignoring());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private class DefaultIgnoredRequestCustomizer implements IgnoredRequestCustomizer {
 | 
			
		||||
 | 
			
		||||
		private final ServerProperties server;
 | 
			
		||||
 | 
			
		||||
		private final SecurityProperties security;
 | 
			
		||||
 | 
			
		||||
		private final ErrorController errorController;
 | 
			
		||||
 | 
			
		||||
		DefaultIgnoredRequestCustomizer(ServerProperties server,
 | 
			
		||||
				SecurityProperties security, ErrorController errorController) {
 | 
			
		||||
			this.server = server;
 | 
			
		||||
			this.security = security;
 | 
			
		||||
			this.errorController = errorController;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void customize(IgnoredRequestConfigurer configurer) {
 | 
			
		||||
			List<String> ignored = getIgnored(this.security);
 | 
			
		||||
			if (this.errorController != null) {
 | 
			
		||||
				ignored.add(normalizePath(this.errorController.getErrorPath()));
 | 
			
		||||
			}
 | 
			
		||||
			String[] paths = this.server.getPathsArray(ignored);
 | 
			
		||||
			List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
 | 
			
		||||
			if (!ObjectUtils.isEmpty(paths)) {
 | 
			
		||||
				builder.ignoring().antMatchers(paths);
 | 
			
		||||
				for (String pattern : paths) {
 | 
			
		||||
					matchers.add(new AntPathRequestMatcher(pattern, null));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (!matchers.isEmpty()) {
 | 
			
		||||
				configurer.requestMatchers(new OrRequestMatcher(matchers));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private List<String> getIgnored(SecurityProperties security) {
 | 
			
		||||
			List<String> ignored = new ArrayList<String>(security.getIgnored());
 | 
			
		||||
			if (ignored.isEmpty()) {
 | 
			
		||||
				ignored.addAll(DEFAULT_IGNORED);
 | 
			
		||||
			}
 | 
			
		||||
			else if (ignored.contains("none")) {
 | 
			
		||||
				ignored.remove("none");
 | 
			
		||||
			}
 | 
			
		||||
			return ignored;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private String normalizePath(String errorPath) {
 | 
			
		||||
			String result = StringUtils.cleanPath(errorPath);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -90,9 +90,9 @@ public class SecurityAutoConfigurationTests {
 | 
			
		|||
				PropertyPlaceholderAutoConfiguration.class);
 | 
			
		||||
		this.context.refresh();
 | 
			
		||||
		assertThat(this.context.getBean(AuthenticationManagerBuilder.class)).isNotNull();
 | 
			
		||||
		// 5 for static resources and one for the rest
 | 
			
		||||
		// 1 for static resources and one for the rest
 | 
			
		||||
		assertThat(this.context.getBean(FilterChainProxy.class).getFilterChains())
 | 
			
		||||
				.hasSize(6);
 | 
			
		||||
				.hasSize(2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,6 @@ import java.lang.annotation.ElementType;
 | 
			
		|||
import java.lang.annotation.Retention;
 | 
			
		||||
import java.lang.annotation.RetentionPolicy;
 | 
			
		||||
import java.lang.annotation.Target;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.Filter;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -84,13 +83,6 @@ public class SpringBootWebSecurityConfigurationTests {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testDefaultIgnores() {
 | 
			
		||||
		List<String> ignored = SpringBootWebSecurityConfiguration
 | 
			
		||||
				.getIgnored(new SecurityProperties());
 | 
			
		||||
		assertThat(ignored).contains("/css/**");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testWebConfigurationOverrideGlobalAuthentication() throws Exception {
 | 
			
		||||
		this.context = SpringApplication.run(TestWebConfiguration.class,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue