Home > Net >  I am not able to use my custom authentication provider along with DaoAuthenticationProivider in Spri
I am not able to use my custom authentication provider along with DaoAuthenticationProivider in Spri

Time:07-31

I have scenario. If the client sends the username and password then my application should use DaoAuthenticationProvider.Else if my client sent a header with "phrase" the it should use PhraseAuthenticationProvider(custom). I will point out what I did so far.

  1. I implemented UserDetailsService as CustomSecurityCustomerService and annotated as @Service
  2. I created a DaoAuthenticationProvider bean configuration as shown in below code snippet in security configuration class
public class ProjectSecurityConfigurer{
    
    @Autowired
    private AuthenticationConfiguration config;
    
    @Autowired
    PhraseAuthenticationProvider pProvider;
    
    @Bean
    ExtractionFilter getExFilter() throws Exception {
        return new ExtractionFilter(config.getAuthenticationManager());
    }

    @Bean
    SecurityFilterChain projectSecSpecs(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
        .antMatchers("/myaccount").authenticated()
        .antMatchers("/contact","/login").permitAll();
        http.httpBasic(Customizer.withDefaults());
        http.addFilterBefore(getExFilter(), BasicAuthenticationFilter.class);
        http.authenticationProvider(pProvider);
        return http.build();
    }
    
    
//  @Bean
//  JdbcUserDetailsManager usersInMemory(DataSource datasource) {
//      return new JdbcUserDetailsManager(datasource);
//  }
    
    @Bean
    DaoAuthenticationProvider getDaoBean(CustomerSecurityService service,PasswordEncoder encoder) {
         DaoAuthenticationProvider daoProvider= new DaoAuthenticationProvider();
         daoProvider.setUserDetailsService(service);
         daoProvider.setPasswordEncoder(encoder);
         return daoProvider;
        
    }
    
    @Bean
    PasswordEncoder encoder() {
        return NoOpPasswordEncoder.getInstance();
    }
    

}
  1. Implemented a PhraseAuthenticationToken which extends AbstractAuthenticationToken
  2. Implemented PhraseAuthenticationProvider as below
@Component
public class PhraseAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        
        Authentication authenticated = new PhraseAuthenticationToken("abc@123", null,null);
        return authenticated;
    }

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

}

This issue I am facing is if I create the DaoAuthenticationProvider bean then its not registering my PhraseAuthenticationProvider. My PhraseAuthenticationProvider only works if comment out the DaoAuthenticationProvider bean. How can I register both my DaoAuthenticationProvider and PhraseAuthenticationProvider and make it work based on the header passed

CodePudding user response:

You have not registered the your both AuthenticationProvider DaoAuthenticationProvider and PhraseAuthenticationProvider. Follow these steps and make changes accordingly to register both the authentication providers

The custom authentication can be implemented in two-step:

  1. Creating custom authentication provider
  2. Registering that custom authentication provider

1. Creating the custom authentication provider

In first step of creating custom authentication provider, decide which kinds of Authentication objects the new AuthenticationProvider supports? Override the supports() method accordingly and

In the second step, provide the implementation of Authentication logic by overriding the authenticate() method.

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {


  @Override
  public Authentication authenticate(Authentication authentication) {
    
    // Writh the authentication logic here...
    
  }

  @Override
  public boolean supports(Class<?> authenticationType) {
    // return authenticationType.equals(authenticationToken.class);
  }
}

2. Registering the Custom Authentication Provider

To plug in the custom implementation of the AuthenticationProvider, override the configure(AuthenticationManagerBuilder auth) method of the WebSecurityConfigurerAdapter class in the configuration class.

Note : To register the multiple AuthenticationProvider implementations, we can invoke the auth.authenticationProvider() for each provider separately.

@EnableWebSecurity
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private CustomAuthenticationProvider customAuthenticationProvider;

  @Override
  protected void configure(AuthenticationManagerBuilder auth) {
      auth.authenticationProvider(customAuthenticationProvider);

      //We can register as many providers as we may have
      
      //auth.authenticationProvider(customProviderTwo);
      //auth.authenticationProvider(customProviderThree);
  }

  // ...
}

CodePudding user response:

You can create authentication provider, which delegates the operation to another provider, based on some condition. A very simplified example:

@Component
public class DelegatingAuthenticationProvider implements AuthenticationProvider {

    private final List<AuthenticationProvider> providers;

    @Autowired
    public DelegatingAuthenticationProvider(List<AuthenticationProvider> providers) {
        this.providers = providers;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        for (AuthenticationProvider provider : this.providers) {
            if (provider.supports(authentication.getClass())) {
                return provider.authenticate(authentication);
            }
        }
        return null;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}

Basically provide dao and phrase providers to this one, it will delegate the operation to one of them based on supports(). You can check this question for information how to register your custom provider.

Tbh, registering both dao and phrase providers in the way mentioned in the above question will most probably achieve the same effect as this delegating provider, but i haven't tested it.

Edit: Didn't notice you are using the new way. According to what i see you are registering only the phrase provider. Did you try to register all providers? Like this, for example:

@Configuration
public class ProjectSecurityConfigurer {

  @Autowired
  private List<AuthenticationProvider> providers;

  @Bean
  SecurityFilterChain projectSecSpecs(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests()
            .antMatchers("/myaccount").authenticated()
            .antMatchers("/contact","/login").permitAll();
    http.httpBasic(Customizer.withDefaults());
    http.addFilterBefore(getExFilter(), BasicAuthenticationFilter.class);
    for (AuthenticationProvider provider : this.providers) {
      http.authenticationProvider(provider);
    }
    return http.build();
  }
}

Autowiring a list of AuthenticationProvider will pick up all beans of this type.

  • Related