title: Chained authentication in Spring Security
body: <p>Can I chain multiple instances of <code>AuthenticationEntryPoint</code> in Spring Security 3.2.4?</p>
  
  <p>I attempting to create the following scenario:</p>
  
  <ul>
  <li>A certain URL is secured with Spring Security</li>
  <li>The <code>AuthenticationEntryPoint</code> used is <code>LoginUrlAuthenticationEntryPoint</code></li>
  <li>An admin interface can spawn services under this URL</li>
  <li>The admin can choose to secure these services with <code>CLIENT-CERT</code></li>
  </ul>
  
  <p>When a user attempts to access the secure URL:</p>
  
  <ol>
  <li>If the path has been secured with <code>CLIENT-CERT</code> then authentication fails unless they have provided a valid certificate the corresponds to a user in the <code>UserService</code>. Standard Spring Security <code>x509</code> authentication.</li>
  <li>Once the user has been authentication as per the first point, or if the URL is not secured with <code>CLIENT-CERT</code>, they are directed to a <code>FORM</code> based authentication page.</li>
  <li>Once they successfully authenticate with a username and password, they are directed to a landing page.</li>
  </ol>
  
  <p>I am running on Tomcat 7.0.54 with <code>clientAuth="want"</code>. This works perfectly in a "simple" Spring Security set up - i.e. with one <code>WebSecurityConfigurerAdapter</code> set to <code>x509()</code> and another set to <code>formLogin()</code> as per <a href="http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#multiple-httpsecurity" rel="nofollow noreferrer">this example</a></p>
  
  <p>So, I want a process flow something like the following:</p>
  
  <p><img src="https://i.stack.imgur.com/CQjB8.png" alt="Authentication flow"></p>
  
  <p>I have had some success with dynamically changing the used authentication method by using a <code>DelegatingAuthenticationEntryPoint</code> but:</p>
  
  <ul>
  <li>When using an <code>AntPathRequestMatcher</code> to map, say, <code>/form/**</code> to a <code>LoginUrlAuthenticationEntryPoint</code> the authentication servlet (<code>/j_spring_security_check</code>) gives a <code>HTTP404</code> error.</li>
  <li>When using an <code>AntPathRequestMatcher</code> to map, say, <code>/cert/**</code> to a <code>Http403ForbiddenEntryPoint</code> the user's details are not extracted from the presented client certificate so this gives a <code>HTTP403</code> error.</li>
  </ul>
  
  <p>I also cannot see how to force a user to authenticate <em>twice</em>.</p>
  
  <p>I am using the java-config and not XML.</p>
  
  <p>My code:</p>
  
  <p>I have a <code>DelegatingAuthenticationEntryPoint</code>:</p>
  
  <pre><code>@Bean
  public AuthenticationEntryPoint delegatingEntryPoint() {
      final LinkedHashMap&lt;RequestMatcher, AuthenticationEntryPoint&gt; map = Maps.newLinkedHashMap();
      map.put(new AntPathRequestMatcher("/basic/**"), new BasicAuthenticationEntryPoint());
      map.put(new AntPathRequestMatcher("/cert/**"), new Http403ForbiddenEntryPoint());
  
      final DelegatingAuthenticationEntryPoint entryPoint = new DelegatingAuthenticationEntryPoint(map);
      entryPoint.setDefaultEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"));
  
      return entryPoint;
  }
  </code></pre>
  
  <p>And my <code>configure</code></p>
  
  <pre><code>@Override
  protected void configure(final HttpSecurity http) throws Exception {
      defaultConfig(http)
              .headers()
              .contentTypeOptions()
              .xssProtection()
              .cacheControl()
              .httpStrictTransportSecurity()
              .addHeaderWriter(new XFrameOptionsHeaderWriter(SAMEORIGIN))
              .and()
              .authorizeRequests()
              .accessDecisionManager(decisionManager())
              .anyRequest()
              .authenticated()
              .and()
              .httpBasic()
              .authenticationEntryPoint(delegatingEntryPoint())
              .and()
              .sessionManagement()
              .maximumSessions(1)
              .sessionRegistry(sessionRegistry())
              .maxSessionsPreventsLogin(true);
  }
  </code></pre>
  
  <p>Where <code>decisionManager()</code> returns a <code>UnanimousBased</code> instance. <code>sessionRegistry()</code> returns a <code>SessionRegistryImpl</code> instance. Both methods are <code>@Bean</code>.</p>
  
  <p>I add a custom <code>UserDetailsService</code> using:</p>
  
  <pre><code>@Autowired
  public void configureAuthManager(
          final AuthenticationManagerBuilder authBuilder,
          final InMemoryUserDetailsService authService) throws Exception {
      authBuilder.userDetailsService(authService);
  }
  </code></pre>
  
  <p>And I have a custom <code>FilterInvocationSecurityMetadataSource</code> mapped using a <code>BeanPostProcessor</code> as in <a href="https://stackoverflow.com/a/8387395/2071828">this example</a>.</p>