From 20fa1b3b483d375f8bb15bbe2b9c0a83addfe209 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Wed, 3 Feb 2016 08:04:52 +0100 Subject: [PATCH 1/2] Support configuration of multiple management roles Closes gh-5045 --- .../actuate/autoconfigure/CrshAutoConfiguration.java | 4 ++-- .../autoconfigure/ManagementServerProperties.java | 12 ++++++++---- .../ManagementWebSecurityAutoConfiguration.java | 7 ++++--- .../asciidoc/appendix-application-properties.adoc | 2 +- .../src/main/asciidoc/production-ready-features.adoc | 2 +- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfiguration.java index f7fc6dd765..235aa88572 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfiguration.java @@ -196,8 +196,8 @@ public class CrshAutoConfiguration { // overridden by ConfigurationProperties. SpringAuthenticationProperties authenticationProperties = new SpringAuthenticationProperties(); if (this.management != null) { - authenticationProperties.setRoles( - new String[] { this.management.getSecurity().getRole() }); + List roles = this.management.getSecurity().getRole(); + authenticationProperties.setRoles(roles.toArray(new String[roles.size()])); } return authenticationProperties; } 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 f53f3d4fe5..db13dd5ebd 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 @@ -17,6 +17,9 @@ package org.springframework.boot.actuate.autoconfigure; import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import javax.validation.constraints.NotNull; @@ -33,6 +36,7 @@ import org.springframework.util.StringUtils; * * @author Dave Syer * @author Stephane Nicoll + * @author Vedran Pavic * @see ServerProperties */ @ConfigurationProperties(prefix = "management", ignoreUnknownFields = true) @@ -160,9 +164,9 @@ public class ManagementServerProperties implements SecurityPrerequisite { private boolean enabled = true; /** - * Role required to access the management endpoint. + * Roles required to access the management endpoint. */ - private String role = "ADMIN"; + private List role = new ArrayList(Arrays.asList("ADMIN")); /** * Session creating policy to use (always, never, if_required, stateless). @@ -177,11 +181,11 @@ public class ManagementServerProperties implements SecurityPrerequisite { this.sessions = sessions; } - public void setRole(String role) { + public void setRole(List role) { this.role = role; } - public String getRole() { + public List getRole() { return this.role; } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java index a4f5ab2be8..4030250622 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java @@ -124,7 +124,7 @@ public class ManagementWebSecurityAutoConfiguration { public void init() { if (this.management != null && this.security != null) { this.security.getUser().getRole() - .add(this.management.getSecurity().getRole()); + .addAll(this.management.getSecurity().getRole()); } } @@ -296,8 +296,9 @@ 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 role - requests.anyRequest().hasRole(this.management.getSecurity().getRole()); + // Restrict the rest to the configured roles + List roles = this.management.getSecurity().getRole(); + requests.anyRequest().hasAnyRole(roles.toArray(new String[roles.size()])); } } diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index e7a94864ab..b31c92487f 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -996,7 +996,7 @@ content into your application; rather pick only the properties that you need. management.context-path= # Management endpoint context-path. For instance `/actuator` management.port= # Management endpoint HTTP port. Use the same port as the application by default. management.security.enabled=true # Enable security. - management.security.role=ADMIN # Role required to access the management endpoint. + management.security.role=ADMIN # Roles required to access the management endpoint. management.security.sessions=stateless # Session creating policy to use (always, never, if_required, stateless). # HEALTH INDICATORS (previously health.*) diff --git a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index cc680083e1..60d8289cd1 100644 --- a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -520,7 +520,7 @@ TIP: Generated passwords are logged as the application starts. Search for '`Usin security password`'. You can use Spring properties to change the username and password and to change the -security role required to access the endpoints. For example, you might set the following +security roles required to access the endpoints. For example, you might set the following in your `application.properties`: [source,properties,indent=0] From b02aba4c757cec7505dfa9ec60cdf7e045eec16e Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 23 May 2016 17:38:45 +0200 Subject: [PATCH 2/2] Polish contribution Closes gh-5074 --- .../autoconfigure/CrshAutoConfiguration.java | 2 +- .../ManagementServerProperties.java | 20 +++++---- ...anagementWebSecurityAutoConfiguration.java | 4 +- ...itional-spring-configuration-metadata.json | 9 ++++ ...erverPropertiesAutoConfigurationTests.java | 43 +++++++++++++++++++ .../appendix-application-properties.adoc | 2 +- .../asciidoc/production-ready-features.adoc | 4 +- 7 files changed, 70 insertions(+), 14 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfiguration.java index 235aa88572..799916594d 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfiguration.java @@ -196,7 +196,7 @@ public class CrshAutoConfiguration { // overridden by ConfigurationProperties. SpringAuthenticationProperties authenticationProperties = new SpringAuthenticationProperties(); if (this.management != null) { - List roles = this.management.getSecurity().getRole(); + List roles = this.management.getSecurity().getRoles(); authenticationProperties.setRoles(roles.toArray(new String[roles.size()])); } return authenticationProperties; 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 db13dd5ebd..7821ea8afd 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 @@ -17,8 +17,7 @@ package org.springframework.boot.actuate.autoconfigure; import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import javax.validation.constraints.NotNull; @@ -164,9 +163,9 @@ public class ManagementServerProperties implements SecurityPrerequisite { private boolean enabled = true; /** - * Roles required to access the management endpoint. + * Comma-separated list of roles that can access the management endpoint. */ - private List role = new ArrayList(Arrays.asList("ADMIN")); + private List roles = Collections.singletonList("ADMIN"); /** * Session creating policy to use (always, never, if_required, stateless). @@ -181,12 +180,17 @@ public class ManagementServerProperties implements SecurityPrerequisite { this.sessions = sessions; } - public void setRole(List role) { - this.role = role; + public void setRoles(List roles) { + this.roles = roles; } - public List getRole() { - return this.role; + @Deprecated + public void setRole(String role) { + this.roles = Collections.singletonList(role); + } + + public List getRoles() { + return this.roles; } public boolean isEnabled() { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java index 4030250622..bc4a48f08a 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java @@ -124,7 +124,7 @@ public class ManagementWebSecurityAutoConfiguration { public void init() { if (this.management != null && this.security != null) { this.security.getUser().getRole() - .addAll(this.management.getSecurity().getRole()); + .addAll(this.management.getSecurity().getRoles()); } } @@ -297,7 +297,7 @@ public class ManagementWebSecurityAutoConfiguration { requests.requestMatchers(new LazyEndpointPathRequestMatcher( this.contextResolver, EndpointPaths.NON_SENSITIVE)).permitAll(); // Restrict the rest to the configured roles - List roles = this.management.getSecurity().getRole(); + List roles = this.management.getSecurity().getRoles(); requests.anyRequest().hasAnyRole(roles.toArray(new String[roles.size()])); } diff --git a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 8ce47a4b0b..8e774d1de4 100644 --- a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -163,6 +163,15 @@ "description": "Enable git info.", "defaultValue": true }, + { + "name": "management.security.role", + "type": "java.lang.String", + "description": "Roles required to access the management endpoint.", + "defaultValue": "ADMIN", + "deprecation": { + "replacement": "management.security.roles" + } + }, { "name": "spring.git.properties", "type": "java.lang.String", diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementServerPropertiesAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementServerPropertiesAutoConfigurationTests.java index 7a318fb9e3..3efbc3bfe0 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementServerPropertiesAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementServerPropertiesAutoConfigurationTests.java @@ -16,8 +16,14 @@ package org.springframework.boot.actuate.autoconfigure; +import org.junit.After; import org.junit.Test; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.util.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Configuration; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -28,6 +34,15 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class ManagementServerPropertiesAutoConfigurationTests { + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + @Test public void defaultManagementServerProperties() { ManagementServerProperties properties = new ManagementServerProperties(); @@ -58,4 +73,32 @@ public class ManagementServerPropertiesAutoConfigurationTests { assertThat(properties.getContextPath()).isEqualTo(""); } + @Test + @Deprecated + public void managementRoleSetRolesProperly() { + ManagementServerProperties properties = load("management.security.role=FOO"); + assertThat(properties.getSecurity().getRoles()).containsOnly("FOO"); + } + + @Test + public void managementRolesSetMultipleRoles() { + ManagementServerProperties properties = load("management.security.roles=FOO,BAR,BIZ"); + assertThat(properties.getSecurity().getRoles()).containsOnly("FOO", "BAR", "BIZ"); + } + + public ManagementServerProperties load(String... environment) { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(ctx, environment); + ctx.register(TestConfiguration.class); + ctx.refresh(); + this.context = ctx; + return this.context.getBean(ManagementServerProperties.class); + } + + @Configuration + @EnableConfigurationProperties(ManagementServerProperties.class) + static class TestConfiguration { + + } + } diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index b31c92487f..62be349e73 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -996,7 +996,7 @@ content into your application; rather pick only the properties that you need. management.context-path= # Management endpoint context-path. For instance `/actuator` management.port= # Management endpoint HTTP port. Use the same port as the application by default. management.security.enabled=true # Enable security. - management.security.role=ADMIN # Roles required to access the management endpoint. + management.security.roles=ADMIN # Comma-separated list of roles that can access the management endpoint. management.security.sessions=stateless # Session creating policy to use (always, never, if_required, stateless). # HEALTH INDICATORS (previously health.*) diff --git a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 60d8289cd1..5315c62246 100644 --- a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -520,14 +520,14 @@ TIP: Generated passwords are logged as the application starts. Search for '`Usin security password`'. You can use Spring properties to change the username and password and to change the -security roles required to access the endpoints. For example, you might set the following +security role(s) required to access the endpoints. For example, you might set the following in your `application.properties`: [source,properties,indent=0] ---- security.user.name=admin security.user.password=secret - management.security.role=SUPERUSER + management.security.roles=SUPERUSER ---- TIP: If you don't use Spring Security and your HTTP endpoints are exposed publicly,