1

I am running out of ideas how to solve this strange filter issue. Here is what I am running right now:

Development machine:

  • Windows 10
  • Java JDK 13.0.2
  • Eclipse 2020-03 (4.15.0)

VPS Server:

  • Centos 7 (Linux version 2.6.32-042stab120.19 (root@kbuild-rh6-x64.eng.sw.ru) (gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC) ) #1 SMP Mon Feb 20 20:05:53 MSK 2017)
  • Java 13.0.1
  • NGinx x.x.x as a proxy

Here is my issue:

I am developing a web based application using Spring Boot 2.2.6.RELEASE as the backend and AngularJS 1.7.9 on the frontend meaning that the server provides REST(ish) API using MariaDB as the persistence storage. Everything works fine until I add a filter. The application works fine on my development machine, but when I run it on the server things get weird. On the server everything works fine until I add that filter. The purpose of the filter is to check XSRF token.

I have narrowed the problem down to the filter. Everything actually works fine on the server. Login is successful and cookies are written etc. the log shows that user is logged in. The login controller responds a redirect in success and failure. What happens is that the response takes a long a time I mean minutes to arrive. I tried to set the response timeout to 240 seconds in nginx to be able to login. Everything after the login works as expected. Looking at the server logs it seems that the login controller is not the problem here it does its job quickly. This response stalling happens only when I have the filter present.

I have tried several combinations and nothing seems to affect the result. The code I will present here is in the middle of tracking the problem so try not to let it bother (for example the login actually uses POST, but to rule out that the issue might be POST related I tried GET). I tried implementing Filter and extending OncePerRequest with no changes in the result. To sum it up I have tracked the issue to happen in login (subsequent call work fine) and that the issue is that the response from the server takes time. When it actually sends out the response to the proxy everything works smoothly. The time spent on DB isn’t the issue and the filter basically does nothing, but tries to write log.

Filter:

//@Component
@Order(0)
public class XSRFFilter extends OncePerRequestFilter
{
    private static final Logger LOG = LogManager.getLogger(XSRFFilter.class);

    @Autowired
    private SessionService sessionService;

//  @Bean
//  public FilterRegistrationBean<? extends Filter> registerFilter()
//  {
//      LOG.trace("Registering XSRF filter");
//      FilterRegistrationBean<XSRFFilter> registrationBean = new FilterRegistrationBean<>();
//      registrationBean.setFilter(this);
//      registrationBean.addUrlPatterns("/fnet/*");
//      return registrationBean;
//  }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
    {
        LOG.trace("Filtering path {}", request.getRequestURI());
        filterChain.doFilter(request, response);
        // Verify XSRF token
//      HttpServletRequest httpRequest = getHttpServletRequest(request);
//      if (httpRequest != null)
//      {
//          if (httpRequest.isRequestedSessionIdValid() && sessionService.isUserLoggedIn())
//          {
//              String xsrfToken = getCookie(ProtectionKey.XSRF_TOKEN.getKeyName(), httpRequest.getCookies());
//              if (sessionService.getXSRFToken().equals(xsrfToken))
//              {
//                  chain.doFilter(request, response);
//                  return;
//              }
//          }
//      }
//      ((HttpServletResponse) response).setStatus(HttpStatus.UNAUTHORIZED.value());
    }

}

Login:

    @GetMapping(value = "/login")
    @ResponseStatus(value = HttpStatus.FOUND)
    public String login(@RequestParam(name = "userName") String userName, @RequestParam(name = "password") String password, HttpServletRequest httpServletRequest,
            HttpServletResponse response) throws NoSuchAlgorithmException
    {
        User user = userService.findUserByName(userName);
        if (user != null)
        {
            try
            {
                UserData userData = userDataService.getForUser(user);
                userService.verifyPassword(user, password.getBytes());
//              userDataService.updateLogin(userData, resolveIP((String) httpServletRequest.getAttribute("X-Real-IP")));
                sessionService.setCurrentUser(user);
                sessionService.setActiveGroup(groupService.getById(userData.getLastActiveGroup()));
                sessionService.setUserData(userData);
                String xsrfToken = Base64.getEncoder().encodeToString(passwordService.generateSalt());
                sessionService.setXSRFToken(xsrfToken);
                Cookie xsrfCookie = new Cookie(ProtectionKey.XSRF_TOKEN.getKeyName(), xsrfToken);
                // One day
                xsrfCookie.setMaxAge(24 * 60 * 60);
                xsrfCookie.setHttpOnly(true);
                xsrfCookie.setPath("/fnet/");
//              response.addCookie(xsrfCookie);
                LOG.info("User {} logged in", user.getUserName());
//              return new RedirectView("/fnet/main.html");
                return "redirect:/fnet/main.html";
            }
            catch (AuthenticationException e)
            {
                LOG.warn("Invalid login", e);
            }
        }
//      return new RedirectView("/login.html?faile");
        return "redirect:/login.html?failed";
    }

This is just a copy paste from my current situation it makes no difference when I return RedirectView from login what I eventually do.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62

1 Answers1

1

Issue solved! Further study and logging revealed that generating the XSRF token was actually the issue. Internally PasswordService.generateSalt invoked SecureRandom.getInstanceStrong which was not an issue when running the app on Windows machine. How to deal with a slow SecureRandom generator? here you can see that there is an issue with Linux. I changed it to SecureRandom.getInstance("SHA1PRNG").nextBytes(salt); which resolved the issue. Why it seemed to cause an issue only when I had the filter present I do not know, we can blame it on my PPMS diagnose (everybody else blames everything on that so why don't you join the club). Also the fact that I have tried to solve the issue for several days without taking any distance from it which had eventually made me blind t things.

Here is a tip for those that suffer from same kind of blindness. Work on other not so serious projects which you can continue when you get stuck. Or get some hobby that gets your mind of the things you are working on. Personally I would skateboard if my body would allow it failing to land some ollie because I would have come up with the solution in mid air.