Merge branch '1.5.x'

This commit is contained in:
Phillip Webb
2017-03-02 00:09:56 -08:00
17 changed files with 172 additions and 88 deletions

View File

@@ -159,9 +159,11 @@ public class EndpointWebMvcManagementContextConfiguration {
@Bean
@ConditionalOnBean(HealthEndpoint.class)
@ConditionalOnEnabledEndpoint("health")
public HealthMvcEndpoint healthMvcEndpoint(HealthEndpoint delegate) {
public HealthMvcEndpoint healthMvcEndpoint(HealthEndpoint delegate,
ManagementServerProperties managementServerProperties) {
HealthMvcEndpoint healthMvcEndpoint = new HealthMvcEndpoint(delegate,
this.managementServerProperties.getSecurity().isEnabled());
this.managementServerProperties.getSecurity().isEnabled(),
managementServerProperties.getSecurity().getRoles());
if (this.healthMvcEndpointProperties.getMapping() != null) {
healthMvcEndpoint
.addStatusMapping(this.healthMvcEndpointProperties.getMapping());

View File

@@ -16,7 +16,9 @@
package org.springframework.boot.actuate.endpoint.mvc;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
@@ -52,6 +54,8 @@ public class HealthMvcEndpoint extends AbstractEndpointMvcAdapter<HealthEndpoint
private final boolean secure;
private final List<String> roles;
private Map<String, HttpStatus> statusMapping = new HashMap<String, HttpStatus>();
private RelaxedPropertyResolver securityPropertyResolver;
@@ -65,9 +69,15 @@ public class HealthMvcEndpoint extends AbstractEndpointMvcAdapter<HealthEndpoint
}
public HealthMvcEndpoint(HealthEndpoint delegate, boolean secure) {
this(delegate, secure, null);
}
public HealthMvcEndpoint(HealthEndpoint delegate, boolean secure,
List<String> roles) {
super(delegate);
this.secure = secure;
setupDefaultStatusMapping();
this.roles = roles;
}
private void setupDefaultStatusMapping() {
@@ -173,10 +183,7 @@ public class HealthMvcEndpoint extends AbstractEndpointMvcAdapter<HealthEndpoint
if (!this.secure) {
return true;
}
String[] roles = StringUtils.commaDelimitedListToStringArray(
this.securityPropertyResolver.getProperty("roles", "ROLE_ACTUATOR"));
roles = StringUtils.trimArrayElements(roles);
for (String role : roles) {
for (String role : getRoles()) {
if (request.isUserInRole(role) || request.isUserInRole("ROLE_" + role)) {
return true;
}
@@ -184,4 +191,14 @@ public class HealthMvcEndpoint extends AbstractEndpointMvcAdapter<HealthEndpoint
return false;
}
private List<String> getRoles() {
if (this.roles != null) {
return this.roles;
}
String[] roles = StringUtils.commaDelimitedListToStringArray(
this.securityPropertyResolver.getProperty("roles", "ROLE_ACTUATOR"));
roles = StringUtils.trimArrayElements(roles);
return Arrays.asList(roles);
}
}

View File

@@ -125,10 +125,14 @@ public class MvcEndpointSecurityInterceptor extends HandlerInterceptorAdapter {
}
}
private class AuthoritiesValidator {
/**
* Inner class to check authorities using Spring Security (when available).
*/
private static class AuthoritiesValidator {
private boolean hasAuthority(String role) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication();
if (authentication != null) {
for (GrantedAuthority authority : authentication.getAuthorities()) {
if (authority.getAuthority().equals(role)) {

View File

@@ -16,6 +16,8 @@
package org.springframework.boot.actuate.autoconfigure;
import java.util.Arrays;
import org.junit.After;
import org.junit.Test;
@@ -34,6 +36,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
@@ -83,6 +86,20 @@ public class HealthMvcEndpointAutoConfigurationTests {
assertThat(map.getDetails().get("foo")).isEqualTo("bar");
}
@Test
public void testSetRoles() throws Exception {
// gh-8314
this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext());
this.context.register(TestConfiguration.class);
EnvironmentTestUtils.addEnvironment(this.context,
"management.security.roles[0]=super");
this.context.refresh();
HealthMvcEndpoint health = this.context.getBean(HealthMvcEndpoint.class);
assertThat(ReflectionTestUtils.getField(health, "roles"))
.isEqualTo(Arrays.asList("super"));
}
@Configuration
@ImportAutoConfiguration({ SecurityAutoConfiguration.class,
JacksonAutoConfiguration.class, WebMvcAutoConfiguration.class,

View File

@@ -16,6 +16,7 @@
package org.springframework.boot.actuate.endpoint.mvc;
import java.util.Arrays;
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
@@ -182,6 +183,19 @@ public class HealthMvcEndpointTests {
assertThat(((Health) result).getDetails().get("foo")).isNull();
}
@Test
public void customRoleFromListShouldNotExposeDetailsForDefaultRole() {
// gh-8314
this.mvc = new HealthMvcEndpoint(this.endpoint, true,
Arrays.asList("HERO", "USER"));
given(this.endpoint.invoke())
.willReturn(new Health.Builder().up().withDetail("foo", "bar").build());
Object result = this.mvc.invoke(this.hero);
assertThat(result instanceof Health).isTrue();
assertThat(((Health) result).getStatus() == Status.UP).isTrue();
assertThat(((Health) result).getDetails().get("foo")).isEqualTo("bar");
}
@Test
public void healthIsCached() {
given(this.endpoint.getTimeToLive()).willReturn(10000L);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
@@ -130,11 +130,13 @@ public class MvcEndpointSecurityInterceptorTests {
}
@Test
public void sensitiveEndpointIfRoleNotCorrectShouldCheckAuthorities() throws Exception {
public void sensitiveEndpointIfRoleNotCorrectShouldCheckAuthorities()
throws Exception {
Principal principal = mock(Principal.class);
this.request.setUserPrincipal(principal);
Authentication authentication = mock(Authentication.class);
Set<SimpleGrantedAuthority> authorities = Collections.singleton(new SimpleGrantedAuthority("SUPER_HERO"));
Set<SimpleGrantedAuthority> authorities = Collections
.singleton(new SimpleGrantedAuthority("SUPER_HERO"));
doReturn(authorities).when(authentication).getAuthorities();
SecurityContextHolder.getContext().setAuthentication(authentication);
assertThat(this.securityInterceptor.preHandle(this.request, this.response,
@@ -142,11 +144,13 @@ public class MvcEndpointSecurityInterceptorTests {
}
@Test
public void sensitiveEndpointIfRoleAndAuthoritiesNotCorrectShouldNotAllowAccess() throws Exception {
public void sensitiveEndpointIfRoleAndAuthoritiesNotCorrectShouldNotAllowAccess()
throws Exception {
Principal principal = mock(Principal.class);
this.request.setUserPrincipal(principal);
Authentication authentication = mock(Authentication.class);
Set<SimpleGrantedAuthority> authorities = Collections.singleton(new SimpleGrantedAuthority("HERO"));
Set<SimpleGrantedAuthority> authorities = Collections
.singleton(new SimpleGrantedAuthority("HERO"));
doReturn(authorities).when(authentication).getAuthorities();
SecurityContextHolder.getContext().setAuthentication(authentication);
assertThat(this.securityInterceptor.preHandle(this.request, this.response,

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
@@ -39,6 +39,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link MvcEndpointSecurityInterceptor} when Spring Security is not available.
*
* @author Madhura Bhave
*/
@RunWith(ModifiedClassPathRunner.class)
@@ -77,7 +79,8 @@ public class NoSpringSecurityMvcEndpointSecurityInterceptorTests {
}
@Test
public void sensitiveEndpointIfRoleNotPresentShouldNotValidateAuthorities() throws Exception {
public void sensitiveEndpointIfRoleNotPresentShouldNotValidateAuthorities()
throws Exception {
Principal principal = mock(Principal.class);
this.request.setUserPrincipal(principal);
this.servletContext.declareRoles("HERO");
@@ -105,5 +108,5 @@ public class NoSpringSecurityMvcEndpointSecurityInterceptorTests {
}
}
}
}