mugua
mugua

Reputation: 224

spring boot csrf and jade

I’ve got a Spring Boot application with java configuration. I’m only referencing spring-boot-starter-jade4j and spring-boot-starter-security in my build.gradle file. I’m trying to figure out why I can’t get a csrf token to appear. Here’s my SecurityConfig

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Autowired
  DataSource ds;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/", "/signup", "/js/**", "/css/**", "/terms", "/privacy", "/favicon.ico").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
        .logout()
            .logoutUrl("/logout")
            .permitAll()
            .and()
        .csrf();
  }
…
}

Here’s my login form. The CSRF hidden field shows in the source code, but the csrf token doesn’t seem to evaluate and the value is empty.

extends _base
block head

block body
  #bodContent.container-fluid
  .row
    .col-md-4
    .col-md-4
      br
      .panel.panel-default
        .panel-body
          h1 Please log in
          form(method="POST", action="/login")
            input(type="hidden", name='_csrf', value='#{_csrf}')
            .form-group
              label(for="email")
                | Email address
              input#username.form-control(name="username", type="email", value="")
            .form-group
              label(for="password")
                | Password
              input#password.form-control(name="password", type="password", value="")
            .checkbox
              label
                input(type="checkbox")
                | Remember me
            input.btn.btn-default(type="submit")
              | Submit
    .col-md-4

Upvotes: 4

Views: 1065

Answers (1)

manish
manish

Reputation: 20135

My suspicion is that Spring Boot does not expose the CSRF token as a model attribute, which could be expected because the token is generally exposed as a request attribute (not a model attribute). In a typical Spring MVC application, the request attributes can be exposed as model attributes by setting exposeRequestAttributes to true on the ViewResolver. However, I am not sure how this can be done with the Jade4j view resolver.

There is however a workaround, which is to expose the token manually through the application configuration.

@Configuration
@EnableAutoConfiguration
public class ApplicationConfig extends WebMvcConfigurerAdapter {
  public static void main(String... args) {
    SpringApplication.run(ApplicationConfig.class, args);
  }

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(csrfTokenAddingInterceptor());
  }

  @Bean
  public HandlerInterceptor csrfTokenAddingInterceptor() {
    return new HandlerInterceptorAdapter() {
      @Override
      public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView view) {
        CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName())
        if (token != null) {
          view.addObject(token.getParameterName(), token)
        }
      }
    }
  }
}

Now your code #{_csrf.parameterName} and #{_csrf.token} will work.

Note: Special credit to this answer.

Upvotes: 4

Related Questions