1515 */
1616
1717package org .springframework .security .web .csrf ;
18-
1918import java .util .UUID ;
19+ import java .util .function .Consumer ;
2020
21- import jakarta .servlet .ServletRequest ;
2221import jakarta .servlet .http .Cookie ;
2322import jakarta .servlet .http .HttpServletRequest ;
2423import jakarta .servlet .http .HttpServletResponse ;
2524
25+ import org .springframework .http .HttpHeaders ;
26+ import org .springframework .http .ResponseCookie ;
2627import org .springframework .util .Assert ;
2728import org .springframework .util .StringUtils ;
2829import org .springframework .web .util .WebUtils ;
3435 *
3536 * @author Rob Winch
3637 * @author Steve Riesenberg
38+ * @author Alex Montoya
3739 * @since 4.1
3840 */
3941public final class CookieCsrfTokenRepository implements CsrfTokenRepository {
@@ -63,7 +65,17 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository {
6365
6466 private int cookieMaxAge = -1 ;
6567
66- public CookieCsrfTokenRepository () {
68+ private Consumer <ResponseCookie .ResponseCookieBuilder > cookieCustomizer = (builder ) -> {};
69+
70+ /**
71+ * Add a {@link Consumer} for a {@code ResponseCookieBuilder} that will be invoked
72+ * for each cookie being built, just before the call to {@code build()}.
73+ * @param cookieCustomizer consumer for a cookie builder
74+ * @since 6.1
75+ */
76+ public void setCookieCustomizer (Consumer <ResponseCookie .ResponseCookieBuilder > cookieCustomizer ) {
77+ Assert .notNull (cookieCustomizer , "cookieCustomizer must not be null" );
78+ this .cookieCustomizer = cookieCustomizer ;
6779 }
6880
6981 @ Override
@@ -74,15 +86,17 @@ public CsrfToken generateToken(HttpServletRequest request) {
7486 @ Override
7587 public void saveToken (CsrfToken token , HttpServletRequest request , HttpServletResponse response ) {
7688 String tokenValue = (token != null ) ? token .getToken () : "" ;
77- Cookie cookie = new Cookie (this .cookieName , tokenValue );
78- cookie .setSecure ((this .secure != null ) ? this .secure : request .isSecure ());
79- cookie .setPath (StringUtils .hasLength (this .cookiePath ) ? this .cookiePath : this .getRequestContext (request ));
80- cookie .setMaxAge ((token != null ) ? this .cookieMaxAge : 0 );
81- cookie .setHttpOnly (this .cookieHttpOnly );
82- if (StringUtils .hasLength (this .cookieDomain )) {
83- cookie .setDomain (this .cookieDomain );
84- }
85- response .addCookie (cookie );
89+
90+ ResponseCookie .ResponseCookieBuilder cookieBuilder = ResponseCookie .from (this .cookieName , tokenValue )
91+ .secure (this .secure != null ? this .secure : request .isSecure ())
92+ .path (StringUtils .hasLength (this .cookiePath ) ? this .cookiePath : this .getRequestContext (request ))
93+ .maxAge (token != null ? this .cookieMaxAge : 0 )
94+ .httpOnly (this .cookieHttpOnly )
95+ .domain (this .cookieDomain );
96+
97+ this .cookieCustomizer .accept (cookieBuilder );
98+
99+ response .setHeader (HttpHeaders .SET_COOKIE , cookieBuilder .build ().toString ());
86100
87101 // Set request attribute to signal that response has blank cookie value,
88102 // which allows loadToken to return null when token has been removed
@@ -143,11 +157,9 @@ public void setCookieName(String cookieName) {
143157 }
144158
145159 /**
146- * Sets the HttpOnly attribute on the cookie containing the CSRF token. Defaults to
147- * <code>true</code>.
148- * @param cookieHttpOnly <code>true</code> sets the HttpOnly attribute,
149- * <code>false</code> does not set it
160+ * @deprecated Use {@link #setCookieCustomizer(Consumer)} instead.
150161 */
162+ @ Deprecated (since = "6.1" )
151163 public void setCookieHttpOnly (boolean cookieHttpOnly ) {
152164 this .cookieHttpOnly = cookieHttpOnly ;
153165 }
@@ -191,51 +203,30 @@ public String getCookiePath() {
191203 }
192204
193205 /**
194- * Sets the domain of the cookie that the expected CSRF token is saved to and read
195- * from.
196- * @param cookieDomain the domain of the cookie that the expected CSRF token is saved
197- * to and read from
206+ * @deprecated Use {@link #setCookieCustomizer(Consumer)} instead.
198207 * @since 5.2
199208 */
209+ @ Deprecated (since = "6.1" )
200210 public void setCookieDomain (String cookieDomain ) {
201211 this .cookieDomain = cookieDomain ;
202212 }
203213
204214 /**
205- * Sets secure flag of the cookie that the expected CSRF token is saved to and read
206- * from. By default secure flag depends on {@link ServletRequest#isSecure()}
207- * @param secure the secure flag of the cookie that the expected CSRF token is saved
208- * to and read from
215+ * @deprecated Use {@link #setCookieCustomizer(Consumer)} instead.
209216 * @since 5.4
210217 */
218+ @ Deprecated (since = "6.1" )
211219 public void setSecure (Boolean secure ) {
212220 this .secure = secure ;
213221 }
214222
215223 /**
216- * Sets maximum age in seconds for the cookie that the expected CSRF token is saved to
217- * and read from. By default maximum age value is -1.
218- *
219- * <p>
220- * A positive value indicates that the cookie will expire after that many seconds have
221- * passed. Note that the value is the <i>maximum</i> age when the cookie will expire,
222- * not the cookie's current age.
223- *
224- * <p>
225- * A negative value means that the cookie is not stored persistently and will be
226- * deleted when the Web browser exits.
227- *
228- * <p>
229- * A zero value causes the cookie to be deleted immediately therefore it is not a
230- * valid value and in that case an {@link IllegalArgumentException} will be thrown.
231- * @param cookieMaxAge an integer specifying the maximum age of the cookie in seconds;
232- * if negative, means the cookie is not stored; if zero, the method throws an
233- * {@link IllegalArgumentException}
224+ * @deprecated Use {@link #setCookieCustomizer(Consumer)} instead.
234225 * @since 5.5
235226 */
227+ @ Deprecated (since = "6.1" )
236228 public void setCookieMaxAge (int cookieMaxAge ) {
237229 Assert .isTrue (cookieMaxAge != 0 , "cookieMaxAge cannot be zero" );
238230 this .cookieMaxAge = cookieMaxAge ;
239231 }
240-
241232}
0 commit comments