title: Spring Security custom AuthenticationSuccessHandler is ignored
body: <p>I'm setting up a pure json rest service with Spring boot + data rest and now having trouble getting my custom authentication success handler (as well as authentication failure handler) to handle login responses. Login itself works as it should but the server responds to a successful login with a status 302 without redirect url (this triggers an error e.g. in javascript's XMLHttpRequest) and completely ignores my handlers set in config.</p>
  
  <p>WebSecurityConfig:</p>
  
  <pre><code>@Configuration
  @EnableWebSecurity
  @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
  public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  
  @Autowired
  private UserDetailsService userDetailsService;
  
  @Autowired
  private RESTAuthenticationEntryPoint authenticationEntryPoint;
  @Autowired
  private RESTAuthenticationFailureHandler authenticationFailureHandler;
  @Autowired
  private RESTAuthenticationSuccessHandler authenticationSuccessHandler;
  @Autowired
  private RESTLogoutSuccessHandler logoutSuccessHandler;
  
  @Bean
  public BCryptPasswordEncoder bCryptPasswordEncoder() {
      return new BCryptPasswordEncoder();
  }
  
  @Override
  protected void configure(HttpSecurity http) throws Exception {
  
      http
          .cors();
  
      http
          .exceptionHandling()
          .authenticationEntryPoint(authenticationEntryPoint);
  
      http
          .formLogin()
          .permitAll()
          .loginProcessingUrl("/login")
          .successHandler(authenticationSuccessHandler)
          .failureHandler(authenticationFailureHandler);
  
      http
          .logout()
          .permitAll()
          .logoutUrl("/logout")
          .logoutSuccessHandler(logoutSuccessHandler);
  
      http
          .sessionManagement()
          .maximumSessions(1);
  
      http.addFilterAt(getAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
      http.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class);
  
      http.authorizeRequests().anyRequest().authenticated();
  }
  
  @Bean
  public CorsConfigurationSource corsConfigurationSource() {
      CorsConfiguration configuration = new CorsConfiguration();
      configuration.addAllowedOrigin("*");
      configuration.setAllowCredentials(true);
      configuration.setExposedHeaders(Arrays.asList("X-CSRF-TOKEN"));
         configuration.setAllowedHeaders(Arrays.asList("X-CSRF-TOKEN", "content-type"));
      configuration.setAllowedMethods(Arrays.asList("GET","POST","OPTIONS"));
      configuration.setMaxAge(3600L);
      UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
      source.registerCorsConfiguration("/**", configuration);
      return source;
  }
  
  @Bean
  public PermissionEvaluator customPermissionEvaluator() {
      return new CustomPermissionEvaluator();
  }
  
  protected CustomUsernamePasswordAuthenticationFilter getAuthenticationFilter() {
      CustomUsernamePasswordAuthenticationFilter authFilter = new CustomUsernamePasswordAuthenticationFilter();
      try { 
          authFilter.setAuthenticationManager(this.authenticationManagerBean());
      } catch (Exception e) {
          e.printStackTrace();
      }
      return authFilter;
  }
  
  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
      auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
  }
  }
  </code></pre>
  
  <p>AuthenticationSuccessHandler:</p>
  
  <pre><code>@Component
  public class RESTAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
  
  @Override
  public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                      Authentication authentication) throws IOException, ServletException {
      response.setStatus(HttpServletResponse.SC_OK);
      PrintWriter writer = response.getWriter();
      writer.write("Login OK");
      writer.flush();        
      clearAuthenticationAttributes(request);
  }
  }
  </code></pre>
  
  <p>CustomUsernamePasswordAuthenticationFilter just reads username and password from json, it does not override the filter() method:</p>
  
  <pre><code>public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
  
  private final Logger log = LoggerFactory.getLogger(this.getClass());
  
  private boolean postOnly = true;
  
  @Override
  public Authentication attemptAuthentication(HttpServletRequest request,
          HttpServletResponse response) throws AuthenticationException {
  
      if (postOnly &amp;&amp; !request.getMethod().equals("POST")) {
          throw new AuthenticationServiceException(
                  "Authentication method not supported: " + request.getMethod());
      }
  
      LoginRequest loginRequest;
      try {
          BufferedReader reader = request.getReader();
          StringBuffer sb = new StringBuffer();
          String line = null;
          while ((line = reader.readLine()) != null){
              sb.append(line);
          }
          ObjectMapper mapper = new ObjectMapper();
          loginRequest = mapper.readValue(sb.toString(), LoginRequest.class);
      } catch (Exception ex) {
          throw new AuthenticationServiceException("Unable to read login credentials.");
      }
  
      UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
              loginRequest.getEmail(), loginRequest.getPassword());
  
      setDetails(request, authRequest);
      return this.getAuthenticationManager().authenticate(authRequest);
  }
  }
  </code></pre>
  
  <p>In debug log I can see that there is a strange RequestAwareAuthenticationSuccessHandler that gets the request after login handler and just passes a default redirect to '/':</p>
  
  <pre><code>2016-12-28 15:44:02.358 DEBUG 6194 --- [nio-8080-exec-7] o.s.s.authentication.ProviderManager     : Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
  2016-12-28 15:44:02.358 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [xxx.server.service.impl.UserDetailsServiceImpl.loadUserByUsername]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
  2016-12-28 15:44:02.358 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.JpaTransactionManager        : Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@908810e] for JPA transaction
  2016-12-28 15:44:02.358 DEBUG 6194 --- [nio-8080-exec-7] o.s.jdbc.datasource.DataSourceUtils      : Setting JDBC Connection [ProxyConnection[PooledConnection[org.postgresql.jdbc.PgConnection@4d362a0f]]] read-only
  2016-12-28 15:44:02.358 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@7cf6e5f]
  [...]
  2016-12-28 15:44:02.380 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.JpaTransactionManager        : Initiating transaction commit
  2016-12-28 15:44:02.380 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.JpaTransactionManager        : Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@908810e]
  2016-12-28 15:44:02.381 DEBUG 6194 --- [nio-8080-exec-7] o.s.jdbc.datasource.DataSourceUtils      : Resetting read-only flag of JDBC Connection [ProxyConnection[PooledConnection[org.postgresql.jdbc.PgConnection@4d362a0f]]]
  2016-12-28 15:44:02.381 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.JpaTransactionManager        : Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@908810e] after transaction
  2016-12-28 15:44:02.381 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.EntityManagerFactoryUtils    : Closing JPA EntityManager
  2016-12-28 15:44:02.488 DEBUG 6194 --- [nio-8080-exec-7] RequestAwareAuthenticationSuccessHandler : Using default Url: /
  2016-12-28 15:44:02.488 DEBUG 6194 --- [nio-8080-exec-7] o.s.s.web.DefaultRedirectStrategy        : Redirecting to '/'
  2016-12-28 15:44:02.488 DEBUG 6194 --- [nio-8080-exec-7] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@273d8edd
  2016-12-28 15:44:02.488 DEBUG 6194 --- [nio-8080-exec-7] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@faa222b9: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@faa222b9: Principal: org.springframework.security.core.userdetails.User@fa84ebb2: Username: hyriauser1@hyria-demo.tbd; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffed504: RemoteIpAddress: 127.0.0.1; SessionId: 1F3FF4A3203600AE56E3CB391BE96EFC; Granted Authorities: USER' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade@692480d1
  2016-12-28 15:44:02.488 DEBUG 6194 --- [nio-8080-exec-7] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
  </code></pre>