Issue
Spring recently deprecated WebSecurityConfigurerAdapter which does seem as not the smartest move, given that the new way is extremely poorly documented and WebSecurityConfigurerAdapter was basically omnipresent. Now I tried to add a custom Filter to the Security Filterchain, which was easy before but does seem to bring some trouble now.
I found a workaround, but it feels extremely overcomplicated and is not even remotely documented anywhere. If I use a code similar the the one below, I do get an instance of the authenticationManager and everything works fine.
public static class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
@Override
public void configure(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager =
http.getSharedObject(AuthenticationManager.class);
AuthFilter filter = new AuthFilter();
filter.setAuthenticationManager(authenticationManager);
System.out.println("Manager is" + authenticationManager);
// prints Manager is ProviderManager as expected
http.addFilter(filter);
}
public static MyCustomDsl customDsl() {
return new MyCustomDsl();
}
}
If I move the exact same code out of this hopefully unnecessary construct directly into the part below, then it does not work. The error I get is authentication Manager is null. I do assume it is related to when which Bean is created, but can't seem to find a cleaner solution than the one above.
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
AuthenticationManager authenticationManager =
http.getSharedObject(AuthenticationManager.class);
AuthFilter filter = new AuthFilter();
filter.setAuthenticationManager(authenticationManager);
System.out.println("Manager is" + authenticationManager);
// says: Manager is null
//more config
}
I might add, there is another strange behavior. I tried to build an instance like this (which seems intuitive).
AuthenticationManager authenticationManager = authenticationManagerBuilder.build();
However, this does not work as well. What is more strange: If I say build() - it errors with "already built". If I try to get it (since it seemingly was already build) - I get an null object. There is even a getorbuild method, but you guessed it, that errors as well. Quite strange to me.
I'd really appreciate if anyone can pin me in the right direction to get this clean and concise. Thanks.
Solution
In this post it says:
To create an AuthenticationManager that is available to the entire application you can simply register the AuthenticationManager as a @Bean.
With that said, if you need to use an AuthenticationManager
somewhere, you need to expose it as a bean. I'll assume that you already have an UserDetailsService
and PasswordEncoder
beans. You can do it like this:
@Bean
AuthenticationManager myAuthenticationManager(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder);
return provider::authenticate;
}
And now just inject it into your SecurityFilterChain
method:
@Bean
SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {
...
}
Be aware that the AuthenticationProvider
interface will be deprecated soon, stay tuned in the release notes for the future versions.
Answered By - Marcus Hert da Coregio
Answer Checked By - Clifford M. (JavaFixing Volunteer)