Определите поставщиков аутентификации для каждого RequestMatchers (Spring Security 6)

нам необходимо поддерживать как аутентификацию SAML, так и базовую аутентификацию HTTP в одном из наших приложений. Мы настроили AuthenticationProvider для каждой конфигурации и также используем разные роли. Поскольку базовые пользователи HTTP имеют доступ (на основе ролей) только к определенному подмножеству API, я бы хотел разделить поставщиков аутентификации, чтобы соответствовать этой ситуации, поскольку нет необходимости проверять обоих поставщиков. При использовании Spring Security 5 документация рекомендует сделать что-то вроде:

    ...
    httpSecurity.antMatchers("/basic-path/**")
        .hasAnyAuthority("ROLE_BASIC")
        .and()
        .authenticationManager(basicAuthManager)
        .antMatchers("/other-path/**")
        .hasAnyAuthority("ROLE_SAML")
        .and()
        .authenticationManager(samlAuthManager)
    ...

В Spring Security 6 and() устарел, и у нас нет аналогичного способа указать authenticationManager(). На данный момент мы определяем:

    ...
    httpSecurity.authenticationManager(basicAuthManager)
        .authorizeHttpRequests { authorizationManagerRequestMatcherRegistry ->
            authorizationManagerRequestMatcherRegistry.requestMatchers("/basic-path/**")
                .hasAnyAuthority("ROLE_BASIC")
                ...
        }
    httpSecurity.authenticationManager(samlAuthManager)
        .authorizeHttpRequests { authorizationManagerRequestMatcherRegistry ->
            authorizationManagerRequestMatcherRegistry.requestMatchers("/other-path/**")
                .hasAnyAuthority("ROLE_SAML")
                ...
        }
    ...

    // this enables http basic globally on all paths
    httpSecurity.httpBasic {}

    // enable saml, also gobally
    httpSecurity.saml2Login { saml2LoginConfigurer ->
        saml2LoginConfigurer
            .authenticationManager(ProviderManager(samlAuthenticationProvider()))
         ...
    }

Я еще не мог найти способ указать, какой authenticationManager/authenticationProvider использовать для какого пути.

0
0
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете использовать следующий способ, чтобы гарантировать правильную обработку обеих цепочек фильтров:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

    private final AuthenticationManager basicAuthManager;
    private final AuthenticationManager samlAuthManager;

    public SecurityConfig(AuthenticationManager basicAuthManager, AuthenticationManager samlAuthManager) {
        this.basicAuthManager = basicAuthManager;
        this.samlAuthManager = samlAuthManager;
    }

    @Override
    public void configure(HttpSecurity http) {
        http
            .authorizeRequests(authorizeRequests ->
                authorizeRequests
                    .requestMatchers(new AntPathRequestMatcher("/basic-path/**"))
                    .hasAuthority("ROLE_BASIC")
                    .requestMatchers(new AntPathRequestMatcher("/other-path/**"))
                    .hasAuthority("ROLE_SAML")
                    .anyRequest()
                    .authenticated()
            )
            .addFilterBefore(new BasicAuthenticationFilter(basicAuthManager), SecurityContextPersistenceFilter.class)
            .addFilterBefore(new SAMLAuthenticationFilter(samlAuthManager), SecurityContextPersistenceFilter.class)
            .requestMatchers()
                .antMatchers("/basic-path/**", "/other-path/**")
            .and()
            .authorizeRequests()
                .antMatchers("/basic-path/**", "/other-path/**")
                .authenticated();
    }
}

Чтобы установить правила разрешения для обоих путей, используйте метод authorizeRequests. Перед SecurityContextPersistenceFilter добавьте оба фильтра аутентификации (BasicAuthenticationFilter и SAMLAuthenticationFilter). Укажите средства сопоставления запросов для путей, которые мы хотим защитить, с помощью функции requestMatchers. Наконец, мы используем функцию antMatchers для предоставления и аутентификации шаблонов муравьев для защищенных путей. Этот параметр должен успешно обрабатывать оба метода аутентификации для указанных путей.

Насколько я вижу, класс HttpSecurity в Spring Security 6 не предоставляет метода requestMatchers(). Мы использовали requestMatchers() в Spring Boot 2.7 (Spring Security 5.X), и нам нужно было обновить код при переходе на Spring Boot 3.

Jan Kohnert 13.09.2023 11:20

Spring Security DSL изменился с Spring Boot 2.x (Spring Security 5) и Spring Boot 3.x (Spring Security 6).

ooxvyd 13.09.2023 12:01

Спасибо за предложение, но, к сожалению, я до сих пор не могу заставить его работать. Если (по свойству) я включаю только один из двух фильтров, аутентификация работает так, как ожидается для включенных конечных точек фильтра. Если оба включены, вызывается только первая цепочка фильтров (в моем случае SAML), это вызывает AccessDeniedException(). Если я добавлю anyRequest().permitAll() в качестве последнего оператора в этом первом фильтре, я получу нулевую аутентификацию. Я не уверен, предназначено ли это, или мне просто чего-то не хватает, чтобы принудительно использовать вторую цепочку фильтров в случае, если первая не соответствует запрошенному пути.

Jan Kohnert 18.09.2023 14:06

Я прошу прощения. Похоже, возникла проблема с настройками, из-за которой срабатывает только первая цепочка фильтров.

ooxvyd 19.09.2023 12:26
Ответ принят как подходящий

Я наконец получил это. Основная идея здесь — использовать два отдельных фильтра, но оба необходимо настроить так, чтобы они работали только для определенного подмножества всех путей API. Поэтому Spring необходимо знать, применяется ли какой-либо из фильтров к определенному пути, прежде чем проверять requestMatcher()-настройки, чтобы определить, следует ли принять или отклонить запрос. Этого можно добиться, используя securityMatcher(), как показано в следующем примере:

class SecurityConfig {
    ...

    @Bean
    fun samlSecurityFilterChain(
        http: HttpSecurity,
        registrations: RelyingPartyRegistrationRepository
    ): SecurityFilterChain {
        // all "normal" users use SAML and paths matching the securityMatcher here 
        http.securityMatcher("/other-path/**")
            .authenticationManager(samlAuthManager)
            .authorizeHttpRequests { authorizationManagerRequestMatcherRegistry ->
                authorizationManagerRequestMatcherRegistry
                    .requestMatchers("/other-path/path1/**")
                    .hasAnyAuthority("ROLE_SAML_1")
                    .requestMatchers("/other-path/path2/**")
                    .hasAnyAuthority("ROLE_SAML_2")
                
                    ...
            }
        
            ...

        return http.build()
    }

    @Bean
    fun basicSecurityFilterChain(
        http: HttpSecurity
    ): SecurityFilterChain {
        // technical users use basic auth and the paths matching this securityMatcher
        http.securityMatcher("/basic-path/**")
            .authenticationManager(basicAuthManager)
            .authorizeHttpRequests { authorizationManagerRequestMatcherRegistry ->
                authorizationManagerRequestMatcherRegistry
                    .requestMatchers("/basic-path/path1/**")
                    .hasAnyAuthority("ROLE_BASIC_1")
                    .requestMatchers("/basic-path/path2/**")
                    .hasAnyAuthority("ROLE_BASIC_2")
                
                    ...
            }

        http.httpBasic(withDefaults())
        
            ...

        return http.build()
    }

    ...
}

Другие вопросы по теме