4

I am using Spring to expose and API in a larger application. When accessing endpoints that are behind an authenticated() configuration, my application throws an ugly Tomcat HTML error because of the following code:

@Component
public class EntryPointUnauthorizedHandler implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
            AuthenticationException e) throws IOException, ServletException {
        httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied");
    }
}

However, since this is an API I only want to return JSON, like in the rest of my API. For normal exception handling I set up the following @ControllerAdvice:

@ControllerAdvice
public class DefaultExceptionHandler extends ResponseEntityExceptionHandler {

    /**
     * Default internal BadCredentialsException handler. Respond with 401 Unauthorized
     */
    @ExceptionHandler(value = BadCredentialsException.class)
    public ResponseEntity<Object> handleBadCredentialsException(BadCredentialsException e, WebRequest request) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return handleExceptionInternal(e, null, headers, HttpStatus.UNAUTHORIZED, request);
    }

    /**
     * Fallback default exception handler. Respond with 500
     */
    @ExceptionHandler(value = Exception.class)
    public ResponseEntity<Object> handleFallbackException(Exception e, WebRequest request) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return handleExceptionInternal(e, null, headers, HttpStatus.INTERNAL_SERVER_ERROR, request);
    }

    @Override
    protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body,
            HttpHeaders headers, HttpStatus status, WebRequest request) {

        final ErrorResponse error = new ErrorResponse(status, ex.getMessage());

        if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {
            request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST);
        }

        return new ResponseEntity<Object>(error, headers, status);
    }
}

Where ErrorResponse is my own little response wrapper, holding the HttpStatus code and exception message. This gets formatted into JSON fine:

{
    "status": 401,
    "message": "Bad credentials"
}

How can I make sure my AuthenticationEntryPoint which only has a request and response object to return a similar formatted error, instead of the ugly Tomcat HTML page.

ChrisDekker
  • 1,584
  • 18
  • 39
  • 2
    Possible duplicate of [Handle spring security authentication exceptions with @ExceptionHandler](https://stackoverflow.com/questions/19767267/handle-spring-security-authentication-exceptions-with-exceptionhandler) – dur Sep 21 '17 at 21:06

1 Answers1

0

You can change the HttpServletResponse as you want. Take a look at: https://stackoverflow.com/a/19788700/1490806

Ignasi
  • 5,887
  • 7
  • 45
  • 81
  • 2
    Writing manual JSON strings or using an ObjectMapper feels very ugly and hacky. Is there really no proper way to do this? It feels like im using Spring incorrectly. What is the point of defining your exception handling in 1 place if you need to do it again in this AuthenticationEntryPoint ? – ChrisDekker Sep 21 '17 at 18:56
  • The spring security filter happens before of spring dispatcher servlet. So I guess spring has no control about exceptions occurred on security filter chain. https://visola.github.io/img/blog/spring-security-architecture.png I don't know any other way to do that. – Ignasi Sep 21 '17 at 20:00