0

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;
}

}
js.hrt
  • 159
  • 2
  • 14
  • Isn't it a problem in the ordering of the scanning? What happens if you specify the `@ComponentScan("com.highrise.isimwebapp.config.customauth")` directly on your `SecurityConfiguration`? – Marcos Barbero Mar 08 '20 at 15:38
  • @MarcosBarbero This solved the issue. I included it directly in the SecurityConfiguration as per your suggestion and it worked! Thank you. Don't know what it wasn't getting scanned their with the other classes.. However, now I am getting error in CustomAuthenticationProvider class after successfully logging in with the defined username and password. I get a NullPointerExveption at the line where I try to get the password: String password = authentication.getCredentials().toString(); – js.hrt Mar 08 '20 at 15:48
  • You also need to define the `authenticationProvider` in the `configure(HttpSecurity)` method – Marcos Barbero Mar 08 '20 at 15:50
  • @MarcosBarbero Ok..Can you guide a little bit on how to do that? Because I do not seem to get this part in the examples on the internet... – js.hrt Mar 08 '20 at 16:28
  • After your `permitAll` something like this `.permitAll().and().authenticationProvider(authProvider).//rest of your code`. – Marcos Barbero Mar 08 '20 at 16:30
  • @MarcosBarbero Unfortunately not able to make that work. After permitAll, if I write: .and().authenticationProvider(authProvider). eclipse starts showing red line on .anyRequest which is underneath. Then I entered this: .and().authenticationProvider(authProvider).authorizeRequests() then the red line went away but still getting the same NullPointerException when I execute the code – js.hrt Mar 08 '20 at 16:55
  • Solved after adding (Collection extends GrantedAuthority>) new ArrayList<>() as a third argument in UsernamePasswordAuthenticationToken when it is returned back from the authenticate function..thanks – js.hrt Mar 08 '20 at 17:17
  • @MarcosBarbero can you write your first comment as answer so that I can mark it as answer? The comment where you suggest to add ComponentScan directly in SecurityConfiguration – js.hrt Mar 08 '20 at 17:19
  • I'm glad you figured! I'll write the answer down, thanks for it! – Marcos Barbero Mar 08 '20 at 17:21
  • No problem, thanks to you for helping...regards – js.hrt Mar 08 '20 at 19:52

1 Answers1

1

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();
  }
}

Marcos Barbero
  • 1,101
  • 8
  • 14