4

I am writing several web applications based on both spring security and the spring security saml extension (RC2).

I have single sign on working with multiple service providers and an Identity provider in a basic fashion (based off the example defined in the spring saml docs).

When the user accesses a protected resource on the SP, he is forwarded to a protected resource on the IDP. So because the user isn't logged in yet, they are redirected to a login page (standard spring security stuff). After logging in, the original request is played back and the authNRequest/Response is done and the user is redirected to the original secured resource.

I now have a requirement that ensures that all services providers must ask the identity provider whether the user is logged in before each request (instead of doing it locally at the SP).

It is my understanding that a local (SP) and remote (IDP) security context is stored and queried during each request and if there isn't a valid context, the user is then forwarded to the identity provider to go through the auth process.

So my question is, is there a way I can configure saml/spring security on the SP side to always "ping" or ask the IDP to check if the current user is logged in or is this sort of thing unnecessary/unsupported.

thanks in advance

dharam
  • 7,882
  • 15
  • 65
  • 93
Paul H
  • 41
  • 2
  • isn't it an un-necessary round trip? I mean I have a configuration where I have many wars and I have one SP war. So I can configure all the URLs which needs to be secure. and all my wars redirect to my SP which will make a trip to IDP only if there is no authentication available. This is the approach one needs to follow, making a request to IDP on each request is not advisable. :) – dharam Jul 17 '14 at 18:45

1 Answers1

5

You are right, Spring SAML queries the local security context during each request and forwards user to IDP once it becomes invalid.

The typical mechanism which defines when the context becomes invalid is usage of SAML's attribute SessionNotOnOrAfter. The attribute is included inside the Assertion's AuthenticationStatement sent back from IDP. Spring SAML will automatically re-authenticate the user once the time goes beyond the value provided in the SessionNotOnOrAfter.

In case you would like to re-authenticate on every request, you could for example add a new custom filter similar to this:

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);
            }
        }

    }

}

You would then include the filter in your Spring configuration:

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

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

Re-authenticating on every request is rather expensive operation (a round-trip to the IDP through user's browser) and is likely to result in poor responsiveness of the application.

Vladimír Schäfer
  • 15,375
  • 2
  • 51
  • 71