Reputation: 893
I have a very simple Spring Boot Application which consists of a main Application.java (with the default main method), a MainController (which has one requestMapping to /login), and a SecurityConfig (with mainly default values).
My problem is with the _csrf support in Groovy Templates. Everything works fine with FreeMarker, but when I switch to GroovyTemplates the _csrf param does not get put into the model.
Is there a bug in the Groovy Templates, something manually I have to do to grab the token, or is there some configuration step I'm missing (although I don't know why it would work for FreeMarker) ?
UPDATE:
I printed this.properties (HashMap) on the login.tpl (Groovy Template) :
{class=class login, out=java.io.BufferedWriter@5e2aead3, model={error=Optional.empty, org.springframework.validation.BindingResult.error=org.springframework.validation.BeanPropertyBindingResult: 0 errors, spring=org.springframework.web.servlet.support.RequestContext@1d99fb33, springMacroRequestContext=org.springframework.web.servlet.support.RequestContext@7fcc5c78}}
The model key in the properties map includes the parameters
I added error in the Controller action using the:
@RequestMapping(value="/login", method = RequestMethod.GET)
public ModelAndView login(@RequestParam Optional<String> error) {
return new ModelAndView("views/login", "error", error);
}
Upvotes: 1
Views: 676
Reputation: 38676
So the hacked up way to handle this is to manually add the _csrf attribute to your model in your Controller. For example:
model.addAttribute( "_csrf", request.getAttribute("_csrf") );
I wouldn't recommend that if you have lots of views on your server. I'd suggest you follow one of the options from @M-Deinnum. But, for quick testing this works.
Upvotes: 0
Reputation: 124441
When using the GroovyMarkupView
and the GroovyMarkupViewResolver
the properties of the view only contain properties available in the model (and some added for Groovy).
To include the request attributes set the exposeRequestAttributes
property of the GroovyMarkupViewResolver
to true
. Ideally this is done by setting the following property in the application.properties
.
spring.groovy.template.exposeRequestAttributes=true
However due to this issue that currently isn't possible.
To work around it create a BeanPostProcessor
which check if the incoming bean is a GroovyMarkupViewResolver
(or AbstractTemplateViewResolver
if you want a more general approach). If so set the exposeRequestAttributes
to true.
public class TemplateViewResolverPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instance GroovyMarkupViewResolver) {
((GroovyMarkupViewResolver) bean).setExposeRequestAttributes(true);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
After doing that the CsfrToken
is available with the key _csfr
, be aware that this is the actual CsfrToken
.
Another solution is to create a HandlerInterceptor
implement the postHandle
method and add the _csfr
property to the model. That way you can simply add the value of the token instead of the actual token itself. This will work with any view technology used.
public class CsrfAddingInterceptor extends HandlerInterceptorAdapter {
public void postHandle(HttpServletRequest req, HttpServletResponse res, Object handler, ModelAndView mav) throws Exception {
CsrfToken token = (CsrfToken) req.getAttribute(CsrfToken.class.getName())
if (token != null) {
mav.addAttribute(token.getParameterName(), token.getToken());
}
}
}
Then add it as an interceptor and you will have the value available.
Upvotes: 4