Spring Boot Security PreAuthenticated Scenario with Anonymous access

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot Security PreAuthenticated Scenario with Anonymous access相关的知识,希望对你有一定的参考价值。

我有一个Spring Boot(1.5.6)应用程序正在使用Spring Security的“pre-authenticated”身份验证方案(SiteMinder)。

我需要匿名公开执行器“运行状况”端点,这意味着对该端点的请求不会通过SiteMinder,因此,HTTP请求标头中不会出现SM_USER标头。

我面临的问题是,无论我如何尝试配置“运行状况”端点,框架都会抛出org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException,因为当请求未通过SiteMinder时,预期的标头(“SM_USER”)不存在。

这是我最初的安全配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .authorizeRequests().antMatchers("/cars/**", "/dealers/**")
                .hasAnyRole("CLIENT", "ADMIN")
            .and()
                .authorizeRequests().antMatchers("/health")
                .permitAll()
            .and()
                .authorizeRequests().anyRequest().denyAll()
            .and()
                .addFilter(requestHeaderAuthenticationFilter())
                .csrf().disable();
    }

    @Bean
    public Filter requestHeaderAuthenticationFilter() throws Exception {
        RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
        filter.setAuthenticationManager(authenticationManager());
        return filter;
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(preAuthProvider());
    }

    @Bean
    public AuthenticationProvider preAuthProvider() {
        PreAuthenticatedAuthenticationProvider authManager = new PreAuthenticatedAuthenticationProvider();
        authManager.setPreAuthenticatedUserDetailsService(preAuthUserDetailsService());
        return authManager;
    }

    @Bean
    public AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> preAuthUserDetailsService() {
        return new UserDetailsByNameServiceWrapper<>(inMemoryUserDetails());
    }

    @Bean
    public UserDetailsService inMemoryUserDetails() {
        return new InMemoryUserDetailsManager(getUserSource().getUsers());
    }

    @Bean
    public UserHolder getUserHolder() {
        return new UserHolderSpringSecurityImple();
    }

    @Bean
    @ConfigurationProperties
    public UserSource getUserSource() {
        return new UserSource();
    }

我试图以几种不同的方式排除/ health端点无济于事。

我试过的事情:

为匿名访问而不是permitAll配置健康端点:

http
   .authorizeRequests().antMatchers("/health")
   .anonymous()

配置WebSecurity以忽略运行状况终结点:

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/health");
}

关闭所有执行器端点的安全性(不知道,但我抓住了吸管):

management.security.enabled=false

查看日志,问题似乎是RequestHeaderAuthenticationFilter被注册为顶级过滤器而不是现有securityFilterChain中的过滤器:

.s.DelegatingFilterProxyRegistrationBean : Mapping filter: 'springSecurityFilterChain' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'webRequestLoggingFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestHeaderAuthenticationFilter' to: [/*]

基于我的理解,因为RequestHeaderAuthenticationFilter扩展了AbstractPreAuthenticatedProcessingFilter,所以框架知道在链中插入过滤器的位置,这就是为什么我没有修改addFilterBefore或addFilterAfter变体。也许我应该?有人知道明确插入过滤器的正确位置吗? (我认为在Spring Security的早期版本中删除了显式指定过滤器顺序的需要)

我知道我可以配置RequestHeaderAuthenticationFilter,这样如果标头不存在它就不会抛出异常,但是如果可能的话我想保持它。

我发现这个SO帖子似乎与我的问题相似,但遗憾的是那里也没有答案。 spring-boot-security-preauthentication-with-permitted-resources-still-authenti

任何帮助将不胜感激!谢谢!

答案

问题确实是RequestHeaderAuthenticationFilter既被注册为顶级过滤器(不需要的),也被注册在Spring Security FilterChain(期望的)中。

“双重注册”的原因是因为Spring Boot会自动向Servlet容器注册任何Filter Bean。

为了防止“自动注册”,我只需要像这样定义一个FilterRegistrationBean

@Bean
public FilterRegistrationBean registration(RequestHeaderAuthenticationFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(filter);
    registration.setEnabled(false);
    return registration;
}

文件:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-disable-registration-of-a-servlet-or-filter

一个替代/更简单的解决方案:只是不要将RequestHeaderAuthenticationFilter类标记为@Bean,这很好,因为该特定滤波器不需要任何DI。通过不使用@Bean标记过滤器,Boot不会尝试自动注册它,这样就无需定义FilterRegistrationBean。

以上是关于Spring Boot Security PreAuthenticated Scenario with Anonymous access的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot Security

Understand Spring Security Architecture and implement Spring Boot Security

如何使用 Spring-Boot 播种 Spring-Security

Spring Boot整合Spring Security总结

Spring Boot:整合Spring Security

spring boot 整合spring security中spring security版本升级的遇到的坑