Reputation: 915
I would like to use Spring Actuator Framework in my Spring Boot 2.0 application. The framework itself works as expected, thus I am able to reach e.g. my /actuator/health
endpoint. There I´m presented a login dialogue. I´d like to get rid of it and tried the following:
@Configuration
@EnableWebFluxSecurity
public class SecurityConfiguration {
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange()
.matchers(EndpointRequest.to("prometheus")).permitAll()
.matchers(EndpointRequest.toAnyEndpoint()).authenticated()
.anyExchange().permitAll()
.and()
.formLogin()
.and()
.httpBasic()
.and()
.build();
}
However, during application startup I get the following error:
Failed to instantiate [org.springframework.security.web.server.SecurityWebFilterChain]: Factory method 'securityWebFilterChain' threw exception; nested exception is java.lang.IllegalArgumentException: authenticationManager cannot be null
Of course I tried to search for it, but I always only get pages describing different scenarios or security configuration with Spring Boot 1.x framework. Can anybody help me here?
Upvotes: 2
Views: 3430
Reputation: 538
Although the answer from Twin has already received upvotes and the question is old: if you want to secure the Actuator endpoints by using Basic Auth, you also need to provide a suitable AuthenticationManager. The AuthenticationManager authenticates a username+password against some kind of repository.
In the following example the request is authenticated against a user defined in application.yml:
SecurityConfig
@RequiredArgsConstructor
@Configuration
public class SecurityConfig {
private final SecurityProperties securityProperties;
@Bean
public SecurityWebFilterChain actuator(ServerHttpSecurity http) {
return http
.authorizeExchange()
.matchers(EndpointRequest.toAnyEndpoint().excluding("prometheus")).hasRole("ACTUATOR")
.anyExchange().permitAll()
.and()
.httpBasic()
.authenticationManager(new UserDetailsRepositoryReactiveAuthenticationManager(
new MapReactiveUserDetailsService(new User(securityProperties.getUser().getName(),
"{noop}".concat(securityProperties.getUser().getPassword()),
securityProperties.getUser().getRoles().stream().map("ROLE_"::concat).map(SimpleGrantedAuthority::new)
.collect(Collectors.toList())))))
.securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
.and()
.requestCache().disable() // disables websession creation
.build();
}
}
application.yml
spring:
security:
user:
name: username
password: password
roles: ACTUATOR
This is not production ready, you shouldn't place the password in your sourcecode.
Upvotes: 1
Reputation: 3824
Off the top of my head, the easiest way to do it should be to have your SecurityConfiguration
extend WebSecurityConfigurerAdapter
and override configure(WebSecurity web)
, like so:
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/actuator/**");
}
// ...
}
Also, I'm not familiar with @EnableWebFluxSecurity
, but for the above to work, you'd need both the @Configuration
and the @EnableWebSecurity
annotation.
Now as for the way your configuration is setup, it's not really optimal. To complement the above suggestion, you should configure your security using HttpSecurity instead of using your current SecurityWebFilterChain
.
Upvotes: 2