title: Spring Security and nested FilterChainProxy writing SAML Service Provider
body: <p>I am trying to figure out a problem involving Spring Security and SAML. We are trying to use Spring Security (spring-security-core-3.1.1.RELEASE.jar) and SAML (spring-security-saml2-core-1.0.0-RC1-SNAPSHOT.jar) to modify our product to be a SAML SP. EDIT: Here is the (I think!) relevant section of my security-related context xml. As you can see, it's almost identical to <a href="http://git.springsource.org/spring-security/se-security/blobs/d2b6827fc2ad3e7044c1695dde2b003602c9cd00/spring-security-saml/saml2-sample/src/main/resources/security/securityContext.xml" rel="noreferrer">this sample XML</a>.</p>
  
  <pre><code>&lt;!-- Entry point to initialize authentication, default values taken from properties file --&gt;
  &lt;bean id="samlEntryPoint" class="com.myproduct.samlsp.impl.PSSAMLEntryPoint"&gt;
      &lt;property name="defaultProfileOptions"&gt;
          &lt;bean class="org.springframework.security.saml.websso.WebSSOProfileOptions"&gt;
              &lt;property name="includeScoping" value="false"/&gt;
          &lt;/bean&gt;
      &lt;/property&gt;
  &lt;/bean&gt;
  
  &lt;!-- Unsecured pages --&gt;
  &lt;security:http security="none" pattern="/saml/web/**"/&gt;
  &lt;security:http security="none" pattern="/logout.jsp"/&gt;
  &lt;security:http security="none" pattern="/favicon.ico"/&gt;
  &lt;security:http security="none" pattern="/images/**"/&gt;
  &lt;security:http security="none" pattern="/scripts/**"/&gt;
  &lt;security:http security="none" pattern="/flash/**"/&gt;
  &lt;security:http security="none" pattern="/loggedout.html"/&gt;
  
  &lt;!-- Secured pages --&gt;
  &lt;security:http entry-point-ref="samlEntryPoint"&gt;
      &lt;security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/&gt;
      &lt;security:custom-filter before="FIRST" ref="metadataGeneratorFilter"/&gt;
      &lt;security:custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/&gt;
  &lt;/security:http&gt;
  
  &lt;!-- IDP Discovery Service --&gt;
  &lt;bean id="samlIDPDiscovery" class="org.springframework.security.saml.SAMLDiscovery"&gt;
      &lt;property name="idpSelectionPath" value="/WEB-INF/security/idpSelection.jsp"/&gt;
  &lt;/bean&gt;
  
  &lt;bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy"&gt;
      &lt;security:filter-chain-map request-matcher="ant"&gt;
          &lt;security:filter-chain pattern="/saml/login/**" filters="samlEntryPoint"/&gt;
          &lt;security:filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter"/&gt;
          &lt;security:filter-chain pattern="/saml/metadata/**" filters="metadataDisplayFilter"/&gt;
          &lt;security:filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter"/&gt;
          &lt;security:filter-chain pattern="/saml/SSOHoK/**" filters="samlWebSSOHoKProcessingFilter"/&gt;
          &lt;security:filter-chain pattern="/saml/SingleLogout/**" filters="samlLogoutProcessingFilter"/&gt;
          &lt;security:filter-chain pattern="/saml/discovery/**" filters="samlIDPDiscovery"/&gt;
      &lt;/security:filter-chain-map&gt;
  &lt;/bean&gt;
  </code></pre>
  
  <p>The symptom is that, immediately after authentication with the IDP, my SP's page shows up correctly; however, changing the URL (e.g. clicking any link) sends me immediately back to the IDP. I think I've figured out why, but I don't know why this is not always the case.</p>
  
  <p>My understanding of Spring Security is that authorization checking is all based around the SecurityContextHolder. Namely, put an Authentication object on the holder, and everything does auth checks around it. Then SecurityContextPersistenceFilter is responsible for maintaining the session repository to match.</p>
  
  <p>So, as I trace through the Spring Security code, I see SecurityContextPersistenceFilter with the following code:</p>
  
  <pre><code>SecurityContext contextBeforeChainExecution = repo.loadContext(holder);
  try {
    SecurityContextHolder.setContext(contextBeforeChainExecution);
    chain.doFilter(holder.getRequest(), holder.getResponse());
  } finally {
    SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
    // Crucial removal of SecurityContextHolder contents - do this before anything else.
    SecurityContextHolder.clearContext();
    repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
    ....
  }
  </code></pre>
  
  <p>So far, so good. Then, I look at FilterChainProxy and find:</p>
  
  <pre><code>public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
          throws IOException, ServletException {
      try {
          doFilterInternal(request, response, chain);
      } finally {
          // SEC-1950
          SecurityContextHolder.clearContext();  &lt;------- Key line here
      }
  }
  </code></pre>
  
  <p>This still seems ok. Since FilterChainProxy should only be invoked once, at the base of all the Spring Security filters, it's not a problem to clear the SecurityContextHolder at that point.</p>
  
  <p>HOWEVER, this is not what's happening. What's actually happening is the clearContext in FilterChainProxy is called BEFORE SecurityContextPersistenceFilter gets a chance to read it out of the context into contextAfterChainExecution. The reason this is happening is because FilterChainProxy actually occurs twice in the call chain. I know this because I set a breakpoint in FilterChainProxy.doFilter, and it IS called twice. The first time it's called, it has another instance of FilterChainProxy in its FilterChain. Here is the stack of Filters returned by FilterChainProxy's getFilters method:</p>
  
  <pre><code>org.springframework.security.saml.metadata.MetadataGeneratorFilter@78104d3c
  org.springframework.security.web.context.SecurityContextPersistenceFilter@168c795e
  FilterChainProxy[ Filter Chains: [ .... my patterns ] ],
  org.springframework.security.web.savedrequest.RequestCacheAwareFilter@7fffde92
  org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@e2d09d7
  org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1c2b968f
  org.springframework.security.web.session.SessionManagementFilter@395f222a
  org.springframework.security.web.access.ExceptionTranslationFilter@372e6f09
  org.springframework.security.web.access.intercept.FilterSecurityInterceptor@7dab91aa
  </code></pre>
  
  <p>With this chain of filters, I don't understand how SecurityContextPersistenceFilter can ever work: it seems like the SecurityContextHolder will always be cleared before it gets a chance to persist it.</p>
  
  <p>Is there something obvious wrong here? Am I misunderstanding something in Spring Security (very possible!)</p>