Spring security SP超时时SLO失败

Spring security SP超时时SLO失败,spring-security,spring-saml,Spring Security,Spring Saml,使用Spring Security SAML 1.0.10,当SP上的SAML会话超时,但IdP上仍处于活动状态时,SLO尝试失败 如何繁殖 将会话超时设置为一分钟(server.servlet.session=1m) 登录您的SP 登录到其他辅助SP-它必须使用SSO 请等待一分钟,等待会话超时 在辅助SP上进行锁定 这会在Spring中导致ClassCastException,因为SecurityContextHolder.getContext().getAuthentication()包含

使用Spring Security SAML 1.0.10,当SP上的SAML会话超时,但IdP上仍处于活动状态时,SLO尝试失败

如何繁殖

  • 将会话超时设置为一分钟(server.servlet.session=1m)
  • 登录您的SP
  • 登录到其他辅助SP-它必须使用SSO
  • 请等待一分钟,等待会话超时
  • 在辅助SP上进行锁定
  • 这会在Spring中导致ClassCastException,因为
    SecurityContextHolder.getContext().getAuthentication()
    包含不包含凭据的
    AnonymousAuthenticationToken
    。它还会断开过滤链,并且永远不会向IdP发送LogoutResponse,并且浏览器中会显示错误页面

    java.lang.ClassCastException: class java.lang.String cannot be cast to class org.springframework.security.saml.SAMLCredential (java.lang.String is in module java.base of loader 'bootstrap'; org.springframework.security.saml.SAMLCredential is in unnamed module of loader 'app')
    at org.springframework.security.saml.SAMLLogoutProcessingFilter.processLogout(SAMLLogoutProcessingFilter.java:172)
    
    这是故意的,是一个bug,还是我对某些东西的配置有误?
    如果是故意的或是错误,是否存在解决方法?

    错误发生在
    SAMLLogoutProcessingFilter.processLogout()
    中,其中以下代码导致ClassCastException。如果用户会话超时,
    auth.getCredentials()
    返回空字符串

    SAMLCredential credential = null;
    if (auth != null) {
        credential = (SAMLCredential)auth.getCredentials();
    }
    
    我发现的唯一解决方法是创建一个LogoutFilter来处理这个问题

    我创建了一个新的LogoutFilter,扩展了SAMLLogoutProcessingFilter。对于LogoutRequest和匿名AuthenticationToken,我创建了LogoutResponse。在任何其他情况下,我转发到SAMLLogoutProcessingFilter,或者调用SAMLLogoutProcessingFilter中方法的副本,在这里我删除了失败的部分

      private void overwrittenLogout(HttpServletRequest request, HttpServletResponse response, SAMLMessageContext context)
          throws ServletException, SAMLException, MetadataProviderException, MessageEncodingException
      {  
          var auth = SecurityContextHolder.getContext().getAuthentication();
          if (auth instanceof AnonymousAuthenticationToken) {
              logoutProfile.sendLogoutResponse(context, StatusCode.SUCCESS_URI, null);
          } else if (auth != null) {
              followNormalProcedure(request, response, auth, context);
          }
      }