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

How to logout from Saml IDP when I logout from my application

我是 SAML 安全和 KEYCLOAK 的新手。 我在 KEYCLOAK 中有一个使用 SAML 协议的客户端。我的应用程序配置为此 SAML 客户端。当我登录我的应用程序时,SAML 身份验证成功,我可以登录我的应用程序。用户会话也在 keycloak 中创建。在执行注销操作时,用户只是从我的应用程序中注销,而不是从 SAML.The 用户中注销。

如何执行注销以便同时清除 saml 会话。我发现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