Skip to content

Commit 008cbc2

Browse files
fb64marcusdacoregio
authored andcommitted
Add cookie customizer to CookieRequestCache and CookieServerRequestCache
Issue gh-15204
1 parent 820ce4e commit 008cbc2

File tree

4 files changed

+72
-8
lines changed

4 files changed

+72
-8
lines changed

web/src/main/java/org/springframework/security/web/savedrequest/CookieRequestCache.java

+15
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.Base64;
2020
import java.util.Collections;
21+
import java.util.function.Consumer;
2122

2223
import jakarta.servlet.http.Cookie;
2324
import jakarta.servlet.http.HttpServletRequest;
@@ -51,6 +52,9 @@ public class CookieRequestCache implements RequestCache {
5152

5253
private static final int COOKIE_MAX_AGE = -1;
5354

55+
private Consumer<Cookie> cookieCustomizer = (cookie) -> {
56+
};
57+
5458
@Override
5559
public void saveRequest(HttpServletRequest request, HttpServletResponse response) {
5660
if (!this.requestMatcher.matches(request)) {
@@ -63,6 +67,7 @@ public void saveRequest(HttpServletRequest request, HttpServletResponse response
6367
savedCookie.setSecure(request.isSecure());
6468
savedCookie.setPath(getCookiePath(request));
6569
savedCookie.setHttpOnly(true);
70+
this.cookieCustomizer.accept(savedCookie);
6671
response.addCookie(savedCookie);
6772
}
6873

@@ -152,4 +157,14 @@ public void setRequestMatcher(RequestMatcher requestMatcher) {
152157
this.requestMatcher = requestMatcher;
153158
}
154159

160+
/**
161+
* Sets the {@link Consumer}, allowing customization of cookie.
162+
* @param cookieCustomizer customize for cookie
163+
* @since 6.4
164+
*/
165+
public void setCookieCustomizer(Consumer<Cookie> cookieCustomizer) {
166+
Assert.notNull(cookieCustomizer, "cookieCustomizer cannot be null");
167+
this.cookieCustomizer = cookieCustomizer;
168+
}
169+
155170
}

web/src/main/java/org/springframework/security/web/server/savedrequest/CookieServerRequestCache.java

+24-8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.time.Duration;
2121
import java.util.Base64;
2222
import java.util.Collections;
23+
import java.util.function.Consumer;
2324

2425
import org.apache.commons.logging.Log;
2526
import org.apache.commons.logging.LogFactory;
@@ -59,6 +60,9 @@ public class CookieServerRequestCache implements ServerRequestCache {
5960

6061
private ServerWebExchangeMatcher saveRequestMatcher = createDefaultRequestMatcher();
6162

63+
private Consumer<ResponseCookie.ResponseCookieBuilder> cookieCustomizer = (cookieBuilder) -> {
64+
};
65+
6266
/**
6367
* Sets the matcher to determine if the request should be saved. The default is to
6468
* match on any GET request.
@@ -77,8 +81,10 @@ public Mono<Void> saveRequest(ServerWebExchange exchange) {
7781
.map((m) -> exchange.getResponse())
7882
.map(ServerHttpResponse::getCookies)
7983
.doOnNext((cookies) -> {
80-
ResponseCookie redirectUriCookie = createRedirectUriCookie(exchange.getRequest());
81-
cookies.add(REDIRECT_URI_COOKIE_NAME, redirectUriCookie);
84+
ResponseCookie.ResponseCookieBuilder redirectUriCookie = createRedirectUriCookieBuilder(
85+
exchange.getRequest());
86+
this.cookieCustomizer.accept(redirectUriCookie);
87+
cookies.add(REDIRECT_URI_COOKIE_NAME, redirectUriCookie.build());
8288
logger.debug(LogMessage.format("Request added to Cookie: %s", redirectUriCookie));
8389
})
8490
.then();
@@ -103,25 +109,35 @@ public Mono<ServerHttpRequest> removeMatchingRequest(ServerWebExchange exchange)
103109
.thenReturn(exchange.getRequest());
104110
}
105111

106-
private static ResponseCookie createRedirectUriCookie(ServerHttpRequest request) {
112+
/**
113+
* Sets the {@link Consumer}, allowing customization of cookie.
114+
* @param cookieCustomizer customize for cookie
115+
* @since 6.4
116+
*/
117+
public void setCookieCustomizer(Consumer<ResponseCookie.ResponseCookieBuilder> cookieCustomizer) {
118+
Assert.notNull(cookieCustomizer, "cookieCustomizer cannot be null");
119+
this.cookieCustomizer = cookieCustomizer;
120+
}
121+
122+
private static ResponseCookie.ResponseCookieBuilder createRedirectUriCookieBuilder(ServerHttpRequest request) {
107123
String path = request.getPath().pathWithinApplication().value();
108124
String query = request.getURI().getRawQuery();
109125
String redirectUri = path + ((query != null) ? "?" + query : "");
110-
return createResponseCookie(request, encodeCookie(redirectUri), COOKIE_MAX_AGE);
126+
return createResponseCookieBuilder(request, encodeCookie(redirectUri), COOKIE_MAX_AGE);
111127
}
112128

113129
private static ResponseCookie invalidateRedirectUriCookie(ServerHttpRequest request) {
114-
return createResponseCookie(request, null, Duration.ZERO);
130+
return createResponseCookieBuilder(request, null, Duration.ZERO).build();
115131
}
116132

117-
private static ResponseCookie createResponseCookie(ServerHttpRequest request, String cookieValue, Duration age) {
133+
private static ResponseCookie.ResponseCookieBuilder createResponseCookieBuilder(ServerHttpRequest request,
134+
String cookieValue, Duration age) {
118135
return ResponseCookie.from(REDIRECT_URI_COOKIE_NAME, cookieValue)
119136
.path(request.getPath().contextPath().value() + "/")
120137
.maxAge(age)
121138
.httpOnly(true)
122139
.secure("https".equalsIgnoreCase(request.getURI().getScheme()))
123-
.sameSite("Lax")
124-
.build();
140+
.sameSite("Lax");
125141
}
126142

127143
private static String encodeCookie(String cookieValue) {

web/src/test/java/org/springframework/security/web/savedrequest/CookieRequestCacheTests.java

+17
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Base64;
2121
import java.util.Collections;
2222
import java.util.Locale;
23+
import java.util.function.Consumer;
2324

2425
import jakarta.servlet.http.Cookie;
2526
import jakarta.servlet.http.HttpServletRequest;
@@ -204,6 +205,22 @@ public void matchingRequestWhenMatchThenKeepOriginalRequestLocale() {
204205
assertThat(Collections.list(matchingRequest.getLocales())).contains(Locale.FRENCH, Locale.GERMANY);
205206
}
206207

208+
@Test
209+
public void setCookieCustomizer() {
210+
Consumer<Cookie> cookieCustomizer = (cookie) -> {
211+
cookie.setAttribute("SameSite", "Strict");
212+
cookie.setAttribute("CustomAttribute", "CustomValue");
213+
};
214+
CookieRequestCache cookieRequestCache = new CookieRequestCache();
215+
cookieRequestCache.setCookieCustomizer(cookieCustomizer);
216+
MockHttpServletResponse response = new MockHttpServletResponse();
217+
cookieRequestCache.saveRequest(new MockHttpServletRequest(), response);
218+
Cookie savedCookie = response.getCookie(DEFAULT_COOKIE_NAME);
219+
assertThat(savedCookie).isNotNull();
220+
assertThat(savedCookie.getAttribute("SameSite")).isEqualTo("Strict");
221+
assertThat(savedCookie.getAttribute("CustomAttribute")).isEqualTo("CustomValue");
222+
}
223+
207224
private static String encodeCookie(String cookieValue) {
208225
return Base64.getEncoder().encodeToString(cookieValue.getBytes());
209226
}

web/src/test/java/org/springframework/security/web/server/savedrequest/CookieServerRequestCacheTests.java

+16
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,20 @@ public void removeMatchingRequestThenRedirectUriCookieExpired() {
138138
"REDIRECT_URI=; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax");
139139
}
140140

141+
@Test
142+
public void saveRequestWithCookieCustomizerThenSameSiteStrict() {
143+
MockServerWebExchange exchange = MockServerWebExchange
144+
.from(MockServerHttpRequest.get("/secured/").accept(MediaType.TEXT_HTML));
145+
CookieServerRequestCache cacheWithCustomizer = new CookieServerRequestCache();
146+
cacheWithCustomizer.setCookieCustomizer(((cookieBuilder) -> cookieBuilder.sameSite("Strict")));
147+
cacheWithCustomizer.saveRequest(exchange).block();
148+
MultiValueMap<String, ResponseCookie> cookies = exchange.getResponse().getCookies();
149+
assertThat(cookies).hasSize(1);
150+
ResponseCookie cookie = cookies.getFirst("REDIRECT_URI");
151+
assertThat(cookie).isNotNull();
152+
String encodedRedirectUrl = Base64.getEncoder().encodeToString("/secured/".getBytes());
153+
assertThat(cookie.toString())
154+
.isEqualTo("REDIRECT_URI=" + encodedRedirectUrl + "; Path=/; HttpOnly; SameSite=Strict");
155+
}
156+
141157
}

0 commit comments

Comments
 (0)