5

I am having a project using Spring Boot and Spring Security. Spring Security validate the header with the session id for every request. If the session id is invalid or expired, an error code 401 will be returned. The session id is validated before it gets to the controller.

Now, I am facing an issue that if the user enters an invalid URL without a valid session id, still the response code is 401 because the session id is validated first. My expectation is that if the URL is invalid, an error code 404 (no mapping found for HTTP request) will be returned. In other words, I want to validate the URL before validating session id.

Is there any way to do so because the session id in the header is validated in the GenericFilterBean before it gets to the controller?

Any help is appreciated. Thank you.

Crist Lam
  • 51
  • 1
  • 2
  • 2
    No. Filters execute before servlets (which handle the mapping). – M. Deinum Dec 18 '19 at 08:09
  • 2
    I would also say that it makes sense not to tell people that have no session whether a page exists or not. – JoSSte Dec 18 '19 at 08:21
  • I know right. My friend suggests an option that is to have all of the valid mapping in a List and then for every request, iterate through the list in the Filter and throw a HTTP 404 if the request url is not in the list. But I don't think it's is okay to do that. – Crist Lam Dec 18 '19 at 08:45

2 Answers2

1

You can try to config access settings inside your WebSecurityConfigurerAdapter class.

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
        .antMatchers("/secure/**").authenticated()
        .and()
        .authorizeRequests().anyRequest().permitAll();
}

So the filter won't return HTTP 401 for any request which is not match "/secure/**" pattern.

  • 2
    Thanks but I think it doesn't solve my problem. Assume the correct URL is like /secure/abc and the request is like /secure/abcd, it would still return a HTTP 401 – Crist Lam Dec 18 '19 at 08:42
  • For more precise setting you can use `requestMatchers` method with something like this: https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.html#toAnyEndpoint-- This way you can include all your actual endpoints into some group. – PavelBahBah Dec 18 '19 at 08:53
  • Thanks for your link. It gives me an idea. I ll gather a list of valid endpoint, and then validate the request manually with that list. – Crist Lam Dec 18 '19 at 09:12
0

Put this filter as the first filter in the Spring Security:

public class NoHandlerFoundFilter extends OncePerRequestFilter {

  private final DispatcherServlet dispatcherServlet;

  public NoHandlerFoundFilter(DispatcherServlet dispatcherServlet) {
    this.dispatcherServlet = dispatcherServlet;
  }

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    if (null == getHandler(request)) {
      throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
          new ServletServerHttpRequest(request).getHeaders());
    }
    filterChain.doFilter(request, response);
  }

  private static String getRequestUri(HttpServletRequest request) {
    String uri = (String) request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE);
    if (uri == null) {
      uri = request.getRequestURI();
    }
    return uri;
  }

  protected HandlerExecutionChain getHandler(HttpServletRequest request) {
    if (dispatcherServlet.getHandlerMappings() != null) {
      for (HandlerMapping mapping : dispatcherServlet.getHandlerMappings()) {
        try {
          HandlerExecutionChain handler = mapping.getHandler(request);
          if (handler != null) {
            return handler;
          }
        } catch (Exception ex) {
          // Ignore
        }
      }
    }
    return null;
  }
}
scruel
  • 426
  • 6
  • 14