CsrfRequestDataValueProcessor takes care of adding a hidden form input field with the CSRF token value for POST forms. This is done in the getExtraHiddenFields() method. When there is no active session (i.e. anonymous user), this triggers a session creation. If some output has already been written to the response (i.e. it's "committed") prior to this and cookies are used to store the session id, this exception occurs:
java.lang.IllegalStateException: Cannot create a session after the response has been committed
Actual Behavior
In Thymeleaf (3), this can occur: (see https://github.com/thymeleaf/thymeleaf-spring/issues/110) in certain conditions:
I have no experience with JSP, but a quick search suggests that flushing output before the whole page is processed is also possible.
I expect other view renderers using CsrfRequestDataValueProcessor can also exhibit this kind of behavior.
Requesting a CSRF token when rendering a form while no session is active is probably a common case when GETting login forms.
The obvious workaround is to make sure a session is created for any page containing a form which can be accessed anonymously.
I haven't been able (yet) to find anything better than my current workaround to solve this issue. Hopefully someone will have a better idea how to solve this.
Spring Boot 1.3.5 with Thymeleaf 3
@berniegp Thanks for the feedback.
As you suggested, the only thing you can really do to prevent this is to eagerly create the CsrfToken. In Spring Security 4.1.0.RELEASE+ and Java Configuration you can do this with:
http
.csrf()
.csrfTokenRepository(new HttpSessionCsrfTokenRepository())
This tells Spring Security that you do not want the token to be lazily persisted. If you are concerned with creating a session, you can also use the cookie implementation. For example:
http
.csrf()
.csrfTokenRepository(new CookieCsrfTokenRepository())
With Spring Boot, you can override the Spring Security version using the information from Customize dependency versions:
build.gradle
ext['spring-security.version'] = '4.1.0.RELEASE'
pom.xml
<spring-security.version>4.1.0.RELEASE</spring-security.version>
I'm fairly confident this resolves the issue, so I'm closing this as answered. If you have additional questions, please re-open or create a new ticket :)
Thank you @rwinch!
Most helpful comment
@berniegp Thanks for the feedback.
As you suggested, the only thing you can really do to prevent this is to eagerly create the
CsrfToken. In Spring Security 4.1.0.RELEASE+ and Java Configuration you can do this with:This tells Spring Security that you do not want the token to be lazily persisted. If you are concerned with creating a session, you can also use the cookie implementation. For example:
With Spring Boot, you can override the Spring Security version using the information from Customize dependency versions:
build.gradle
pom.xml