1

I'm using a filter to check if the user is connected (token is valid) , if the token is not a valid I set an attribute called "error" with the details of the error, here is my controller

@RestController
public class HomeController {


@RequestMapping(value = "secure/info", method = RequestMethod.POST)

public Object login(@RequestBody User user,@RequestAttribute(name="error") AppError error)  {

    if(error!=null) return error ;
    return "information";

}

And here is my filter :

        @Override
        public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain)
                throws IOException, ServletException {

            final HttpServletRequest request = (HttpServletRequest) req;
            final HttpServletResponse response = (HttpServletResponse) res;
            final String authHeader = request.getHeader("authorization");

            if ("OPTIONS".equals(request.getMethod())) {
                response.setStatus(HttpServletResponse.SC_OK);

                chain.doFilter(request, response);
            } else {

                if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                    AppError error = new AppError("0001","Invalid bearer token.");
                    request.setAttribute("error", error);
                    chain.doFilter(request, response);
                }

                final String token = authHeader.substring(7);

                try {
                    final Claims claims = Jwts.parser().setSigningKey("secretkey").parseClaimsJws(token).getBody();
                    request.setAttribute("claims", claims);
                } catch (final SignatureException e) {
                    AppError error = new AppError("0002","Invalid token signature.");
                    request.setAttribute("error", error);
                    chain.doFilter(request, response);
                }
                 catch (final ExpiredJwtException e) {
                     AppError error = new AppError("0003","Expired token.");
                     request.setAttribute("error", error);
                     chain.doFilter(request, response);

                 }

                 catch (final MalformedJwtException e) {
                     AppError error = new AppError("0004","Malformed token.");
                     request.setAttribute("error", error);
                     chain.doFilter(request, response);
                     //return ;
                 }



                chain.doFilter(req, res);
            }
        }

and here is the exception I get :

java.lang.IllegalStateException: Cannot call sendError() after the response has been committed at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:472) ~[tomcat-embed-core-8.5.16.jar:8.5.16] at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.handleHttpMessageNotReadable(DefaultHandlerExceptionResolver.java:386) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE] at ... .... at com.inconso.LoginFilter.doFilter(LoginFilter.java:67) [classes/:na]

glytching
  • 44,936
  • 9
  • 114
  • 120
BadrEddineBen
  • 235
  • 1
  • 4
  • 24

2 Answers2

2

Either add a return statement right after first chain.doFilter(request, response); -- Early return approach

                if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                    AppError error = new AppError("0001","Invalid bearer token.");
                    request.setAttribute("error", error);
                    chain.doFilter(request, response);

                    // ADD a RETURN STATEMENT HERE
                }

OR (IF-ELSE Ladder Approach)

// START: MOVE THIS inside AN ELSE Block

                final String token = authHeader.substring(7);

                try {
                    final Claims claims = Jwts.parser().setSigningKey("secretkey").parseClaimsJws(token).getBody();
                    request.setAttribute("claims", claims);
                } catch (final SignatureException e) {
                    AppError error = new AppError("0002","Invalid token signature.");
                    request.setAttribute("error", error);
                    chain.doFilter(request, response);
                }
                 catch (final ExpiredJwtException e) {
                     AppError error = new AppError("0003","Expired token.");
                     request.setAttribute("error", error);
                     chain.doFilter(request, response);

                 }

                 catch (final MalformedJwtException e) {
                     AppError error = new AppError("0004","Malformed token.");
                     request.setAttribute("error", error);
                     chain.doFilter(request, response);
                     //return ;
                 }
// END: MOVE THIS inside AN ELSE Block
so-random-dude
  • 15,277
  • 10
  • 68
  • 113
1

In the else block where this condition is true: authHeader == null || !authHeader.startsWith("Bearer ") you are invoking chain.doFilter() twice.

Once in this block:

if (authHeader == null || !authHeader.startsWith("Bearer ")) {
    AppError error = new AppError("0001","Invalid bearer token.");
    request.setAttribute("error", error);
    chain.doFilter(request, response);
}

And the a second time at the end of the else block:

else {

    ...

    chain.doFilter(req, res);
}

Once is enough so either remove the last chain.doFilter(request, response) from the bottom of the else block or remove the chain.doFilter(request, response) from the if and catch clauses elsewhere in that block.

glytching
  • 44,936
  • 9
  • 114
  • 120