简体   繁体   中英

Spring security with multiple providers

I am setting up an app with 2 differents users:

  • one from my ldap that can connect with cas authentication
  • one external, hard coded with a simple formlogin

I created 2 Security configurations:

External User Configuration:

@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
@Order(1)
public class SecurityVanuatuConfiguration extends WebSecurityConfigurerAdapter {

@Bean
@Override
public UserDetailsService userDetailsService() {
    UserDetails user =
        User.withUsername("user")
            .password("{noop}user")
            .roles("USER")
            .build();

    return new InMemoryUserDetailsManager(user);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable().antMatcher("/user/**")
        .authorizeRequests()
        .requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginPage(LOGIN_URL).permitAll()
        .loginProcessingUrl(LOGIN_PROCESSING_URL)
        .failureUrl(LOGIN_FAILURE_URL)
        .successHandler(successHandler)
        .failureHandler(successHandler)
        .and().logout().logoutSuccessUrl(LOGOUT_SUCCESS_URL);
}

Cas Configuration:

@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
@Order(2)
public class SecurityCasConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable().antMatcher("/admin/**")
        .authorizeRequests()
        .requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()
        .anyRequest().authenticated()
        .and()
        .httpBasic()
        .authenticationEntryPoint(authenticationEntryPoint())
        .and()
        .addFilter(casAuthenticationFilter())
        .addFilterBefore(casLogoutFilter(), CasAuthenticationFilter.class);
}

@Bean
public SingleSignOutFilter casLogoutFilter() {
    SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
    return singleSignOutFilter;
}

// if I remove this bean, external configuration works
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
    CasAuthenticationProvider provider = new CasAuthenticationProvider();
    provider.setServiceProperties(serviceProperties());
    provider.setTicketValidator(new Cas30ServiceTicketValidator("https://sso.unc.nc/cas"));
    provider.setKey("cas");
    provider.setAuthenticationUserDetailsService(successHandler);
    return provider;
}

Each configuration work when it's alone, but when there is both, the external doesn't work.

It seems that the CasAuthenticationProvider bean prevent the formLogin to work and I endup in the FailureHandler.

Here is the error:

org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken

How can I make these 2 configuration work together?

when you mark something as @Bean you are putting it in the pool of beans that spring can use to inject into classes if they need it.

you have registered

@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
    ...
}

as a @Bean which is an AuthenticationProvider . When you register this using @Bean it will get picked up by everyone that needs it, meaning that both your WebSecurityConfigurerAdapter will use it.

Spring has no way of knowing that you only want this is in one of your security configurations and not the other.

you have to explicitly define that you want it in one and not the other by removing @Bean and setting it manually.

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

public CasAuthenticationProvider casAuthenticationProvider() {
    ...
}

You have to always decied if you want to set something manually, or use @Bean and let spring inject it for you.

So for instance, you are registering a filter (casLogoutFilter) setting it manually but also defining it as @Bean telling spring to inject it into the filter chain, which sort of doesn't make sense.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM