1

I've implemented some token based authentication in my spring-boot application. I have a filter and in that filter, I am doing the following:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    String authToken = httpRequest.getHeader("X-TOKEN-AUTH");
    String username = null;

    if (securityEnabled) {
       if (authToken != null) {

            try {
                username = userTokenService.validateToken(authToken);
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), null, userDetails.getAuthorities());
                auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
                SecurityContextHolder.getContext().setAuthentication(auth);

            } catch (AuthenticationException ae) {
                //TODO log something about signature exception
                log.warn(ae.getMessage());
            }
        }

    }

    chain.doFilter(request, response);
}

I also have a custom AuthFailureHandler:

@Component
public class AuthFailureHandler extends SimpleUrlAuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        PrintWriter writer = response.getWriter();
        writer.write(exception.getMessage());
        writer.flush();
    }
}

My code username = userTokenService.validateToken(authToken); throws an AuthenticationException for various reasons. AuthenticationException is a custom exception that extends Exception. When I catch this exception, I still want to return a 401, but I want my message to appear in what is currently being sent back as JSON by Spring Security as default:

{
    "timestamp": 1463408604943,
    "status": 401,
    "error": "Unauthorized",
    "message": "An Authentication object was not found in the SecurityContext",
    "path": "/api/brands/2"
}

I would want, for example...

{
    "timestamp": 1463408604943,
    "status": 401,
    "error": "Unauthorized",
    "message": "Invalid Token: Expired",
    "path": "/api/brands/2"
}

I'm unsure how to override this behavior.

2
  • This AuthenticationException is your custom exception or spring's AuthenticationException? Commented May 16, 2016 at 14:53
  • It is my own custom exception class Commented May 16, 2016 at 14:58

1 Answer 1

1

So...I finally figured this out. The problem was that Filters are higher up on the food chain so they really don't involve Spring all that much. Where I was throwing an exception in the Filter, Spring wasn't necessarily catching it. The filter would just throw a 500 and display the exception message. To fix it, I simply had to catch my exceptions in the filter and then call sendError with the appropriate http status.

try {
  username = userTokenService.validateToken(authToken);
  UserDetails userDetails = userDetailsService.loadUserByUsername(username);
  UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), null, userDetails.getAuthorities());
  auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
  SecurityContextHolder.getContext().setAuthentication(auth);
  chain.doFilter(request, response);
  return;
} catch (Exception ex) {
  httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, ex.getMessage());
  return;
}

The return statement in the catch is so that my chain.doFilter(request, response); at the end of the doFilter method isn't called.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.