IDP 的 Spring SAML 预身份验证检查

Posted

技术标签:

【中文标题】IDP 的 Spring SAML 预身份验证检查【英文标题】:Spring SAML pre auth check at IDP 【发布时间】:2014-08-15 04:43:01 【问题描述】:

我正在编写几个基于 spring security 和 spring security saml extension (RC2) 的 Web 应用程序。

我在以基本方式与多个服务提供者和身份提供者合作时进行单点登录(基于 spring saml 文档中定义的示例)。

当用户访问 SP 上的受保护资源时,他会被转发到 IDP 上的受保护资源。所以因为用户还没有登录,他们被重定向到登录页面(标准的弹簧安全的东西)。登录后,播放原始请求并完成 authNRequest/Response,并将用户重定向到原始安全资源。

我现在有一个要求,确保所有服务提供者都必须在每次请求之前询问身份提供者用户是否已登录(而不是在 SP 本地进行)。

据我了解,在每次请求期间都会存储和查询本地 (SP) 和远程 (IDP) 安全上下文,如果没有有效的上下文,则用户会被转发给身份提供者以通过身份验证过程。

所以我的问题是,有没有一种方法可以在 SP 端配置 saml/spring 安全性以始终“ping”或要求 IDP 检查当前用户是否已登录,或者此类事情是否不必要/不受支持.

提前致谢

【问题讨论】:

这不是不必要的往返吗?我的意思是我有一个配置,我有很多战争,我有一个 SP 战争。所以我可以配置所有需要安全的 URL。并且我所有的战争都重定向到我的 SP,只有在没有可用身份验证的情况下才会前往 IDP。这是需要遵循的方法,不建议针对每个请求向 IDP 提出请求。 :) 【参考方案1】:

你是对的,Spring SAML 在每次请求期间都会查询本地安全上下文,一旦它变得无效,就会将用户转发给 IDP。

定义上下文何时失效的典型机制是使用 SAML 的属性SessionNotOnOrAfter。该属性包含在从 IDP 发回的断言的 AuthenticationStatement 中。一旦时间超过SessionNotOnOrAfter中提供的值,Spring SAML 将自动重新验证用户。

如果您想对每个请求重新进行身份验证,您可以添加一个新的自定义过滤器,例如:

package fi.test;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterInvocation;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

public class ReAuthenticateFilter extends GenericFilterBean 

    private static final String FILTER_APPLIED = "__spring_security_filterReAuthenticate_filterApplied";

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException 
        FilterInvocation fi = new FilterInvocation(request, response, chain);
        invoke(fi);
    

    protected void invoke(FilterInvocation fi) throws IOException, ServletException 

        if ((fi.getRequest() != null) && (fi.getRequest().getAttribute(FILTER_APPLIED) != null)) 
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
         else 
            if (fi.getRequest() != null) 
                fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
            
        

       Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        try 
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
         finally 
            if (authentication != null) 
                authentication.setAuthenticated(false);
            
        

    


然后您将在 Spring 配置中包含过滤器:

<security:http entry-point-ref="samlEntryPoint">
    <security:custom-filter after="SECURITY_CONTEXT_FILTER" ref="reAuthenticateFilter"/>
    ...
</security:http>

<bean id="reAuthenticateFilter" class="fi.test.ReAuthenticateFilter"/>

对每个请求重新进行身份验证是一项相当昂贵的操作(通过用户浏览器往返 IDP),并且可能导致应用程序响应速度不佳。

【讨论】:

以上是关于IDP 的 Spring SAML 预身份验证检查的主要内容,如果未能解决你的问题,请参考以下文章

即使在 IDP 使用 SAML 成功登录后,获取身份验证对象仍为空

spring saml - IDP 发起的 SSO

使用 Spring Security saml 的 IDP 会话超时

Spring Saml FilterChainProxy 清除上下文 - 空身份验证

我如何才能完全信任 SAML IDP?

ADFS spring-saml 依赖方没有配置 AssertionConsumerService