I have an Spring Boot App with this configuration running on the port 8081:
@Configuration
@EnableMethodSecurity
public class WebSecurityConfig { // extends WebSecurityConfigurerAdapter {
private final JwtUtils jwtUtils;
private final UserDetailsServiceImpl userDetailsService;
private final AuthEntryPointJwt unauthorizedHandler;
public WebSecurityConfig(JwtUtils jwtUtils,
UserDetailsServiceImpl userDetailsService,
AuthEntryPointJwt unauthorizedHandler) {
this.jwtUtils = jwtUtils;
this.userDetailsService = userDetailsService;
this.unauthorizedHandler = unauthorizedHandler;
}
@Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter(jwtUtils, userDetailsService);
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth ->
auth.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/actuator/**").permitAll()
.requestMatchers("/actuator/metrics").permitAll()
.requestMatchers("/api/languages").permitAll()
.requestMatchers("/api/actuator/health").permitAll()
.requestMatchers("/api/auth/sendMailOTP").permitAll()
.requestMatchers("/api/messages/**").permitAll()
.requestMatchers("/api/auth/socialSignin").permitAll()
.requestMatchers("/api/geoDetails").permitAll()
.requestMatchers("/api/legalinfo/**").permitAll()
.requestMatchers("/api/legalinfo/*").permitAll()
.requestMatchers("/api/legalinfo/eula").permitAll()
.requestMatchers("/api/users/uploadFile/**").permitAll()
.requestMatchers("/api/users/sendEmail").permitAll()
.requestMatchers("/api/legalinfo/privacy").permitAll()
.requestMatchers("/api/changeuserpassword").permitAll()
.requestMatchers("/api/forgotmypassword").permitAll()
.requestMatchers("/api/validateEmail").permitAll()
.requestMatchers("/api/checkToken").permitAll()
.requestMatchers("/api/checkOTPToken").permitAll()
.anyRequest().authenticated()
);
http.authenticationProvider(authenticationProvider());
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
doing: http://172.105.90.17:8081/actuator/health
I get :
{
"status": "UP"
}
but accessing : http://172.105.90.17:8081/actuator/metrics
I receive:
{
"message": "Full authentication is required to access this resource"
}
in the console:
2024-01-24 06:47:28.884 DEBUG [] o.s.b.f.s.DefaultListableBeanFactory@registerDependentBeans(952) - Autowiring by type from bean name 'webEndpointServletHandlerMapping' via factory method to bean named 'management.endpoints.web-org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties'
2024-01-24 06:47:28.884 DEBUG [] o.s.b.f.s.DefaultListableBeanFactory@registerDependentBeans(952) - Autowiring by type from bean name 'webEndpointServletHandlerMapping' via factory method to bean named 'environment'
2024-01-24 06:47:28.891 INFO [] o.s.b.a.e.web.EndpointLinksResolver@<init>(58) - Exposing 1 endpoint(s) beneath base path '/actuator'
2024-01-24 06:47:28.905 DEBUG [] o.s.b.f.s.DefaultListableBeanFactory@getSingleton(225) - Creating shared instance of singleton bean 'controllerEndpointHandlerMapping'
Your question can be divided into this two problems:
Solution of problem 1.
By default only the health
endpoint is enabled and exposed over HTTP. To include all available endpoints add this to application.properties
:
management.endpoints.web.exposure.include=*
If you want the shutdown
endpoint to be available as well add this:
management.endpoint.shutdown.enabled=true
If you want to change the default prefix which is actuator
you can add this:
management.endpoints.web.base-path=/manage
Whith the above settings the URL for displaying all Spring beans will look like:
http://localhost:8081/manage/beans
Solution of problem 2.
If the Spring Boot Security is enabled (as in your case) then only health
endpoint will be accessible without login. You can override this default behavior by adding /manage/**
to the requestMatchers block. Something like this:
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/manage/**").permitAll()
.anyRequest().authenticated()
)
The above is not very nice. The prefix manage
is hard coded here. What if somebody change the prefix in the application.properties
later on?
It is better to use a dedicated factory class EndpointRequest
instead. Leave the application specific SecurityFilterChange
bean as it is and add another one just for the actuator:
@Order(Ordered.HIGHEST_PRECEDENCE)
@Bean
public SecurityFilterChain actuatorFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher(EndpointRequest.toAnyEndpoint().excluding(ShutdownEndpoint.class));
http.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll());
return http.build();
}
In the above example all endpoints but the shutdown
are accessible for everyone.
Please mind the @Order
annotation. It is important because of use of SecurityMatcher.
On the server log you will see something similar to this:
EndpointLinksResolver : Exposing 14 endpoint(s) beneath base path '/manage'
DefaultSecurityFilterChain : Will secure EndpointRequestMatcher includes=[*], excludes=[shutdown]...
DefaultSecurityFilterChain : Will secure any request with...
Based on Spring Boot Documentation.