在IDP进行Spring SAML预授权检查

时间:2014-06-24 19:31:28

标签: java spring spring-security saml spring-saml

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

我以单一方式单独使用多个服务提供商和身份提供商以基本方式(基于spring saml docs中定义的示例)。

当用户访问SP上的受保护资源时,他将被转发到IDP上的受保护资源。因此,由于用户尚未登录,因此会将其重定向到登录页面(标准弹簧安全性内容)。登录后,将播放原始请求并完成authNRequest / Response,并将用户重定向到原始安全资源。

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

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

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

提前致谢

1 个答案:

答案 0 :(得分:3)

您是对的,Spring SAML在每次请求期间查询本地安全上下文,并在用户无效后将其转发给IDP。

定义上下文何时变为无效的典型机制是使用SAML的属性SessionNotOnOrAfter。该属性包含在从IDP发回的Assertion的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)并且可能导致应用程序的响应性差。