From 14d3b468093c6bc946f75449273070af9aa02098 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 7 May 2014 14:41:35 -0700 Subject: [PATCH] Add constants to SecurityProperties and ManagementServerProperties For the convenience of users who want to selectively override the access rules in an application without taking complete control of the security configuration we now have some constants: * SecurityProperties.ACCESS_OVERRIDE_ORDER for overriding just the application endpoint access rules * ManagementServerProperties.ACCESS_OVERRIDE_ORDER for overriding the application endpoint and management endpoint access rules Fixes gh-803 --- .../ManagementSecurityAutoConfiguration.java | 6 ++-- .../ManagementServerProperties.java | 16 ++++++++++ .../security/SecurityProperties.java | 22 +++++++++++++ .../SpringBootWebSecurityConfiguration.java | 4 +-- .../main/asciidoc/spring-boot-features.adoc | 11 +++++-- .../SampleMethodSecurityApplication.java | 32 +++++++++++-------- .../SampleMethodSecurityApplicationTests.java | 6 ++-- .../ui/secure/SampleWebSecureApplication.java | 16 ++++++---- 8 files changed, 82 insertions(+), 31 deletions(-) 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(); } }