spring-boot: Spring Security Principal missing from 4xx responses

Hi folks,

today I came across a strange behavior when using Spring Boot in conjunction with Spring Security and a custom error page setting.

My WebApplicationConfiguration class (which extends WebMvcConfigurerAdapter) defines a EmbeddedServletContainerCustomizer bean:

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
   return (container -> container.addErrorPages(
                new ErrorPage(HttpStatus.BAD_REQUEST, "/4x"),
                new ErrorPage(HttpStatus.UNAUTHORIZED, "/4xx"),
                new ErrorPage(HttpStatus.FORBIDDEN, "/4xx"),
                new ErrorPage(HttpStatus.NOT_FOUND, "/4xx"),
                new ErrorPage(HttpStatus.METHOD_NOT_ALLOWED, "/4xx"),
                new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/5xx")));
}

The path /4xx (and /5xx as well) is handled by the following controller:

@Controller
public class ErrorPageController {

   private static final Logger LOG = Logger.getLogger(ErrorPageController.class.getName());

   @RequestMapping(value = { "/4xx", "/5xx" })
   public String handleError(HttpServletRequest request, ModelMap map) {
      String name = request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : "NULL";
      LOG.warn("user name is " + name);

     …
   }
}

Within the controller method handleError I’m trying to get the name of the successfully authenticated user.

If I’m running the application (as a JAR file) with an embedded application server (Tomcat 7.0.52) the following output can be found in the log file

WARN [de.szott.mybootapp.web.controller.ErrorPageController.handleError:65] - user name is NULL

If I’m running the application (as a WAR file) in a standalone Tomcat (same version) the log file states

WARN [de.szott.mybootapp.web.controller.ErrorPageController.handleError:65] - user name is johndoe

Does anybody have a clue on how to fix this? Please note, that it’s crucial for me to get the user name in the controller method since I want to output the name in the view (which is a Thymeleaf template in my case). Thanks!

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Reactions: 2
  • Comments: 16 (7 by maintainers)

Most upvoted comments

There were some discussion on this topic in #4505 and #4739. I believe that the default configuration should be changed.

Current Configuration:

static final EnumSet<DispatcherType> ASYNC_DISPATCHER_TYPES = EnumSet.of(
            DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.REQUEST,
            DispatcherType.ASYNC);

    static final EnumSet<DispatcherType> NON_ASYNC_DISPATCHER_TYPES = EnumSet
            .of(DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.REQUEST)

What I am proposing is that replacing INCLUDE with ERROR. This seems more sensible to me. Issues like this are suffering from default configurations.

ping @philwebb

Are there any workarounds? Or does anyone have any ideas for a code change that I could work quick?

I’m not sure is this a bug or not, because it described in documentation (but there is no words about Spring Security):

N.B. if you register an ErrorPage with a path that will end up being handled by a Filter (e.g. as is common with some non-Spring web frameworks, like Jersey and Wicket), then the Filter has to be explicitly registered as an ERROR dispatcher (the default FilterRegistrationBean does not include the ERROR dispatcher type).

This is how I’ve fixed it for myself:

@Bean
public FilterRegistrationBean getSpringSecurityFilterChainBindedToError(
                @Qualifier("springSecurityFilterChain") Filter springSecurityFilterChain) {

        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(springSecurityFilterChain);
        registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
        return registration;
}