【问题标题】:spring boot actuator endpoints with Keycloak security具有 Keycloak 安全性的 Spring Boot 执行器端点
【发布时间】:2022-01-18 14:13:12
【问题描述】:

我们有一个带有执行器端点的 Spring Boot 项目 (2.3.0.RELEASE),我们正在使用 KeycloakWebSecurityConfigurerAdapter 将 keycloak 引入项目中,如何防止执行器端点受到 keycloak 过滤器链的保护。

我们希望通过基本身份验证保护“/actuator/**”端点。

目前我们有一个带有 @Order(1) 的自定义 WebSecurityConfigurerAdapter,我们将基本身份验证应用于“/actuator/**”,然后我们使用 @Order(2) 对 KeycloakWebSecurityConfigurerAdapter 进行了注释

所以 2 个过滤器链被注册,当我调用执行器端点时,第二个过滤器链因未授权 401 而失败

是否可以防止在第二个过滤器链上处理“/actuator/**”资源路径?

第一个执行器安全配置。

@Configuration
@Order(1)
public class ActuatorWebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final String username;
    private final String password;
    private final PasswordEncoder encoder;

    public ActuatorWebSecurityConfig(
            @Value("${spring.security.user.name}") String username,
            @Value("${spring.security.user.password}") String password,
            Optional<PasswordEncoder> encoder) {
        this.username = username;
        this.password = password;
        this.encoder = encoder.orElseGet(PasswordEncoderFactories::createDelegatingPasswordEncoder);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser(username)
                .password(encoder.encode(password))
                .roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .antMatcher("/actuator/**")
                .authorizeRequests(authorize -> authorize.anyRequest().authenticated())
                .httpBasic(Customizer.withDefaults());
    }
}

第二个keycloak安全配置

@Order(2)
@KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    private final String swaggerUrl;
    private final CorsFilter corsFilter;
    private final CustomSecurityConfig customSecurityConfig;

    @Autowired
    public SecurityConfig(
            @Value("${springdoc.swagger-ui.url:#{null}}") String swaggerUrl,
            CorsFilter corsFilter,
            CustomSecurityConfig customSecurityConfig) {
        this.swaggerUrl = swaggerUrl;
        this.corsFilter = corsFilter;
        this.customSecurityConfig = customSecurityConfig;
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        KeycloakAuthenticationProvider keycloakProvider = keycloakAuthenticationProvider();
        keycloakProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakProvider);
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new NullAuthenticatedSessionStrategy();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.csrf().disable()
            .requestMatcher(new NegatedRequestMatcher(new AntPathRequestMatcher("/actuator/**")));
            .headers().frameOptions().disable()
        .and()
           .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .authorizeRequests()
           .antMatchers("/public/**", "/resources/**", "/resources/public/**").permitAll()
           .antMatchers(OPTIONS, "/**").permitAll();
        .authorizeRequests()
           .antMatchers("/**")
           .authenticated();
    }
}

我已经尝试过使用 keycloak 配置

.antMatchers("/actuator/**").permitAll();

http.requestMatcher(new NegatedRequestMatcher(new AntPathRequestMatcher("/actuator/**")));

但没有任何效果我收到未授权的执行器 401

已注册的过滤器链:

2022-01-18 17:38:44,688 INFO org.springframework.security.web.DefaultSecurityFilterChain [main] Creating filter chain: Ant [pattern='/actuator/**'], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@25c6a9de, org.springframework.security.web.context.SecurityContextPersistenceFilter@56f3f9da, org.springframework.security.web.header.HeaderWriterFilter@33dcbdc2, org.springframework.security.web.csrf.CsrfFilter@522fdf0c, org.springframework.security.web.authentication.logout.LogoutFilter@365ad794, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@23df16cf, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@227cba85, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@b38dc7d, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@142422a4, org.springframework.security.web.session.SessionManagementFilter@2f0b7b6d, org.springframework.security.web.access.ExceptionTranslationFilter@74bca236, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@30587737]
2022-01-18 17:38:44,691 INFO org.springframework.security.web.DefaultSecurityFilterChain [main] Creating filter chain: NegatedRequestMatcher [requestMatcher=Ant [pattern='/actuator/**']], [com.betex.auth.filters.CorsFilter@20a9f5fb, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@10e28d97, org.springframework.security.web.context.SecurityContextPersistenceFilter@c6b08a5, org.springframework.security.web.header.HeaderWriterFilter@5f05cd7e, org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter@2a54c92e, org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter@55b62db8, org.springframework.security.web.authentication.logout.LogoutFilter@274f51ad, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@54980154, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@25874884, org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter@8cb7185, org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter@4dac40b, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@37d43b9b, org.springframework.security.web.session.SessionManagementFilter@11e8e183, org.springframework.security.web.access.ExceptionTranslationFilter@56f1db5f, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@78543f0d]

【问题讨论】:

  • 您是否尝试调试FilterChainProxy#doFilterInternal 以查看正在调用哪个过滤器链?另外,我建议将logging.level.org.springframework.security=TRACE 添加到您的application.properties 文件中,并确切知道谁在拒绝您访问
  • @MarcusHertdaCoregio 是的,KeycloakAuthenticationProcessingFilter 未通过,未找到授权标头,请参阅 WWW-Authenticate 标头
  • 在这里您可以阅读我提供的答案,如何从 spring security stackoverflow.com/questions/70717704/… 中完全排除路径,您可以尝试一下
  • @Toerktumlare ths but is not working 无论哪个过滤器链映射到奇怪的请求,都会调用 KeycloakAuthenticationProcessingFilter
  • @MarcusHertdaCoregio 即使我有两个不同的过滤器链,第一个过滤器链中没有 KeycloakAuthenticationProcessingFilter 但无论如何都是调用者...看起来它已在通过 VirtualFilterChain 应用的内部过滤器列表中注册...有什么办法可以避免这种情况?

标签: spring-boot spring-security keycloak spring-boot-actuator actuator


【解决方案1】:

当您扩展KeycloakWebSecurityConfigurerAdapter 时,适配器会注册一个KeycloakAuthenticationProcessingFilter 类型的Bean。这个过滤器注册在 Spring Security 的SecurityFilterChain 中,因为它是一个 Bean,所以 Spring Boot 也会自动在原链中注册,所以即使 Spring Security 不应用它,也会在后面应用到原链中过滤器链。

尝试禁止这个过滤器被 Spring Boot 注册,如下所示:

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

此外,如果您使用的是 OAuth 2,您可以考虑使用 spring-security-oauth2-resource-server 并简化您的资源服务器的配置。看看documentation。这样您就不需要扩展自定义适配器,只需依赖 Spring Security 的开箱即用配置即可。

【讨论】:

  • Marcus thnx 的信息看起来很有效,我知道避免 KeycloakWebSecurityConfigurerAdapter 可能会很有趣,以避免对 keycloak 的额外依赖,但是您对此有何松动,可能 KeycloakWebSecurityConfigurerAdapter 添加了一些额外的东西好不好?我们使用 OAuth2。
  • 如果您没有使用适配器的任何特殊功能,您应该不会丢失任何东西。它将表现相同,接收 Bearer 令牌,提取它,并使用从您配置的 issuer-uri 返回的 JWK 对其进行验证。
猜你喜欢
  • 2018-09-11
  • 2016-08-26
  • 2020-01-03
  • 2014-11-21
  • 2022-09-28
  • 2018-08-05
  • 2018-12-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多