0

We have extended AbstractPreAuthenticatedProcessingFilter to authenticate shibboleth users, it does nothing special but obtain the user name from a specific request attribute and return a PreAuthenticatedAuthenticationToken.

If we access the root context of our application it works ok, but if we request a specific URL within our application we get "java.lang.IllegalStateException: Response already commited".

In SecurityConfig we have:

@Override
    protected void configure(final HttpSecurity http) throws SecurityException {
        try {

        http.authorizeRequests().antMatchers("/favicon.ico", "/resources/**", "/signin**").permitAll()
            .anyRequest().authenticated().and().formLogin().loginPage("/signin").permitAll()
            .failureUrl("/signin?error=1").successHandler(new CustomAuthenticationSuccessHandler())
            .loginProcessingUrl("/authenticate").and().sessionManagement().invalidSessionUrl("/signin")
            .and().exceptionHandling().accessDeniedHandler(new AccessDeniedHandler()).and().headers()
            .frameOptions().disable();

        
            http.addFilterBefore(
                new ShibbolethPreAuthenticatedProcessingFilter(new ShibbolethAuthenticationManager(),
                    new CustomAuthenticationSuccessHandler()),
                AbstractPreAuthenticatedProcessingFilter.class);
            http.logout().logoutUrl("/logout")
                .logoutSuccessUrl(environment.getProperty(Constantes.CT_SHIBBOLETH_LOGOUT_URL))
                .clearAuthentication(true).invalidateHttpSession(true);
        

        } catch (final Exception e) {
        throw new SecurityException(e);
        }
    }

ShibbolethAuthenticationManager implements AuthenticationManager and just loads UserDetails and GrantedAuthorities into a PreAuthenticatedAuthenticationToken

CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler and loads the user language into the LocaleProvider and loads the current license details into the session.

If we request for "/" in our application it takes us to:

 @ResponseStatus(HttpStatus.MOVED_PERMANENTLY)
        @RequestMapping("/")
        public String index(HttpServletRequest httpRequest, HttpSession session, Authentication auth) {
        if (auth.getAuthorities().contains(new SimpleGrantedAuthority(Constants.CONTROL_PANEL_PERMISSION))) {
           return "redirect:/controlpanel/dashboard";
        }  else if (auth.getAuthorities().contains(new SimpleGrantedAuthority(Constants.CONFIG_PERMISSION))) 
        {
           return "redirect:/config";
        } else {
           return "redirect:/userpage";
        }
    }

I don't know why those redirects work, but not when we request another URL, for example if we request to go directly to /controlpanel/dashboard we get the error.

@RequestMapping("/controlpanel/dashboard")    
public String dashboard(Model model, HttpServletRequest httpRequest, HttpSession session,
            @RequestParam(name = "comite", defaultValue = "-1") Long comite,
            @RequestParam(required = false) final Boolean tasksToDo) {
    
        // This method does nothing but add things to the  model object, such as:
        model.addAttribute("tasks", tasksToDo);
        // and then it takes the user to the view page
    
        return "cuadromando/dashboard";
        }

EDIT: stack trace:

2020-12-02 14:14:07|ERROR|NA|01.10.00|http-nio-8080-exec-2|java.lang.IllegalStateException: No puedo reenviar después de que la respuesta se haya llevado a cabo.
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:323)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312)
    at org.sitemesh.webapp.WebAppContext.dispatch(WebAppContext.java:182)
    at org.sitemesh.webapp.WebAppContext.decorate(WebAppContext.java:157)
    at org.sitemesh.BaseSiteMeshContext.decorate(BaseSiteMeshContext.java:39)
    at org.sitemesh.webapp.SiteMeshFilter.postProcess(SiteMeshFilter.java:83)
    at org.sitemesh.webapp.contentfilter.ContentBufferingFilter.bufferAndPostProcess(ContentBufferingFilter.java:175)
    at org.sitemesh.webapp.contentfilter.ContentBufferingFilter.doFilter(ContentBufferingFilter.java:126)
    at org.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:120)
    at org.sitemesh.config.ConfigurableSiteMeshFilter.doFilter(ConfigurableSiteMeshFilter.java:163)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doFilter(AbstractPreAuthenticatedProcessingFilter.java:121)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at es.bahiasoftware.meet.web.filter.RefererManagerFilter.doFilter(RefererManagerFilter.java:49)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:122)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:178)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:770)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
diminuta
  • 1,545
  • 8
  • 32
  • 55
  • Please add a stacktrace for the `IllegalStateException`. If you find where the exception is raised, you should find why component is trying to modify the (already commited) response. Secondly, you'd need to find where the response is already commited (maybe a redirect to login from an authentication filter?). – Simon Dec 02 '20 at 13:43
  • Hi @Simon I added the stack trace. But the only authentication filter we use is the one I already mentioned. – diminuta Dec 02 '20 at 14:07
  • The stacktrace shows that the application is trying to forward and committed response. Most likely, the ShibbolethPreAuthenticatedProcessingFilter has already commited the response. Does removing ShibbolethPreAuthenticatedProcessingFilter resolve the issue? Does a permitAll() on the pages under test resolve the issue? – Simon Dec 02 '20 at 14:14
  • So I have seen that SavedRequestAwareAuthenticationSuccessHandler (which is extended by my CustomAuthenticationSuccessHandler) does getRedirectStrategy().sendRedirect(request, response, targetUrl); Which is what we expect, as we expect the application to redirect the user to the url he requested after he has been successfully authenticated... – diminuta Dec 02 '20 at 14:44
  • Even if CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler instead, I get the same exception. The handle method calls getRedirectStrategy().sendRedirect(request, response, targetUrl); Which is, in fact, the expected behavior... – diminuta Dec 02 '20 at 14:54

1 Answers1

0

In the end I solved it by implementing AuthenticationSuccessHandler instead of extending SavedRequestAwareAuthenticationSuccessHandler:

CustomSuccessHandler implements AuthenticationSuccessHandler

So I get rid of the commited response, because both SavedRequestAwareAuthenticationSuccessHandler and SimpleUrlAuthenticationSuccessHandler called getRedirectStrategy().sendRedirect(request, response, targetUrl); so they commited the response before we could do the actual redirect we needed.

diminuta
  • 1,545
  • 8
  • 32
  • 55