close

Filter

loading table of contents...

Content Application Developer Manual / Version 2406.0

Table Of Contents
Backward Compatibility for CSRF Tokens in Legacy Templates

When updating to CoreMedia CMCC from an older version to 2007 or newer, there may be custom templates (other ones than those that are provided with Blueprint) that cannot instantly be updated to using the org.springframework.security.web.csrf.CsrfToken instead of the former _CSRFToken string. To allow such legacy templates to still work (for a migration period) with the Spring Security CSRF implementation that is now used by CoreMedia CMCC, the following code snippets show how to add backward compatibility to the project.

To allow the legacy templates to still render the _CSRFToken parameters with the string value, a HandlerInterceptor has to be added that provides the _CSRFToken request attribute to the templates:

package com.coremedia.blueprint.component.cae.csrf;

import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

class CsrfLegacyTokenSetter implements HandlerInterceptor {

  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response,
                         Object handler, ModelAndView modelAndView) {
    CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
    if (csrfToken != null) {
      request.setAttribute("_CSRFToken", csrfToken.getToken());
    }
  }
}

Example 4.15. Implementing a CsrfLegacyTokenSetter


To verify the token, Spring Security expects the CSRF token to be provided with different parameter and header names. To allow Spring Security to also verify tokens that are sent by the legacy templates, a filter has to be added that wraps the HttpServletRequest with one that gets the token using the old parameter or header name when it is not provided with the new name:

package com.coremedia.blueprint.component.cae.csrf;

import org.springframework.web.filter.OncePerRequestFilter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

class CsrfLegacyTokenGetterFilter extends OncePerRequestFilter {

  @Override
  protected void doFilterInternal(HttpServletRequest request,
                                  HttpServletResponse response,
                                  FilterChain filterChain)
          throws ServletException, IOException {
    filterChain.doFilter(new CsrfLegacyTokenRequestWrapper(request), response);
  }

  private static class CsrfLegacyTokenRequestWrapper extends HttpServletRequestWrapper {

    public CsrfLegacyTokenRequestWrapper(HttpServletRequest request) {
      super(request);
    }

    @Override
    public String getParameter(String name) {
      String value = super.getParameter(name);
      if (value == null && "_csrf".equals(name)) {
        value = super.getParameter("_CSRFToken");
      }
      return value;
    }

    @Override
    public String getHeader(String name) {
      String value = super.getHeader(name);
      if (value == null && "X-CSRF-TOKEN".equals(name)) {
        value = super.getHeader("X-CSRFToken");
      }
      return value;
    }
  }
}

Example 4.16. Implementing a CsrfLegacyTokenGetterFilter


Both classes have to be added to the application context for the CAE:

package com.coremedia.blueprint.component.cae.csrf;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.handler.MappedInterceptor;

@Configuration(proxyBeanMethods = false)
public class CaeCsrfBackwardCompatibilityConfiguration {

  private static final int ORDER_CSRF_LEGACY_TOKEN_FILTER =
          Ordered.HIGHEST_PRECEDENCE + 347_483_648; // == -1_800_000_000

  @Bean
  public MappedInterceptor csrfLegacyTokenSetter() {
    // Register the token setter for all paths
    return new MappedInterceptor(null, new CsrfLegacyTokenSetter());
  }

  @Bean
  public FilterRegistrationBean<CsrfLegacyTokenGetterFilter> csrfLegacyTokenGetterFRB() {
    var registrationBean = new FilterRegistrationBean<>(
            new CsrfLegacyTokenGetterFilter());
    // Register the filter before the Spring Security filter chain
    registrationBean.setOrder(ORDER_CSRF_LEGACY_TOKEN_FILTER);
    return registrationBean;
  }
}

Example 4.17. Configuring CSRF backward compatibility


Search Results

Table Of Contents
warning

Your Internet Explorer is no longer supported.

Please use Mozilla Firefox, Google Chrome, or Microsoft Edge.