Skip to content

Commit e96f75f

Browse files
committed
Fix management endpoint without Spring Security
The method 'injectIntoSecurityFilter' added In 3c1e48c assumes that Spring security is in the classpath so any management endpoints that are deployed on a different port requires Spring Security all the sudden. This commit separates the creating of the EndpointHandlerMapping in two mutually exclusive @configuration: one that is triggered if Spring Security is not in the classpath and one that is triggered if Spring Security is in the classpath. The latter apply the security filter in the endpoint mapping if it exists. Fixes gh-2124
1 parent f8141cb commit e96f75f

File tree

1 file changed

+67
-34
lines changed

1 file changed

+67
-34
lines changed

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

+67-34
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
4040
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
4141
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
42+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
4243
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
4344
import org.springframework.boot.autoconfigure.web.ErrorAttributes;
4445
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
@@ -50,6 +51,7 @@
5051
import org.springframework.context.annotation.Bean;
5152
import org.springframework.context.annotation.Configuration;
5253
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
54+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
5355
import org.springframework.web.servlet.DispatcherServlet;
5456
import org.springframework.web.servlet.HandlerAdapter;
5557
import org.springframework.web.servlet.HandlerMapping;
@@ -133,40 +135,6 @@ public HandlerAdapter handlerAdapter(HttpMessageConverters converters) {
133135
return adapter;
134136
}
135137

136-
@Bean
137-
public HandlerMapping handlerMapping(MvcEndpoints endpoints,
138-
ListableBeanFactory beanFactory) {
139-
Set<MvcEndpoint> set = new HashSet<MvcEndpoint>(endpoints.getEndpoints());
140-
set.addAll(beanFactory.getBeansOfType(MvcEndpoint.class).values());
141-
EndpointHandlerMapping mapping = new EndpointHandlerMapping(set);
142-
// In a child context we definitely want to see the parent endpoints
143-
mapping.setDetectHandlerMethodsInAncestorContexts(true);
144-
injectIntoSecurityFilter(beanFactory, mapping);
145-
if (this.mappingCustomizers != null) {
146-
for (EndpointHandlerMappingCustomizer customizer : this.mappingCustomizers) {
147-
customizer.customize(mapping);
148-
}
149-
}
150-
return mapping;
151-
}
152-
153-
private void injectIntoSecurityFilter(ListableBeanFactory beanFactory,
154-
EndpointHandlerMapping mapping) {
155-
// The parent context has the security filter, so we need to get it injected with
156-
// our EndpointHandlerMapping if we can.
157-
if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,
158-
ManagementWebSecurityConfigurerAdapter.class).length == 1) {
159-
ManagementWebSecurityConfigurerAdapter bean = beanFactory
160-
.getBean(ManagementWebSecurityConfigurerAdapter.class);
161-
bean.setEndpointHandlerMapping(mapping);
162-
}
163-
else {
164-
logger.warn("No single bean of type "
165-
+ ManagementWebSecurityConfigurerAdapter.class.getSimpleName()
166-
+ " found (this might make some endpoints inaccessible without authentication)");
167-
}
168-
}
169-
170138
/*
171139
* The error controller is present but not mapped as an endpoint in this context
172140
* because of the DispatcherServlet having had it's HandlerMapping explicitly
@@ -177,6 +145,71 @@ public ManagementErrorEndpoint errorEndpoint(final ErrorAttributes errorAttribut
177145
return new ManagementErrorEndpoint(this.errorPath, errorAttributes);
178146
}
179147

148+
@Configuration
149+
@ConditionalOnMissingClass(WebSecurityConfigurerAdapter.class)
150+
static class EndpointHandlerMappingSimpleConfiguration {
151+
152+
@Autowired(required = false)
153+
private List<EndpointHandlerMappingCustomizer> mappingCustomizers;
154+
155+
@Bean
156+
public HandlerMapping handlerMapping(MvcEndpoints endpoints,
157+
ListableBeanFactory beanFactory) {
158+
159+
EndpointHandlerMapping mapping = doCreateEndpointHandlerMapping(endpoints, beanFactory);
160+
if (this.mappingCustomizers != null) {
161+
for (EndpointHandlerMappingCustomizer customizer : this.mappingCustomizers) {
162+
customizer.customize(mapping);
163+
}
164+
}
165+
return mapping;
166+
}
167+
168+
protected EndpointHandlerMapping doCreateEndpointHandlerMapping(MvcEndpoints endpoints,
169+
ListableBeanFactory beanFactory) {
170+
Set<MvcEndpoint> set = new HashSet<MvcEndpoint>(endpoints.getEndpoints());
171+
set.addAll(beanFactory.getBeansOfType(MvcEndpoint.class).values());
172+
EndpointHandlerMapping mapping = new EndpointHandlerMapping(set);
173+
// In a child context we definitely want to see the parent endpoints
174+
mapping.setDetectHandlerMethodsInAncestorContexts(true);
175+
return mapping;
176+
}
177+
178+
}
179+
180+
@Configuration
181+
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
182+
static class EndpointHandlerMappingSecurityConfiguration
183+
extends EndpointHandlerMappingSimpleConfiguration {
184+
185+
@Override
186+
protected EndpointHandlerMapping doCreateEndpointHandlerMapping(MvcEndpoints endpoints,
187+
ListableBeanFactory beanFactory) {
188+
189+
EndpointHandlerMapping mapping = super.doCreateEndpointHandlerMapping(endpoints, beanFactory);
190+
injectIntoSecurityFilter(beanFactory, mapping);
191+
return mapping;
192+
}
193+
194+
private void injectIntoSecurityFilter(ListableBeanFactory beanFactory,
195+
EndpointHandlerMapping mapping) {
196+
// The parent context has the security filter, so we need to get it injected with
197+
// our EndpointHandlerMapping if we can.
198+
if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,
199+
ManagementWebSecurityConfigurerAdapter.class).length == 1) {
200+
ManagementWebSecurityConfigurerAdapter bean = beanFactory
201+
.getBean(ManagementWebSecurityConfigurerAdapter.class);
202+
bean.setEndpointHandlerMapping(mapping);
203+
}
204+
else {
205+
logger.warn("No single bean of type "
206+
+ ManagementWebSecurityConfigurerAdapter.class.getSimpleName()
207+
+ " found (this might make some endpoints inaccessible without authentication)");
208+
}
209+
}
210+
211+
}
212+
180213
@Configuration
181214
@ConditionalOnClass({ EnableWebSecurity.class, Filter.class })
182215
@ConditionalOnBean(name = "springSecurityFilterChain", search = SearchStrategy.PARENTS)

0 commit comments

Comments
 (0)