javaspring-mvcspring-securitycustom-authenticationbeancreationexception

Unable to implement CustomAuthenticationProvider with Spring Security: BeanCreationException while autowiring


I am implementing CustomAuthenticationProvider in Spring Security. I have created the CustomAuthenticationProvider class which implements AuthenticationProvider. However, when I define this CustomAuthenticationProvider in my SecurityConfiguration class and autowire it, the application throws following error:

2020-03-08 19:27:42 [main] ERROR o.s.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'securityConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.highrise.isimwebapp.config.customauth.CustomAuthenticationProvider com.highrise.isimwebapp.config.SecurityConfiguration.authProvider; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.highrise.isimwebapp.config.customauth.CustomAuthenticationProvider] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

I have included the @Component annotation in my CustomAuthenticationProvider class. Also, the package under which this class is defined, is included in the @ComponentScan. The context is not picking up CustomAuthenticationProvider bean. The other defined classes are successfully getting picked up by the context as defined in the @ComponentScan and no such error is received on their autowired objects. What could be wrong from my side? Any help regarding how this can be fixed would be highly appreciated.

CustomAuthenticationProvider.java

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    // TODO Auto-generated method stub
    String name = authentication.getName();
    String password = authentication.getCredentials().toString();
    if(name.equalsIgnoreCase("testuser1") && password.equalsIgnoreCase("demo"))
        return new UsernamePasswordAuthenticationToken(name, password);
    else
        throw new BadCredentialsException("Authentication failed");
}

@Override
public boolean supports(Class<?> authentication) {
    // TODO Auto-generated method stub
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
}

}

SecurityConfiguration.java

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
private CustomAuthenticationProvider authProvider;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authProvider);
}

@Override
protected void configure(HttpSecurity http) throws Exception {

  http.authorizeRequests()
    .antMatchers("/resources/**").permitAll()
    .antMatchers("/icon/**").permitAll()
    .anyRequest().authenticated()
    .and().formLogin().loginPage("/login").usernameParameter("username").passwordParameter("password").permitAll().defaultSuccessUrl("/persons/listall")
    .and().csrf().disable();

}
}

SpringWebConfig.java

@EnableWebMvc
@Configuration
@ComponentScan({ "com.highrise.isimwebapp.config", "com.highrise.isimwebapp.config.customauth", "com.highrise.isimwebapp.config.servlet3", "com.highrise.isimwebapp.web", "com.highrise.isimwebapp.service", "com.highrise.isimwebapp.dao",
    "com.highrise.isimwebapp.exception", "com.highrise.isimwebapp.validator" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}

@Bean
public InternalResourceViewResolver viewResolver() {
    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
    viewResolver.setViewClass(JstlView.class);
    viewResolver.setPrefix("/WEB-INF/views/jsp/");
    viewResolver.setSuffix(".jsp");
    return viewResolver;
}

@Bean
public ResourceBundleMessageSource messageSource() {
    ResourceBundleMessageSource rb = new ResourceBundleMessageSource();
    rb.setBasenames(new String[] { "messages/messages", "messages/validation" });
    return rb;
}

}

Solution

  • The problem is probably in the ordering of the package scanning, I can suggest you two approaches:

    1. Move the @ComponentScan("com.highrise.isimwebapp.config.customauth") to the SecurityConfiguration class.
    2. Remove the @Component annotation from the CustomAuthenticationProvider class and declare the @Bean inside the SecurityConfiguration, something like the following:
    @Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthProvider());
      }
    
      @Override
      protected void configure(HttpSecurity http) throws Exception {
    
        http.authorizeRequests()
          .antMatchers("/resources/**").permitAll()
          .antMatchers("/icon/**").permitAll()
          .anyRequest().authenticated()
     .and().formLogin().loginPage("/login").usernameParameter("username").passwordParameter("password").permitAll().defaultSuccessUrl("/persons/listall")
        .and().csrf().disable();
    
      }
    
      @Bean
      public CustomAuthenticationProvider customAuthProvider() {
        return new CustomAuthenticationProvider();
      }
    }