diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java index 4641195173a..e32db831418 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -26,12 +26,14 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.security.ConditionalOnDefaultWebSecurity; +import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration; import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration; import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain; @@ -46,6 +48,7 @@ import org.springframework.security.web.SecurityFilterChain; * of the custom security configuration. * * @author Madhura Bhave + * @author Hatef Palizgar * @since 2.1.0 */ @Configuration(proxyBeanMethods = false) @@ -58,6 +61,7 @@ import org.springframework.security.web.SecurityFilterChain; public class ManagementWebSecurityAutoConfiguration { @Bean + @Order(SecurityProperties.BASIC_AUTH_ORDER) SecurityFilterChain managementSecurityFilterChain(HttpSecurity http) throws Exception { http.authorizeRequests((requests) -> { requests.requestMatchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)).permitAll(); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java index 23e24f76932..3b6ffee813d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java @@ -17,6 +17,8 @@ package org.springframework.boot.actuate.autoconfigure.security.servlet; import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; import org.junit.jupiter.api.Test; @@ -27,6 +29,7 @@ import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAu import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration; import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; @@ -35,6 +38,7 @@ import org.springframework.boot.test.context.assertj.AssertableWebApplicationCon import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.mock.web.MockFilterChain; import org.springframework.mock.web.MockHttpServletRequest; @@ -45,6 +49,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.web.context.WebApplicationContext; import static org.assertj.core.api.Assertions.assertThat; @@ -53,6 +58,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link ManagementWebSecurityAutoConfiguration}. * * @author Madhura Bhave + * @author Hatef Palizgar */ class ManagementWebSecurityAutoConfigurationTests { @@ -121,7 +127,7 @@ class ManagementWebSecurityAutoConfigurationTests { @Test void backsOffIfSecurityFilterChainBeanIsPresent() { this.contextRunner.withUserConfiguration(TestSecurityFilterChainConfig.class).run((context) -> { - assertThat(context.getBeansOfType(SecurityFilterChain.class).size()).isEqualTo(1); + assertThat(context.getBeansOfType(SecurityFilterChain.class)).hasSize(1); assertThat(context.containsBean("testSecurityFilterChain")).isTrue(); }); } @@ -146,6 +152,21 @@ class ManagementWebSecurityAutoConfigurationTests { .doesNotHaveBean(MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN)); } + @Test + void backOffIfRemoteDevToolsSecurityFilterChainIsPresent() { + this.contextRunner.withUserConfiguration(TestRemoteDevToolsSecurityFilterChainConfig.class).run((context) -> { + SecurityFilterChain testSecurityFilterChain = context.getBean("testSecurityFilterChain", + SecurityFilterChain.class); + SecurityFilterChain testRemoteDevToolsSecurityFilterChain = context + .getBean("testRemoteDevToolsSecurityFilterChain", SecurityFilterChain.class); + List orderedSecurityFilterChains = context.getBeanProvider(SecurityFilterChain.class) + .orderedStream().collect(Collectors.toList()); + assertThat(orderedSecurityFilterChains).containsExactly(testRemoteDevToolsSecurityFilterChain, + testSecurityFilterChain); + assertThat(context).doesNotHaveBean(ManagementWebSecurityAutoConfiguration.class); + }); + } + private HttpStatus getResponseStatus(AssertableWebApplicationContext context, String path) throws IOException, javax.servlet.ServletException { FilterChainProxy filterChainProxy = context.getBean(FilterChainProxy.class); @@ -185,4 +206,16 @@ class ManagementWebSecurityAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class TestRemoteDevToolsSecurityFilterChainConfig extends TestSecurityFilterChainConfig { + + @Bean + @Order(SecurityProperties.BASIC_AUTH_ORDER - 1) + SecurityFilterChain testRemoteDevToolsSecurityFilterChain(HttpSecurity http) throws Exception { + return http.requestMatcher(new AntPathRequestMatcher("/**")).authorizeRequests().anyRequest().anonymous() + .and().csrf().disable().build(); + } + + } + }