Browse Source

Don't apply CookieSameSiteSupplier to session cookies when using Jetty

Closes gh-39766
pull/40554/head
Moritz Halbritter 2 years ago
parent
commit
00a25f5d89
  1. 25
      spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyServletWebServerFactory.java
  2. 20
      spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java

25
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyServletWebServerFactory.java

@ -77,6 +77,7 @@ import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.eclipse.jetty.session.DefaultSessionCache; import org.eclipse.jetty.session.DefaultSessionCache;
import org.eclipse.jetty.session.FileSessionDataStore; import org.eclipse.jetty.session.FileSessionDataStore;
import org.eclipse.jetty.session.SessionConfig;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.resource.CombinedResource; import org.eclipse.jetty.util.resource.CombinedResource;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
@ -237,11 +238,17 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
handler = applyWrapper(handler, JettyHandlerWrappers.createServerHeaderHandlerWrapper(getServerHeader())); handler = applyWrapper(handler, JettyHandlerWrappers.createServerHeaderHandlerWrapper(getServerHeader()));
} }
if (!CollectionUtils.isEmpty(getCookieSameSiteSuppliers())) { if (!CollectionUtils.isEmpty(getCookieSameSiteSuppliers())) {
handler = applyWrapper(handler, new SuppliedSameSiteCookieHandlerWrapper(getCookieSameSiteSuppliers())); handler = applyWrapper(handler,
new SuppliedSameSiteCookieHandlerWrapper(getSessionCookieName(), getCookieSameSiteSuppliers()));
} }
return handler; return handler;
} }
private String getSessionCookieName() {
String name = getSession().getCookie().getName();
return (name != null) ? name : SessionConfig.__DefaultSessionCookie;
}
private Handler applyWrapper(Handler handler, Handler.Wrapper wrapper) { private Handler applyWrapper(Handler handler, Handler.Wrapper wrapper) {
wrapper.setHandler(handler); wrapper.setHandler(handler);
return wrapper; return wrapper;
@ -779,9 +786,12 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
private static final SetCookieParser setCookieParser = SetCookieParser.newInstance(); private static final SetCookieParser setCookieParser = SetCookieParser.newInstance();
private final String sessionCookieName;
private final List<CookieSameSiteSupplier> suppliers; private final List<CookieSameSiteSupplier> suppliers;
SuppliedSameSiteCookieHandlerWrapper(List<CookieSameSiteSupplier> suppliers) { SuppliedSameSiteCookieHandlerWrapper(String sessionCookieName, List<CookieSameSiteSupplier> suppliers) {
this.sessionCookieName = sessionCookieName;
this.suppliers = suppliers; this.suppliers = suppliers;
} }
@ -793,7 +803,7 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
private class SuppliedSameSiteCookieResponse extends Response.Wrapper { private class SuppliedSameSiteCookieResponse extends Response.Wrapper {
private HttpFields.Mutable wrappedHeaders; private final HttpFields.Mutable wrappedHeaders;
SuppliedSameSiteCookieResponse(Request request, Response wrapped) { SuppliedSameSiteCookieResponse(Request request, Response wrapped) {
super(request, wrapped); super(request, wrapped);
@ -825,7 +835,10 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
private HttpField onAddSetCookieField(HttpField field) { private HttpField onAddSetCookieField(HttpField field) {
HttpCookie cookie = setCookieParser.parse(field.getValue()); HttpCookie cookie = setCookieParser.parse(field.getValue());
SameSite sameSite = (cookie != null) ? getSameSite(cookie) : null; if (cookie == null || isSessionCookie(cookie)) {
return field;
}
SameSite sameSite = getSameSite(cookie);
if (sameSite == null) { if (sameSite == null) {
return field; return field;
} }
@ -833,6 +846,10 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
return new HttpCookieUtils.SetCookieHttpField(updatedCookie, this.compliance); return new HttpCookieUtils.SetCookieHttpField(updatedCookie, this.compliance);
} }
private boolean isSessionCookie(HttpCookie cookie) {
return SuppliedSameSiteCookieHandlerWrapper.this.sessionCookieName.equals(cookie.getName());
}
private HttpCookie buildCookieWithUpdatedSameSite(HttpCookie cookie, SameSite sameSite) { private HttpCookie buildCookieWithUpdatedSameSite(HttpCookie cookie, SameSite sameSite) {
return HttpCookie.build(cookie) return HttpCookie.build(cookie)
.sameSite(org.eclipse.jetty.http.HttpCookie.SameSite.from(sameSite.name())) .sameSite(org.eclipse.jetty.http.HttpCookie.SameSite.from(sameSite.name()))

20
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java

@ -177,6 +177,7 @@ import static org.mockito.Mockito.times;
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Raja Kolli * @author Raja Kolli
* @author Scott Frederick * @author Scott Frederick
* @author Moritz Halbritter
*/ */
@SuppressWarnings("removal") @SuppressWarnings("removal")
@ExtendWith(OutputCaptureExtension.class) @ExtendWith(OutputCaptureExtension.class)
@ -957,6 +958,23 @@ public abstract class AbstractServletWebServerFactoryTests {
(header) -> assertThat(header).contains("controlled=test").contains("SameSite=Strict")); (header) -> assertThat(header).contains("controlled=test").contains("SameSite=Strict"));
} }
@Test
void cookieSameSiteSuppliersShouldNotAffectSessionCookie() throws IOException, URISyntaxException {
AbstractServletWebServerFactory factory = getFactory();
factory.getSession().getCookie().setSameSite(SameSite.LAX);
factory.getSession().getCookie().setName("SESSIONCOOKIE");
factory.addCookieSameSiteSuppliers(CookieSameSiteSupplier.ofStrict());
factory.addInitializers(new ServletRegistrationBean<>(new CookieServlet(false), "/"));
this.webServer = factory.getWebServer();
this.webServer.start();
ClientHttpResponse clientResponse = getClientResponse(getLocalUrl("/"));
assertThat(clientResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
List<String> setCookieHeaders = clientResponse.getHeaders().get("Set-Cookie");
assertThat(setCookieHeaders).satisfiesExactlyInAnyOrder(
(header) -> assertThat(header).contains("SESSIONCOOKIE").contains("SameSite=Lax"),
(header) -> assertThat(header).contains("test=test").contains("SameSite=Strict"));
}
@Test @Test
protected void sslSessionTracking() { protected void sslSessionTracking() {
AbstractServletWebServerFactory factory = getFactory(); AbstractServletWebServerFactory factory = getFactory();
@ -1803,7 +1821,7 @@ public abstract class AbstractServletWebServerFactoryTests {
} }
@Override @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
req.getSession(true); req.getSession(true);
resp.addCookie(new Cookie("test", "test")); resp.addCookie(new Cookie("test", "test"));
if (this.addSupplierTestCookies) { if (this.addSupplierTestCookies) {

Loading…
Cancel
Save