нам необходимо поддерживать как аутентификацию 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 использовать для какого пути.
Вы можете использовать следующий способ, чтобы гарантировать правильную обработку обеих цепочек фильтров:
@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
для предоставления и аутентификации шаблонов муравьев для защищенных путей. Этот параметр должен успешно обрабатывать оба метода аутентификации для указанных путей.
Spring Security DSL изменился с Spring Boot 2.x (Spring Security 5) и Spring Boot 3.x (Spring Security 6).
Спасибо за предложение, но, к сожалению, я до сих пор не могу заставить его работать. Если (по свойству) я включаю только один из двух фильтров, аутентификация работает так, как ожидается для включенных конечных точек фильтра. Если оба включены, вызывается только первая цепочка фильтров (в моем случае SAML), это вызывает AccessDeniedException()
. Если я добавлю anyRequest().permitAll()
в качестве последнего оператора в этом первом фильтре, я получу нулевую аутентификацию. Я не уверен, предназначено ли это, или мне просто чего-то не хватает, чтобы принудительно использовать вторую цепочку фильтров в случае, если первая не соответствует запрошенному пути.
Я прошу прощения. Похоже, возникла проблема с настройками, из-за которой срабатывает только первая цепочка фильтров.
Я наконец получил это. Основная идея здесь — использовать два отдельных фильтра, но оба необходимо настроить так, чтобы они работали только для определенного подмножества всех путей 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()
}
...
}
Насколько я вижу, класс
HttpSecurity
в Spring Security 6 не предоставляет методаrequestMatchers()
. Мы использовалиrequestMatchers()
в Spring Boot 2.7 (Spring Security 5.X), и нам нужно было обновить код при переходе на Spring Boot 3.