Hi folks,

maybe I've missed something, but the current implementation of BasicErrorController (method errorHtml) do not prevent the user from calling /error directly in his browser. This allows the user to see the rendered error page in an unintended context.

Would it be better to add a pre-check and redirect the user to the application's main entry point (which needs to be defined somewhere) if

request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)

returns null?

Best regards, Sascha

Comment From: dsyer

I don't see much benefit in that, and it's actually pretty useful to be able to see the error page if you want to tweak it.

Comment From: saschaszott

Thanks! Is it possible to overwrite the /error request mapping and implement the requested behavior in a custom controller action?

Comment From: dsyer

Yes. See docs here: http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-error-handling. You can also disable the default error handling by excluding it in @EnableAutoConfiguration.

Comment From: saschaszott

Hi, thanks for the pointer to the current-SNAPSHOT version of the Spring Boot documentation (there was a crucial update in the section on Error Handling recently)!

My fix was to implement a CustomErrorController class that implements org.springframework.boot.actuate.web.ErrorController (extending BasicErrorController was not successful):

@Controller
public class CustomErrorController implements ErrorController {

    private BasicErrorController basicErrorController = new BasicErrorController();

    @Value("${error.path:/error}")
    private String errorPath;

    @Override
    public String getErrorPath() {
        return errorPath;
    }

    @Override
    public Map<String, Object> extract(RequestAttributes attributes, boolean trace, boolean log) {
        return basicErrorController.extract(attributes, trace, log);
    }

    @RequestMapping(value = "${error.path:/error}", produces = "text/html")
    public ModelAndView errorHtml(HttpServletRequest request) {
        if (request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE) == null) {
            // do not allow the user to call this action directly
            return new ModelAndView("redirect:");
        }
        return basicErrorController.errorHtml(request);
    }

    @RequestMapping(value = "${error.path:/error}")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        return basicErrorController.error(request);
    }

}

If there is a more elegant solution, so please let me know. I'm using Spring Boot 1.0.2.RELEASE.

Comment From: saschaszott

Please note, that this approach does not work with the latest release of Spring Boot (1.1.4).

Comment From: dsyer

Sorry, which approach? What doesn't work?

Comment From: saschaszott

The "fix" to define a custom ErrorController class that has an instance of type BasicErrorController. Since Spring Boot 1.1.x the BasicErrorController's constructor expects an object that implements the ErrorAttributes interface.

If there is a (elegant) way to disallow the user to call /error directly then please let me know.

Comment From: dsyer

You can still create a BasicErrorController subclass and inject the ErrorAttributes. Or you can create an ErrorAttributes subclass if you don't want the default one. I don't see the problem.

Comment From: saschaszott

Thank you, Dave! I wasn't aware of the fact that it's possible to extend a Spring Boot controller class and overwrite an existing request mapping.

With Spring Boot 1.1.4 the following is a valid approach to prevent the user from calling /error directly:

@Controller
public class CustomErrorController extends BasicErrorController {

    public CustomErrorController() {
        super(new DefaultErrorAttributes());
    }

    @RequestMapping(value = "${error.path:/error}", produces = "text/html")
    public ModelAndView errorHtml(HttpServletRequest request) {
        if (request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE) == null) {
            // do not allow the user to call this action directly
            return new ModelAndView("redirect:");
        }
        return super.errorHtml(request);
    }


}

Comment From: rafis

Does it the same in Spring Boot 2.x? When you extend BasicErrorController the main problem is with the two constructors. Spring requires no argument constructor and I don't know what to pass in. Seems like I can pass new DefaultErrorAttributes(), but what should I pass in for ErrorProperties?