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.