Commit a3a53d29 authored by Madhura Bhave's avatar Madhura Bhave

Check authorities when exposing health details

Fixes gh-18998
parent 2c1e70de
...@@ -16,11 +16,15 @@ ...@@ -16,11 +16,15 @@
package org.springframework.boot.actuate.health; package org.springframework.boot.actuate.health;
import java.security.Principal;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
/** /**
...@@ -108,12 +112,29 @@ public class HealthWebEndpointResponseMapper { ...@@ -108,12 +112,29 @@ public class HealthWebEndpointResponseMapper {
if (CollectionUtils.isEmpty(this.authorizedRoles)) { if (CollectionUtils.isEmpty(this.authorizedRoles)) {
return true; return true;
} }
Principal principal = securityContext.getPrincipal();
boolean checkAuthorities = isSpringSecurityAuthentication(principal);
for (String role : this.authorizedRoles) { for (String role : this.authorizedRoles) {
if (securityContext.isUserInRole(role)) { if (securityContext.isUserInRole(role)) {
return true; return true;
} }
if (checkAuthorities) {
Authentication authentication = (Authentication) principal;
for (GrantedAuthority authority : authentication.getAuthorities()) {
String name = authority.getAuthority();
if (role.equals(name)) {
return true;
}
}
}
} }
return false; return false;
} }
private boolean isSpringSecurityAuthentication(Principal principal) {
return ClassUtils.isPresent("org.springframework.security.core.Authentication", null)
&& (principal instanceof Authentication);
}
} }
...@@ -29,6 +29,8 @@ import org.mockito.stubbing.Answer; ...@@ -29,6 +29,8 @@ import org.mockito.stubbing.Answer;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
...@@ -84,6 +86,39 @@ public class HealthWebEndpointResponseMapperTests { ...@@ -84,6 +86,39 @@ public class HealthWebEndpointResponseMapperTests {
verify(securityContext).isUserInRole("ACTUATOR"); verify(securityContext).isUserInRole("ACTUATOR");
} }
@Test
public void mapDetailsWithRightAuthoritiesInvokesSupplier() {
HealthWebEndpointResponseMapper mapper = createMapper(ShowDetails.WHEN_AUTHORIZED);
Supplier<Health> supplier = mockSupplier();
given(supplier.get()).willReturn(Health.down().build());
SecurityContext securityContext = getSecurityContext("ACTUATOR");
WebEndpointResponse<Health> response = mapper.mapDetails(supplier, securityContext);
assertThat(response.getStatus()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE.value());
assertThat(response.getBody().getStatus()).isEqualTo(Status.DOWN);
verify(supplier).get();
}
@Test
public void mapDetailsWithOtherAuthoritiesShouldNotInvokeSupplier() {
HealthWebEndpointResponseMapper mapper = createMapper(ShowDetails.WHEN_AUTHORIZED);
Supplier<Health> supplier = mockSupplier();
given(supplier.get()).willReturn(Health.down().build());
SecurityContext securityContext = getSecurityContext("OTHER");
WebEndpointResponse<Health> response = mapper.mapDetails(supplier, securityContext);
assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
assertThat(response.getBody()).isNull();
verifyZeroInteractions(supplier);
}
private SecurityContext getSecurityContext(String other) {
SecurityContext securityContext = mock(SecurityContext.class);
Authentication principal = mock(Authentication.class);
given(securityContext.getPrincipal()).willReturn(principal);
given(principal.getAuthorities())
.willAnswer((invocation) -> Collections.singleton(new SimpleGrantedAuthority(other)));
return securityContext;
}
@Test @Test
public void mapDetailsWithUnavailableHealth() { public void mapDetailsWithUnavailableHealth() {
HealthWebEndpointResponseMapper mapper = createMapper(ShowDetails.ALWAYS); HealthWebEndpointResponseMapper mapper = createMapper(ShowDetails.ALWAYS);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment