-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Description
Context
The purpose of my module/starter is to be used by other applications in the company I work in order to publish automatically specific logs related to authentication and authorization via ApplicationListeners using Spring Security's and OAuth2's strategy for publishing authentication events (DefaultAuthenticationEventPublisher
).
Expected behaviour: using old WebSecurityConfigurerAdapter
My old security config code based on Spring Boot 2.6 worked perfectly fine:
@Configuration @EnableWebSecurity
public class ResourceServerConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
. . .
.and()
.oauth2ResourceServer()
.jwt();
}
}
Description of the bug
After upgrading to Spring Boot 2.7 and replacing the usage of deprecated WebSecurityConfigurerAdapter
class in favour of a config method @Bean
that returns SecurityFilterChain
as recommended in this article and release notes my applications don't publish automatically anymore because they do not have a valid AuthenticationEventPublisher as before.
How to reproduce it
@Configuration @EnableWebSecurity
public class ResourceServerConfig {
@Bean
public SecurityFilterChain configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
. . .
.and()
.oauth2ResourceServer()
.jwt();
return http.build();
}
}
Cause of the bug
The reason for this problem is: the object BearerTokenAuthenticationFilter
uses an instance of ProviderManager
as AuthenticationManager
(so same way when using WebSecurityConfigurerAdapter
). But as default an instance of ProviderManager declares its AuthenticationEventPublisher
this way:
public class ProviderManager implements AuthenticationManager, . . . {
. . .
private AuthenticationEventPublisher eventPublisher = new NullEventPublisher();
More details about the bug
So this is the problem: NullEventPublisher
is a useless implementation which doesn't publish events.
Why this problem just now? When using WebSecurityConfigurerAdapter - this class was setting an instance of DefaultAuthenticationEventPublisher to ProviderManager
's eventPublisher
attribute over its default value NullEventPublisher's instance.
Note: I also tried using Spring Security autoconfiguration which is org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration#authenticationEventPublisher()
from spring-boot-autoconfigure
- but this one is never injected into ProviderManager.
Expected behaviour via a workaround - but I'm not fine with it
After some tests I was able to "fix the problem" with the following code:
@Configuration
@ConditionalOnClass({AuthenticationEventPublisher.class, JwtAuthenticationProvider.class})
public class SpringConfiguration { //global configuration for several other applications using my module/starter
@Bean
public AuthenticationEventPublisher eventPublisher(ApplicationEventPublisher application) {
DefaultAuthenticationEventPublisher authentication =
new DefaultAuthenticationEventPublisher(application);
authentication.setDefaultAuthenticationFailureEvent(AuthenticationFailureBadCredentialsEvent.class);
return authentication;
}
@Bean
public ProviderManager providerManagerAvecDefaultAuthenticationPublisher(@Lazy JwtDecoder jwtDecoder, AuthenticationEventPublisher authenticationPublisher) {
JwtAuthenticationProvider authenticationProvider = new JwtAuthenticationProvider(jwtDecoder);
ProviderManager providerManager = new ProviderManager(Arrays.asList(authenticationProvider));
providerManager.setAuthenticationEventPublisher(authenticationPublisher);
return providerManager;
}
}
And also had to adjust my security configuration:
@Configuration @EnableWebSecurity
public class ResourceServerConfig {
@Autowired ProviderManager manager; //1
@Bean
public SecurityFilterChain configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
. . .
.and()
.oauth2ResourceServer()
.jwt()
.authenticationManager(manager); //2
return http.build();
}
}
But I have some big concerns:
-
As my module/application is to be used by other applications - this "workaround" solution will force dozens of applications to add the lines followed by comments 1 and 2
-
By adding a custom
ProviderManager
I am not aware of the risks of "forcing" a pre-built one for those applications
So finally my question here is: Is there a way to bypasseventPublisher = new NullEventPublisher()
fromProviderManager
without forcing to configure oauth2ResourceServer().authenticationManager(manager) in all applications configuring itsSecurityFilterChain
? -
I had to use
@Lazy
for the injection ofJwtDecoder
- and also I'm not aware how this will affect different other applications