Petar Tahchiev
Petar Tahchiev

Reputation: 4386

Spring security csrf not working with spring-session

I'm using spring-session version 1.0.0.M1 and I have configured it to use the MapSessionRepository: sessionFilterChainReg.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), false, dispatcherServletReg.getName());

@Bean(name = {"defaultSessionFilter", "sessionFilter"})
public SessionRepositoryFilter sessionFilter() {
    return new SessionRepositoryFilter((SessionRepository) applicationContext.getBean("sessionRepository"));
}


@Bean(name = { "defaultSessionRepository", "sessionRepository" })
public SessionRepository defaultSessionRepository() {
    return new MapSessionRepository();
}

and then in the web-config:

    final FilterRegistration sessionFilterChainReg = servletContext.addFilter("sessionFilter", DelegatingFilterProxy.class);

So I have in my register.jsp the following input hidden element:

<input type="hidden" id="${_csrf.parameterName}" name="${_csrf.parameterName}" value="${_csrf.token}"/>

And I can see the page gets rendered with a correct CSRF token. When I submit the POST request the CSRF filter is triggered and the token is passed correctly to the filter, which calls the HttpSessionCsrfTokenRepository:loadToken and in there on line 66 we see:

HttpSession session = request.getSession(false);

and now the session is null, so the repository returns a null CSRF token and then a MissingCsrfTokenException is thrown. Is there something else I need to configure?

Here's the stacktrace when hitting line 66 (there's a lot more, but i guess this is the relevant part of it):

at org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.loadToken(HttpSessionCsrfTokenRepository.java:66)
  at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:75)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
  at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
  at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
  at org.springframework.security.web.access.channel.ChannelProcessingFilter.doFilter(ChannelProcessingFilter.java:144)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
  at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
  at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1632)
  at org.springframework.session.web.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:83)
  at org.springframework.session.web.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:66)
  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1632)

Upvotes: 1

Views: 2704

Answers (1)

Petar Tahchiev
Petar Tahchiev

Reputation: 4386

Found the problem - I myself was having a Filter which Wrapped the HttpServletRequest object and the filter was firing before the SessionRepositoryFilter. I'm not sure this is correct but to force it to fire after the SessionRepositoryFilter I did this:

@Bean(name = {"defaultSessionFilter", "sessionFilter"})
public Filter sessionFilter() {
    CompositeFilter compositeFilter = new CompositeFilter();
    compositeFilter.setFilters(Arrays.asList(new SessionRepositoryFilter((SessionRepository) applicationContext.getBean("sessionRepository")), applicationContext.getBean("myFilter")));

    return compositeFilter;
}

which solves the problem.

Upvotes: 1

Related Questions