Skip to content

Commit e5e1f24

Browse files
committed
Revert "Skip MvcSecurityInterceptor if Spring Security present"
Instead of entirely skipping the interceptor, we will be additionally checking for authorities.
1 parent ad5cb8a commit e5e1f24

File tree

8 files changed

+39
-184
lines changed

8 files changed

+39
-184
lines changed

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcManagementContextConfiguration.java

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@
5454
import org.springframework.context.annotation.Conditional;
5555
import org.springframework.core.env.Environment;
5656
import org.springframework.core.type.AnnotatedTypeMetadata;
57-
import org.springframework.util.ClassUtils;
5857
import org.springframework.util.CollectionUtils;
5958
import org.springframework.util.StringUtils;
6059
import org.springframework.web.cors.CorsConfiguration;
@@ -103,29 +102,16 @@ public EndpointHandlerMapping endpointHandlerMapping() {
103102
EndpointHandlerMapping mapping = new EndpointHandlerMapping(endpoints,
104103
corsConfiguration);
105104
mapping.setPrefix(this.managementServerProperties.getContextPath());
106-
if (isSecurityInterceptorRequired()) {
107-
MvcEndpointSecurityInterceptor securityInterceptor = new MvcEndpointSecurityInterceptor(
108-
this.managementServerProperties.getSecurity().getRoles());
109-
mapping.setSecurityInterceptor(securityInterceptor);
110-
}
111-
105+
MvcEndpointSecurityInterceptor securityInterceptor = new MvcEndpointSecurityInterceptor(
106+
this.managementServerProperties.getSecurity().isEnabled(),
107+
this.managementServerProperties.getSecurity().getRoles());
108+
mapping.setSecurityInterceptor(securityInterceptor);
112109
for (EndpointHandlerMappingCustomizer customizer : this.mappingCustomizers) {
113110
customizer.customize(mapping);
114111
}
115112
return mapping;
116113
}
117114

118-
private boolean isSecurityInterceptorRequired() {
119-
return this.managementServerProperties.getSecurity().isEnabled()
120-
&& !isSpringSecurityAvailable();
121-
}
122-
123-
private boolean isSpringSecurityAvailable() {
124-
return ClassUtils.isPresent(
125-
"org.springframework.security.config.annotation.web.WebSecurityConfigurer",
126-
getClass().getClassLoader());
127-
}
128-
129115
private CorsConfiguration getCorsConfiguration(EndpointCorsProperties properties) {
130116
if (CollectionUtils.isEmpty(properties.getAllowedOrigins())) {
131117
return null;

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,10 +257,8 @@ private AuthenticationEntryPoint entryPoint() {
257257

258258
private void configurePermittedRequests(
259259
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry requests) {
260-
List<String> roles = this.management.getSecurity().getRoles();
261260
requests.requestMatchers(new LazyEndpointPathRequestMatcher(
262-
this.contextResolver, EndpointPaths.SENSITIVE))
263-
.hasAnyRole(roles.toArray(new String[roles.size()]));
261+
this.contextResolver, EndpointPaths.SENSITIVE)).authenticated();
264262
// Permit access to the non-sensitive endpoints
265263
requests.requestMatchers(new LazyEndpointPathRequestMatcher(
266264
this.contextResolver, EndpointPaths.NON_SENSITIVE)).permitAll();

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointSecurityInterceptor.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,21 @@ public class MvcEndpointSecurityInterceptor extends HandlerInterceptorAdapter {
4343
private static final Log logger = LogFactory
4444
.getLog(MvcEndpointSecurityInterceptor.class);
4545

46+
private final boolean secure;
47+
4648
private final List<String> roles;
4749

4850
private AtomicBoolean loggedUnauthorizedAttempt = new AtomicBoolean();
4951

50-
public MvcEndpointSecurityInterceptor(List<String> roles) {
52+
public MvcEndpointSecurityInterceptor(boolean secure, List<String> roles) {
53+
this.secure = secure;
5154
this.roles = roles;
5255
}
5356

5457
@Override
5558
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
5659
Object handler) throws Exception {
57-
if (CorsUtils.isPreFlightRequest(request)) {
60+
if (CorsUtils.isPreFlightRequest(request) || !this.secure) {
5861
return true;
5962
}
6063
HandlerMethod handlerMethod = (HandlerMethod) handler;

spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcManagementContextConfigurationTests.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure;
1818

19+
import java.util.List;
20+
1921
import org.junit.After;
2022
import org.junit.Before;
2123
import org.junit.Test;
@@ -28,6 +30,7 @@
2830
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
2931
import org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration;
3032
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
33+
import org.springframework.boot.test.util.EnvironmentTestUtils;
3134
import org.springframework.mock.web.MockServletContext;
3235
import org.springframework.test.util.ReflectionTestUtils;
3336
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
@@ -55,8 +58,6 @@ public void setup() {
5558
PropertyPlaceholderAutoConfiguration.class,
5659
WebClientAutoConfiguration.class,
5760
EndpointWebMvcManagementContextConfiguration.class);
58-
this.context.refresh();
59-
6061
}
6162

6263
@After
@@ -67,13 +68,25 @@ public void close() {
6768
}
6869

6970
@Test
70-
public void endpointHandlerMappingShouldNotHaveSecurityInterceptor() throws Exception {
71+
public void endpointHandlerMapping() throws Exception {
72+
EnvironmentTestUtils.addEnvironment(this.context,
73+
"management.security.enabled=false",
74+
"management.security.roles=my-role,your-role");
75+
this.context.refresh();
7176
EndpointHandlerMapping mapping = this.context.getBean("endpointHandlerMapping",
7277
EndpointHandlerMapping.class);
7378
assertThat(mapping.getPrefix()).isEmpty();
7479
MvcEndpointSecurityInterceptor securityInterceptor = (MvcEndpointSecurityInterceptor) ReflectionTestUtils
7580
.getField(mapping, "securityInterceptor");
76-
assertThat(securityInterceptor).isNull();
81+
Object secure = ReflectionTestUtils.getField(securityInterceptor, "secure");
82+
List<String> roles = getRoles(securityInterceptor);
83+
assertThat(secure).isEqualTo(false);
84+
assertThat(roles).containsExactly("my-role", "your-role");
85+
}
86+
87+
@SuppressWarnings("unchecked")
88+
private List<String> getRoles(MvcEndpointSecurityInterceptor securityInterceptor) {
89+
return (List<String>) ReflectionTestUtils.getField(securityInterceptor, "roles");
7790
}
7891

7992
}

spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfigurationTests.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.actuate.autoconfigure;
1818

1919
import java.util.Collection;
20+
import java.util.Collections;
2021

2122
import org.hamcrest.Matchers;
2223
import org.junit.After;
@@ -25,6 +26,7 @@
2526
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
2627
import org.springframework.boot.actuate.endpoint.mvc.JolokiaMvcEndpoint;
2728
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
29+
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpointSecurityInterceptor;
2830
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
2931
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
3032
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
@@ -142,6 +144,8 @@ protected static class EndpointsConfig extends Config {
142144
public EndpointHandlerMapping endpointHandlerMapping(
143145
Collection<? extends MvcEndpoint> endpoints) {
144146
EndpointHandlerMapping mapping = new EndpointHandlerMapping(endpoints);
147+
mapping.setSecurityInterceptor(new MvcEndpointSecurityInterceptor(false,
148+
Collections.<String>emptyList()));
145149
return mapping;
146150
}
147151

spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfigurationTests.java

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
5656
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
5757
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
58-
import org.springframework.util.Base64Utils;
5958
import org.springframework.util.StringUtils;
6059
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
6160

@@ -255,57 +254,6 @@ public void testMarkAllEndpointsSensitive() throws Exception {
255254
.andExpect(status().isUnauthorized());
256255
}
257256

258-
@Test
259-
public void sensitiveEndpointWithRightRoleShouldReturnOk() throws Exception {
260-
this.context = new AnnotationConfigWebApplicationContext();
261-
this.context.setServletContext(new MockServletContext());
262-
this.context.register(AuthenticationConfig.class, WebConfiguration.class);
263-
EnvironmentTestUtils.addEnvironment(this.context, "management.security.roles:USER");
264-
this.context.refresh();
265-
266-
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
267-
.apply(springSecurity())
268-
.build();
269-
270-
String authorizationHeader = Base64Utils.encodeToString("user:password".getBytes());
271-
mockMvc //
272-
.perform(get("/env").header("authorization", "Basic " + authorizationHeader))
273-
.andExpect(status().isOk());
274-
}
275-
276-
@Test
277-
public void sensitiveEndpointWithRightRoleShouldReturnForbidden() throws Exception {
278-
this.context = new AnnotationConfigWebApplicationContext();
279-
this.context.setServletContext(new MockServletContext());
280-
this.context.register(AuthenticationConfig.class, WebConfiguration.class);
281-
this.context.refresh();
282-
283-
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
284-
.apply(springSecurity())
285-
.build();
286-
287-
String authorizationHeader = Base64Utils.encodeToString("user:password".getBytes());
288-
mockMvc //
289-
.perform(get("/env").header("authorization", "Basic " + authorizationHeader))
290-
.andExpect(status().isForbidden());
291-
}
292-
293-
@Test
294-
public void nonSensitiveEndpointShouldAlwaysReturnOk() throws Exception {
295-
this.context = new AnnotationConfigWebApplicationContext();
296-
this.context.setServletContext(new MockServletContext());
297-
this.context.register(WebConfiguration.class);
298-
this.context.refresh();
299-
300-
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
301-
.apply(springSecurity())
302-
.build();
303-
304-
mockMvc //
305-
.perform(get("/health"))
306-
.andExpect(status().isOk());
307-
}
308-
309257
private ResultMatcher springAuthenticateRealmHeader() {
310258
return MockMvcResultMatchers.header().string("www-authenticate",
311259
Matchers.containsString("realm=\"Spring\""));

spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/NoSpringSecurityEndpointWebMvcManagementContextConfigurationTests.java

Lines changed: 0 additions & 104 deletions
This file was deleted.

spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointSecurityInterceptorTests.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public class MvcEndpointSecurityInterceptorTests {
6666
@Before
6767
public void setup() throws Exception {
6868
this.roles = Arrays.asList("SUPER_HERO");
69-
this.securityInterceptor = new MvcEndpointSecurityInterceptor(this.roles);
69+
this.securityInterceptor = new MvcEndpointSecurityInterceptor(true, this.roles);
7070
this.endpoint = new TestEndpoint("a");
7171
this.mvcEndpoint = new TestMvcEndpoint(this.endpoint);
7272
this.handlerMethod = new HandlerMethod(this.mvcEndpoint, "invoke");
@@ -75,6 +75,13 @@ public void setup() throws Exception {
7575
this.response = mock(HttpServletResponse.class);
7676
}
7777

78+
@Test
79+
public void securityDisabledShouldAllowAccess() throws Exception {
80+
this.securityInterceptor = new MvcEndpointSecurityInterceptor(false, this.roles);
81+
assertThat(this.securityInterceptor.preHandle(this.request, this.response,
82+
this.handlerMethod)).isTrue();
83+
}
84+
7885
@Test
7986
public void endpointNotSensitiveShouldAllowAccess() throws Exception {
8087
this.endpoint.setSensitive(false);

0 commit comments

Comments
 (0)