java - 当我从我的应用程序注销时如何从 Saml IDP 注销

标签 java spring-boot keycloak saml

我是 SAML 安全性和 KEYCLOAK 的新手。 我有一个使用 SAML 协议(protocol)的 KEYCLOAK 客户端。我的应用程序已配置到此 SAML 客户端。当我登录到我的应用程序时,SAML 身份验证成功,我可以登录到我的应用程序。用户 session 也是在 keycloak 中创建的。执行注销操作时,用户只是从我的应用程序注销,而不是从 SAML 注销。用户保持 Activity 状态。

如何执行注销以便 saml session 也被清除。我发现spring saml支持“/saml/logout”来清除 session 。但是这个 url 需要从浏览器显式调用,然后再次必须从我的应用程序执行注销。有没有办法一次性执行这两个调用。

下面是我的 samlSecurityconfig java 代码:

 @Bean
public FilterChainProxy samlFilter() throws Exception {
    List<SecurityFilterChain> chains = new ArrayList<>();
    chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/login/**"),
            samlEntryPoint()));
    chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/logout/**"),
            samlLogoutFilter()));
    chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/metadata/**"),
            metadataDisplayFilter()));
    chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSO/**"),
            samlWebSSOProcessingFilter()));
    chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSOHoK/**"),
            samlWebSSOHoKProcessingFilter()));
    chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SingleLogout/**"),
            samlLogoutProcessingFilter()));
    return new FilterChainProxy(chains);
}

  // Handler for successful logout
@Bean
public SimpleUrlLogoutSuccessHandler successLogoutHandler() {
    SimpleUrlLogoutSuccessHandler successLogoutHandler = new CustomSimpleUrlLogoutSuccessHandler();
    successLogoutHandler.setDefaultTargetUrl(config().getSp().getEntityBaseURL());
    return successLogoutHandler;
}

// Logout handler terminating local session
@Bean
public SecurityContextLogoutHandler logoutHandler() {
    SecurityContextLogoutHandler logoutHandler =
            new SecurityContextLogoutHandler();
    logoutHandler.setInvalidateHttpSession(true);
    logoutHandler.setClearAuthentication(true);
    return logoutHandler;
}

// Filter processing incoming logout messages
// First argument determines URL user will be redirected to after successful
// global logout
@Bean
public SAMLLogoutProcessingFilter samlLogoutProcessingFilter() {
    return new SAMLLogoutProcessingFilter(successLogoutHandler(),
            logoutHandler());
}

// Overrides default logout processing filter with the one processing SAML
// messages
@Bean
public SAMLLogoutFilter samlLogoutFilter() {
    return new SAMLLogoutFilter(successLogoutHandler(),
            new LogoutHandler[]{logoutHandler()},
            new LogoutHandler[]{logoutHandler()});
}
@Bean
public FilterChainProxy samlFilter() throws Exception {
    List<SecurityFilterChain> chains = new ArrayList<>();
    chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/login/**"),
            samlEntryPoint()));
    chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/logout/**"),
            samlLogoutFilter()));
    chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/metadata/**"),
            metadataDisplayFilter()));
    chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSO/**"),
            samlWebSSOProcessingFilter()));
    chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSOHoK/**"),
            samlWebSSOHoKProcessingFilter()));
    chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SingleLogout/**"),
            samlLogoutProcessingFilter()));
    return new FilterChainProxy(chains);
}
 @Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .httpBasic()
            .authenticationEntryPoint(samlEntryPoint());
    http
            .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            .ignoringAntMatchers("/saml/**");
    http
            .addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class)
            .addFilterAfter(samlFilter(), BasicAuthenticationFilter.class);
    http
            .logout()
            .logoutRequestMatcher(new AntPathRequestMatcher("/saml/logout"))
            .deleteCookies("JSESSIONID")
            .logoutSuccessUrl(config().getSp().getEntityBaseURL() + LOGIN);
    http
            .headers()
            .frameOptions()
            .disable();
    http
            .sessionManagement()
            .sessionAuthenticationErrorUrl(config().getSp().getEntityBaseURL() + LOGIN)
            .invalidSessionUrl(config().getSp().getEntityBaseURL() + LOGIN);
    http
            .sessionManagement()
            .maximumSessions(1)
            .expiredUrl(config().getSp().getEntityBaseURL() + LOGIN);
    http
            .sessionManagement()
            .sessionFixation()
            .newSession();
    http
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.NEVER);

    permitEndpoints(http);
}

public class CustomSimpleUrlLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
                                Authentication authentication) throws IOException, ServletException {
        if(config().getSp().getEntityBaseURL().equalsIgnoreCase(this.getDefaultTargetUrl())) {
            URLBuilder builder = new URLBuilder(request.getRequestURL().toString());
            builder.setPath("/");
            builder.setFragment("/login");
            builder.setPort(CmsUtil.getWebServerPort());
            this.setDefaultTargetUrl(builder.buildURL());
        }
        super.onLogoutSuccess(request, response, authentication);
    }
}

请帮忙

最佳答案

为了支持全局注销,IDP 服务器应该公开注销 URL(简单的方法是如果元数据包含 SingleLogoutService) 更多信息您可以从这里获取 https://docs.spring.io/spring-security/reference/servlet/saml2/logout.html

本地注销可以引用spring saml: How is LOGOUT handled? Is it mandatory to have logout endpoint in IDP metadata xml?

对于全局注销,您只需在上述接受的答案中的查询参数中删除 local=true,即只需发送 /saml/logout

更多注销相关信息可以引用https://docs.spring.io/spring-security-saml/docs/1.0.x-SNAPSHOT/reference/htmlsingle/#configuration-logout

关于java - 当我从我的应用程序注销时如何从 Saml IDP 注销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71338734/

相关文章:

java - 设备中的应用名称

java - 构造函数必须在方法返回之前调用 super() 或 this()

java - WordNet Java API

java - 如何使用 ZUUL 处理多个服务的 POST 请求

java - 使用 keycloak 管理客户端以编程方式为具有 access-type public 的客户端创建用户

javascript - 如果 Keycloak 身份验证是在 Apache 级别而不是前端应用程序上完成的,是否有办法获取用户数据

javac 错误不可转换类型 java.lang.Double

java - Spring Boot属性在初始化时加载并尊重所有并根据属性文件中的值控制@Aspect

java - 形成pojo来解析JSON

Keycloak 4.3.0 无限循环场景