Keycloak 多租户:一个领域的身份验证用于验证另一个领域



我正在使用key斗篷弹簧安全适配器来保护我的应用程序,我有两个key斗篷领域。

  • ;应用程序";realm用于单点登录并从Active Directory获取角色
  • ";S2S";领域用于系统到系统的通信;"载体";Authentication标头中的令牌,并且具有密钥斗篷配置bearer-only: true

我的应用程序中有两个端点

  • CCD_ 2由";应用程序";领域
  • CCD_ 3由";S2S";领域

我正在目睹的以下行为

  1. 在浏览器中,我点击了/s2s/client,得到了一个未经授权的401
  2. 在浏览器中,我点击/api/client,通过keycloft重定向进行SSO登录,最终从rest端点获得200响应
  3. 在浏览器中,当我从未为S2S领域提供密钥斗篷令牌时,我点击了/s2s/client并得到了200的响应

我有以下配置

security:
keycloak:
adapter-config:
s2s:
realm: S2S
resource: MyClient
auth-server-url: https://my-keycloak.com/auth
ssl-required: none
use-resource-role-mappings: true
public-client: true
bearer-only: true
applications:
realm: Applications
resource: MyClient
auth-server-url: https://my-keycloak.com/auth
ssl-required: none
use-resource-role-mappings: true
public-client: true

我有以下逻辑来选择一个基于URL的领域,它的灵感来自多租户文档

import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SecurityConfiguration {
@Bean
@ConfigurationProperties(prefix = "security.keycloak.adapter-config.s2s")
public AdapterConfig s2sAdapterConfig() {
return new AdapterConfig();
}
@Bean
@ConfigurationProperties(prefix = "security.keycloak.adapter-config.applications")
public AdapterConfig applicationsAdapterConfig() {
return new AdapterConfig();
}
@Bean
public KeycloakConfigResolver keycloakConfigResolver(
@Qualifier("s2sAdapterConfig") AdapterConfig s2sAdapterConfig,
@Qualifier("applicationsAdapterConfig") AdapterConfig applicationsAdapterConfig
) {
KeycloakDeployment s2sDeployment = KeycloakDeploymentBuilder.build(s2sAdapterConfig);
KeycloakDeployment applicationsDeployment = KeycloakDeploymentBuilder.build(applicationsAdapterConfig);
return request -> request.getRelativePath().startsWith("/s2s/") ? s2sDeployment : applicationsDeployment;
}
}   

我有以下@KeycloakConfiguration

@KeycloakConfiguration
public static class KeycloakSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(buildSessionRegistry());
}
@Bean
protected SessionRegistry buildSessionRegistry() {
return new SessionRegistryImpl();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeRequests()
.antMatchers("/api/**", "/s2s/**").authenticated()
.antMatchers("/actuator/**", "/error").permitAll();
}
}    

版本

18.0.2

预期行为

对于没有S2S领域的有效令牌的所有请求,对/s2s/*URL的请求应以401响应

实际行为

当使用已针对Applications领域进行身份验证的会话cookie请求时,对/s2s/*URL的请求将接收200 OK响应

如何复制

  1. 配置一个";应用程序";spring启动应用程序中的领域
  2. 配置一个";S2S";领域与bearer-only: true的应用
  3. 配置CCD_;应用程序";api*URL的领域
  4. 配置CCD_;S2S";s2s*URL的领域
  5. 在浏览器中点击api*URL并得到200响应(在以下针对SSO/cookie的密钥斗篷重定向之后(
  6. 在浏览器中点击s2s*URL,得到200的响应(应该是401(

我在密钥斗篷github存储库上提出了问题#14301,但没有得到及时的响应

在对spring-security源代码进行了一些挖掘之后,发现HttpSessionSecurityContextRepository将身份验证存储在会话中,然后用于后续请求。

我破解了以下的修复程序

import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
@KeycloakConfiguration
public static class KeycloakSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// workaround for https://github.com/keycloak/keycloak/issues/14301
SecurityContextRepository s2sRepository = new NullSecurityContextRepository();
SecurityContextRepository otherRepository = new HttpSessionSecurityContextRepository();
SecurityContextRepository repositoryDelegator = new SecurityContextRepository() {
@Override
public SecurityContext loadContext(HttpRequestResponseHolder requestResponse) {
return getSecurityContextRepository(requestResponse.getRequest()).loadContext(requestResponse);
}
@Override
public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
getSecurityContextRepository(request).saveContext(context, request, response);
}
@Override
public boolean containsContext(HttpServletRequest request) {
return getSecurityContextRepository(request).containsContext(request);
}
private SecurityContextRepository getSecurityContextRepository(HttpServletRequest request) {
return request.getServletPath().startsWith("/s2s/") ? s2sRepository : otherRepository;
}
};
super.configure(http);
http
.securityContext().securityContextRepository(repositoryDelegator).and()
.authorizeRequests()
.antMatchers("/api/**", "/s2s/**").authenticated()
.antMatchers("/actuator/**", "/error").permitAll();
}
...
}

不要为spring使用密钥斗篷库它已被弃用(可能是没有得到及时响应的原因(。阅读这篇文章以了解其他选择。

使用JWT,您应该使用无会话(会话管理设置为无状态(。这会解决你的问题。

附带说明一下,本文末尾引用的spring-addons starter lib确实处理了多租户。

相关内容

  • 没有找到相关文章

最新更新