Spring Security does not let me login using one of my 2 authentication providers.
My application should be able to authenticate two types of users - User and Organization by checking information stored on the database. For that, I created two separate WebSecurityConfiguration classes, with different SecurityFilterChain, defining different form logins and using the 2 different authentication providers - which use two different UserDetailsService implementations (pointing to different repositories).
My endpoints for Organization work - both register and login, and the session is successfully created, but for User, my POST method on the login endpoint (/auth/login/user) is blocked - returning Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported] on IntelliJ as a warning, but the backend returns status 200 on Postman. The application does not crash, but the POST method is not completed - on debug, it completes as 405 and redirects the request to /auth/login/org.
This is OrgWebSecurityConfiguration's SecurityFilterChain:
@Bean
@CrossOrigin
public SecurityFilterChain orgSecurityFilterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.securityMatchers((matcher) -> matcher
.requestMatchers("/auth/*/org").anyRequest())
.authorizeHttpRequests()
.requestMatchers("/auth/register/**")
.permitAll()
.requestMatchers("/auth/login/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/auth/login/org")
.loginProcessingUrl("/auth/login/org")
.defaultSuccessUrl("/auth/org-login-success", true)
.permitAll()
.and()
.authenticationManager(orgAuthenticationManager(http))
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/auth/login?logout")
.permitAll();
return http.build();
}
UserWebSecurityConfiguration's SecurityFilterChain:
@Bean
@CrossOrigin
public SecurityFilterChain userSecurityFilterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.securityMatchers((matcher) -> matcher
.requestMatchers("/auth/*/user").anyRequest())
.authorizeHttpRequests()
.requestMatchers("/auth/register/**")
.permitAll()
.requestMatchers("/auth/login/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/auth/login/user")
.loginProcessingUrl("/auth/login/user")
.defaultSuccessUrl("/auth/login-success", true)
.permitAll()
.and()
.authenticationManager(userAuthenticationManager(http))
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/auth/login?logout")
.permitAll();
return http.build();
}
userAuthProvider:
@Bean
public DaoAuthenticationProvider userAuthProvider() {
DaoAuthenticationProvider userAuthenticationProvider = new DaoAuthenticationProvider();
userAuthenticationProvider.setUserDetailsService(userDetailsService);
userAuthenticationProvider.setPasswordEncoder(passwordEncoder());
return userAuthenticationProvider;
}
orgAuthProvider:
@Bean
public DaoAuthenticationProvider orgAuthProvider() {
DaoAuthenticationProvider orgAuthenticationProvider = new DaoAuthenticationProvider();
orgAuthenticationProvider.setUserDetailsService(organizationDetailsService);
orgAuthenticationProvider.setPasswordEncoder(passwordEncoder);
return orgAuthenticationProvider;
}
Both orgAuthenticationManager and userAuthenticationManager were created by defining an authentication provider of type DaoAuthenticationProvider and setting the proper UserDetailsService for each, implementing the created auth providers on AuthenticationManagerBuilder. In this case, User's authentication manager is set to be the primary one, by using @Primary annotation.
I've tried using @Order(0) annotation on UserWebSecurityConfiguration as per this question, but the problem persisted. I also disabled csrf.