Skip to content

Commit

Permalink
Merge pull request #42316 from nosan
Browse files Browse the repository at this point in the history
* pr/42316:
  Polish "Add support for partitioned cookies"
  Add support for partitioned cookies

Closes gh-42316
  • Loading branch information
mhalbritter committed Sep 25, 2024
2 parents 7a176bc + 2114744 commit eb7b6a7
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -98,6 +98,7 @@ DefaultCookieSerializer cookieSerializer(ServerProperties serverProperties,
map.from(cookie::getSecure).to(cookieSerializer::setUseSecureCookie);
map.from(cookie::getMaxAge).asInt(Duration::getSeconds).to(cookieSerializer::setCookieMaxAge);
map.from(cookie::getSameSite).as(SameSite::attributeValue).to(cookieSerializer::setSameSite);
map.from(cookie::getPartitioned).to(cookieSerializer::setPartitioned);
cookieSerializerCustomizers.orderedStream().forEach((customizer) -> customizer.customize(cookieSerializer));
return cookieSerializer;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -76,6 +76,7 @@ private void initializeCookie(ResponseCookieBuilder builder) {
map.from(cookie::getHttpOnly).to(builder::httpOnly);
map.from(cookie::getSecure).to(builder::secure);
map.from(cookie::getMaxAge).to(builder::maxAge);
map.from(cookie::getPartitioned).to(builder::partitioned);
map.from(getSameSite(cookie)).to(builder::sameSite);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@
"name": "server.reactive.session.cookie.name",
"description": "Name for the cookie."
},
{
"name": "server.reactive.session.cookie.partitioned",
"description": "Whether the generated cookie carries the Partitioned attribute."
},
{
"name": "server.reactive.session.cookie.path",
"description": "Path of the cookie."
Expand Down Expand Up @@ -229,6 +233,10 @@
"name": "server.servlet.session.cookie.name",
"description": "Name of the cookie."
},
{
"name": "server.servlet.session.cookie.partitioned",
"description": "Whether the generated cookie carries the Partitioned attribute."
},
{
"name": "server.servlet.session.cookie.path",
"description": "Path of the cookie."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ void sessionCookieConfigurationIsAppliedToAutoConfiguredCookieSerializer() {
.withPropertyValues("server.servlet.session.cookie.name=sid", "server.servlet.session.cookie.domain=spring",
"server.servlet.session.cookie.path=/test", "server.servlet.session.cookie.httpOnly=false",
"server.servlet.session.cookie.secure=false", "server.servlet.session.cookie.maxAge=10s",
"server.servlet.session.cookie.sameSite=strict")
"server.servlet.session.cookie.sameSite=strict", "server.servlet.session.cookie.partitioned=true")
.run((context) -> {
DefaultCookieSerializer cookieSerializer = context.getBean(DefaultCookieSerializer.class);
assertThat(cookieSerializer).hasFieldOrPropertyWithValue("cookieName", "sid");
Expand All @@ -166,6 +166,7 @@ void sessionCookieConfigurationIsAppliedToAutoConfiguredCookieSerializer() {
assertThat(cookieSerializer).hasFieldOrPropertyWithValue("useSecureCookie", false);
assertThat(cookieSerializer).hasFieldOrPropertyWithValue("cookieMaxAge", 10);
assertThat(cookieSerializer).hasFieldOrPropertyWithValue("sameSite", "Strict");
assertThat(cookieSerializer).hasFieldOrPropertyWithValue("partitioned", true);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,8 @@ void customSessionCookieConfigurationShouldBeApplied() {
this.contextRunner.withPropertyValues("server.reactive.session.cookie.name:JSESSIONID",
"server.reactive.session.cookie.domain:.example.com", "server.reactive.session.cookie.path:/example",
"server.reactive.session.cookie.max-age:60", "server.reactive.session.cookie.http-only:false",
"server.reactive.session.cookie.secure:false", "server.reactive.session.cookie.same-site:strict")
"server.reactive.session.cookie.secure:false", "server.reactive.session.cookie.same-site:strict",
"server.reactive.session.cookie.partitioned:true")
.run(assertExchangeWithSession((exchange) -> {
List<ResponseCookie> cookies = exchange.getResponse().getCookies().get("JSESSIONID");
assertThat(cookies).isNotEmpty();
Expand All @@ -654,6 +655,7 @@ void customSessionCookieConfigurationShouldBeApplied() {
assertThat(cookies).allMatch((cookie) -> !cookie.isHttpOnly());
assertThat(cookies).allMatch((cookie) -> !cookie.isSecure());
assertThat(cookies).allMatch((cookie) -> cookie.getSameSite().equals("Strict"));
assertThat(cookies).allMatch(ResponseCookie::isPartitioned);
}));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -57,6 +57,11 @@ public class Cookie {
*/
private Boolean secure;

/**
* Whether the generated cookie carries the Partitioned attribute.
*/
private Boolean partitioned;

/**
* Maximum age of the cookie. If a duration suffix is not specified, seconds will be
* used. A positive value indicates when the cookie expires relative to the current
Expand Down Expand Up @@ -127,6 +132,14 @@ public void setSameSite(SameSite sameSite) {
this.sameSite = sameSite;
}

public Boolean getPartitioned() {
return this.partitioned;
}

public void setPartitioned(Boolean partitioned) {
this.partitioned = partitioned;
}

/**
* SameSite values.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
public abstract class AbstractServletWebServerFactory extends AbstractConfigurableWebServerFactory
implements ConfigurableServletWebServerFactory {

private static final String PARTITIONED_ATTRIBUTE_NAME = "Partitioned";

protected final Log logger = LogFactory.getLog(getClass());

private String contextPath = "";
Expand Down Expand Up @@ -350,6 +352,9 @@ private void configureSessionCookie(SessionCookieConfig config) {
map.from(cookie::getHttpOnly).to(config::setHttpOnly);
map.from(cookie::getSecure).to(config::setSecure);
map.from(cookie::getMaxAge).asInt(Duration::getSeconds).to(config::setMaxAge);
map.from(cookie::getPartitioned)
.as(Object::toString)
.to((partitioned) -> config.setAttribute(PARTITIONED_ATTRIBUTE_NAME, partitioned));
}

private Set<jakarta.servlet.SessionTrackingMode> unwrap(Set<Session.SessionTrackingMode> modes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,7 @@ void sessionCookieConfiguration() {
factory.getSession().getCookie().setPath("/testpath");
factory.getSession().getCookie().setHttpOnly(true);
factory.getSession().getCookie().setSecure(true);
factory.getSession().getCookie().setPartitioned(true);
factory.getSession().getCookie().setMaxAge(Duration.ofSeconds(60));
final AtomicReference<SessionCookieConfig> configReference = new AtomicReference<>();
this.webServer = factory.getWebServer((context) -> configReference.set(context.getSessionCookieConfig()));
Expand All @@ -872,6 +873,7 @@ void sessionCookieConfiguration() {
assertThat(sessionCookieConfig.getPath()).isEqualTo("/testpath");
assertThat(sessionCookieConfig.isHttpOnly()).isTrue();
assertThat(sessionCookieConfig.isSecure()).isTrue();
assertThat(sessionCookieConfig.getAttribute("Partitioned")).isEqualTo("true");
assertThat(sessionCookieConfig.getMaxAge()).isEqualTo(60);
}

Expand Down Expand Up @@ -1166,6 +1168,7 @@ void sessionConfiguration() {
factory.getSession().getCookie().setPath("/testpath");
factory.getSession().getCookie().setHttpOnly(true);
factory.getSession().getCookie().setSecure(true);
factory.getSession().getCookie().setPartitioned(false);
factory.getSession().getCookie().setMaxAge(Duration.ofMinutes(1));
AtomicReference<ServletContext> contextReference = new AtomicReference<>();
factory.getWebServer(contextReference::set).start();
Expand All @@ -1178,6 +1181,7 @@ void sessionConfiguration() {
assertThat(servletContext.getSessionCookieConfig().isHttpOnly()).isTrue();
assertThat(servletContext.getSessionCookieConfig().isSecure()).isTrue();
assertThat(servletContext.getSessionCookieConfig().getMaxAge()).isEqualTo(60);
assertThat(servletContext.getSessionCookieConfig().getAttribute("Partitioned")).isEqualTo("false");
}

@Test
Expand Down

0 comments on commit eb7b6a7

Please sign in to comment.