diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfiguration.java index 13d8148ce6..49228c0b8c 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfiguration.java @@ -44,7 +44,6 @@ import org.springframework.boot.autoconfigure.web.ErrorController; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.web.WebSecurityConfigurer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -106,7 +105,7 @@ public class ManagementSecurityAutoConfiguration { } // Get the ignored paths in early - @Order(Ordered.HIGHEST_PRECEDENCE + 1) + @Order(SecurityProperties.IGNORED_ORDER + 1) private static class IgnoredPathsWebSecurityConfigurerAdapter implements WebSecurityConfigurer { @@ -169,8 +168,7 @@ public class ManagementSecurityAutoConfiguration { @ConditionalOnMissingBean({ ManagementWebSecurityConfigurerAdapter.class }) @ConditionalOnExpression("${management.security.enabled:true}") @ConditionalOnWebApplication - // Give user-supplied filters a chance to be last in line - @Order(Ordered.LOWEST_PRECEDENCE - 10) + @Order(ManagementServerProperties.BASIC_AUTH_ORDER) protected static class ManagementWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementServerProperties.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementServerProperties.java index c76e385166..7b8b363237 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementServerProperties.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementServerProperties.java @@ -21,6 +21,7 @@ import java.net.InetAddress; import javax.validation.constraints.NotNull; import org.springframework.boot.autoconfigure.security.SecurityPrequisite; +import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.security.config.http.SessionCreationPolicy; @@ -37,6 +38,21 @@ public class ManagementServerProperties implements SecurityPrequisite { private static final String SECURITY_CHECK_CLASS = "org.springframework.security.config.http.SessionCreationPolicy"; + /** + * Order applied to the WebSecurityConfigurerAdapter that is used to configure basic + * authentication for management endpoints. If you want to add your own authentication + * for all or some of those endpoints the best thing to do is add your own + * WebSecurityConfigurerAdapter with lower order. + */ + public static final int BASIC_AUTH_ORDER = SecurityProperties.BASIC_AUTH_ORDER - 5; + + /** + * Order after the basic authentication access control provided automatically for the + * management endpoints. This is a useful place to put user-defined access rules if + * you want to override the default access rules. + */ + public static final int ACCESS_OVERRIDE_ORDER = ManagementServerProperties.BASIC_AUTH_ORDER - 1; + private Integer port; private InetAddress address; diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java index 794d58c674..a96a47d31a 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.UUID; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.core.Ordered; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.util.StringUtils; @@ -33,6 +34,27 @@ import org.springframework.util.StringUtils; @ConfigurationProperties(prefix = "security", ignoreUnknownFields = false) public class SecurityProperties implements SecurityPrequisite { + /** + * Order before the basic authentication access control provided by Boot. This is a + * useful place to put user-defined access rules if you want to override the default + * access rules. + */ + public static final int ACCESS_OVERRIDE_ORDER = SecurityProperties.BASIC_AUTH_ORDER - 1; + + /** + * Order applied to the WebSecurityConfigurerAdapter that is used to configure basic + * authentication for application endpoints. If you want to add your own + * authentication for all or some of those endpoints the best thing to do is add your + * own WebSecurityConfigurerAdapter with lower order. + */ + public static final int BASIC_AUTH_ORDER = Ordered.LOWEST_PRECEDENCE - 5; + + /** + * Order applied to the WebSecurityConfigurer that ignores standard static resource + * paths. + */ + public static final int IGNORED_ORDER = Ordered.HIGHEST_PRECEDENCE; + private boolean requireSsl; // Flip this when session creation is disabled by default diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java index edd77520cf..96cace1a72 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java @@ -155,7 +155,7 @@ public class SpringBootWebSecurityConfiguration { } // Get the ignored paths in early - @Order(Ordered.HIGHEST_PRECEDENCE) + @Order(SecurityProperties.IGNORED_ORDER) private static class IgnoredPathsWebSecurityConfigurerAdapter implements WebSecurityConfigurer { @@ -203,7 +203,7 @@ public class SpringBootWebSecurityConfiguration { @ConditionalOnExpression("${security.basic.enabled:true}") @Configuration - @Order(Ordered.LOWEST_PRECEDENCE - 5) + @Order(SecurityProperties.BASIC_AUTH_ORDER) protected static class ApplicationWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index ebe816a361..7b059968bb 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -1124,7 +1124,9 @@ The basic features you get out of the box in a web application are: on by default. All of the above can be switched on and off or modified using external properties -(`security.*`). +(`security.*`). To override the access rules without changing any other autoconfigured +features add a `@Bean` of type `WebConfigurerAdapter` with +`@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)`. If the Actuator is also in use, you will find: @@ -1133,7 +1135,12 @@ If the Actuator is also in use, you will find: * The default user will have the "ADMIN" role as well as the "USER" role. The Actuator security features can be modified using external properties -(`management.security.*`). +(`management.security.*`). To override the application access rules +add a `@Bean` of type `WebConfigurerAdapter` and use +`@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)` if you _don't_ want to override +the actuator access rules, or `@Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER)` +if you _do_ want to override the actuator access rules. + diff --git a/spring-boot-samples/spring-boot-sample-web-method-security/src/main/java/sample/ui/method/SampleMethodSecurityApplication.java b/spring-boot-samples/spring-boot-sample-web-method-security/src/main/java/sample/ui/method/SampleMethodSecurityApplication.java index 52e5bc1f86..3bbf1afb88 100644 --- a/spring-boot-samples/spring-boot-sample-web-method-security/src/main/java/sample/ui/method/SampleMethodSecurityApplication.java +++ b/spring-boot-samples/spring-boot-sample-web-method-security/src/main/java/sample/ui/method/SampleMethodSecurityApplication.java @@ -20,6 +20,7 @@ import java.util.Date; import java.util.Map; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -58,7 +59,8 @@ public class SampleMethodSecurityApplication extends WebMvcConfigurerAdapter { } public static void main(String[] args) throws Exception { - new SpringApplicationBuilder(SampleMethodSecurityApplication.class).run(args); + new SpringApplicationBuilder(SampleMethodSecurityApplication.class) + .run(args); } @Override @@ -74,29 +76,33 @@ public class SampleMethodSecurityApplication extends WebMvcConfigurerAdapter { @Order(Ordered.HIGHEST_PRECEDENCE) @Configuration - protected static class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter { - + protected static class AuthenticationSecurity extends + GlobalAuthenticationConfigurerAdapter { + @Override public void init(AuthenticationManagerBuilder auth) throws Exception { // @formatter:off auth.inMemoryAuthentication().withUser("admin").password("admin") - .roles("ADMIN", "USER").and().withUser("user").password("user") - .roles("USER"); + .roles("ADMIN", "USER").and().withUser("user") + .password("user").roles("USER"); // @formatter:on } } - - @Order(Ordered.LOWEST_PRECEDENCE - 8) - protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter { + + @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) + protected static class ApplicationSecurity extends + WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // @formatter:off - http.authorizeRequests().antMatchers("/login").permitAll().anyRequest() - .fullyAuthenticated().and().formLogin().loginPage("/login") - .failureUrl("/login?error").and().logout() - .logoutRequestMatcher(new AntPathRequestMatcher("/logout")).and() - .exceptionHandling().accessDeniedPage("/access?error"); + http.authorizeRequests().antMatchers("/login").permitAll() + .anyRequest().fullyAuthenticated().and().formLogin() + .loginPage("/login").failureUrl("/login?error").and() + .logout() + .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) + .and().exceptionHandling() + .accessDeniedPage("/access?error"); // @formatter:on } diff --git a/spring-boot-samples/spring-boot-sample-web-method-security/src/test/java/sample/ui/method/SampleMethodSecurityApplicationTests.java b/spring-boot-samples/spring-boot-sample-web-method-security/src/test/java/sample/ui/method/SampleMethodSecurityApplicationTests.java index 4db71ecf86..d8d219de94 100644 --- a/spring-boot-samples/spring-boot-sample-web-method-security/src/test/java/sample/ui/method/SampleMethodSecurityApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-web-method-security/src/test/java/sample/ui/method/SampleMethodSecurityApplicationTests.java @@ -16,6 +16,9 @@ package sample.ui.method; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -38,9 +41,6 @@ import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - /** * Basic integration tests for demo application. * diff --git a/spring-boot-samples/spring-boot-sample-web-secure/src/main/java/sample/ui/secure/SampleWebSecureApplication.java b/spring-boot-samples/spring-boot-sample-web-secure/src/main/java/sample/ui/secure/SampleWebSecureApplication.java index 139e696e03..747fd862b5 100644 --- a/spring-boot-samples/spring-boot-sample-web-secure/src/main/java/sample/ui/secure/SampleWebSecureApplication.java +++ b/spring-boot-samples/spring-boot-sample-web-secure/src/main/java/sample/ui/secure/SampleWebSecureApplication.java @@ -20,10 +20,10 @@ import java.util.Date; import java.util.Map; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; -import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @@ -52,8 +52,8 @@ public class SampleWebSecureApplication extends WebMvcConfigurerAdapter { public static void main(String[] args) throws Exception { // Set user password to "password" for demo purposes only - new SpringApplicationBuilder(SampleWebSecureApplication.class).properties( - "security.user.password=password").run(args); + new SpringApplicationBuilder(SampleWebSecureApplication.class) + .properties("security.user.password=password").run(args); } @Override @@ -66,12 +66,14 @@ public class SampleWebSecureApplication extends WebMvcConfigurerAdapter { return new ApplicationSecurity(); } - @Order(Ordered.LOWEST_PRECEDENCE - 8) - protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter { + @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) + protected static class ApplicationSecurity extends + WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { - http.authorizeRequests().anyRequest().fullyAuthenticated().and().formLogin() - .loginPage("/login").failureUrl("/login?error").permitAll(); + http.authorizeRequests().anyRequest().fullyAuthenticated().and() + .formLogin().loginPage("/login").failureUrl("/login?error") + .permitAll(); } }