Summary
Registering a custom UsernamePasswordAuthenticationFilter Bean produces java.lang.IllegalArgumentException: authenticationManager must be specified error.
Actual Behavior
When I add a custom UsernamePasswordAuthenticationFilter in the @Configuration class that extends WebSecurityConfigurerAdapter, Spring application fails to run.
2020-04-02 22:53:09.405 ERROR 58116 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:156) ~[spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
...
Caused by: java.lang.IllegalArgumentException: authenticationManager must be specified
at org.springframework.util.Assert.notNull(Assert.java:198) ~[spring-core-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.afterPropertiesSet(AbstractAuthenticationProcessingFilter.java:164) ~[spring-security-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1855) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1792) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
... 56 common frames omitted
Expected Behavior
Spring application should run successfully without error even after the custom UsernamePasswordAuthenticationFilter filter Bean has been added.
Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic()
.and()
.addFilterBefore(getSimpleAuthFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public SimpleUsernamePasswordAuthFilter getSimpleAuthFilter() throws Exception {
return new SimpleUsernamePasswordAuthFilter(authenticationManager());
}
}
Version
spring-boot-2.2.6.RELEASE spring-security-web:5.2.2.RELEASE
Sample
https://github.com/HomoEfficio/spring-security-practice
Comment From: rwinch
Thanks for the report and the simple example to recreate your issue. This is not a bug. The issue was with SimpleUsernamePasswordAuthFilter which had a separate reference to AuthenticationManager. This means there was an unused (null) variable in UsernamePasswordAuthenticationFilter. It also meant that SimpleUsernamePasswordAuthFilter.setAuthenticationManager was setting an
AuthenticationManager that would never be used.
I sent a PR to your sample repository https://github.com/HomoEfficio/spring-security-practice/pull/1
Comment From: HomoEfficio
@rwinch Thanks for the kind and warm answer, and PR.
Considering the responsibilities and usages of the AbstractAuthenticationProcessingFilter, authenticationManager property seems to be required, not optional.
So it is better to use constructor injection rather than to use setter injection, especially for the required properties.
But for now, the required property authenticationManager can only be set by setter method, which does not look so great in my opinion, and it leads to this uncomfortable issue.
What about adding another constructor that receives an AuthenticationManager to the AbstractAuthenticationProcessingFilter so we can seamlessly use constructor injection?
If you think this is reasonable, I will make another PR, including some follow-up changes for the UsernamePasswordAuthenticationFilter.
Comment From: rwinch
Thanks for your offer to help! I am ok with adding a constructor that accepts AuthenticationManager, but we cannot remove the old constructor for passivity reasons. If you are alright with submitting a PR, I can review it once you submit it.