Merge pull request #42316 from nosan
* pr/42316: Polish "Add support for partitioned cookies" Add support for partitioned cookies Closes gh-42316
This commit is contained in:
commit
eb7b6a776d
|
@ -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.
|
||||
|
@ -98,6 +98,7 @@ public class SessionAutoConfiguration {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -76,6 +76,7 @@ public class WebSessionIdResolverAutoConfiguration {
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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."
|
||||
|
@ -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."
|
||||
|
|
|
@ -156,7 +156,7 @@ class SessionAutoConfigurationTests extends AbstractSessionAutoConfigurationTest
|
|||
.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");
|
||||
|
@ -166,6 +166,7 @@ class SessionAutoConfigurationTests extends AbstractSessionAutoConfigurationTest
|
|||
assertThat(cookieSerializer).hasFieldOrPropertyWithValue("useSecureCookie", false);
|
||||
assertThat(cookieSerializer).hasFieldOrPropertyWithValue("cookieMaxAge", 10);
|
||||
assertThat(cookieSerializer).hasFieldOrPropertyWithValue("sameSite", "Strict");
|
||||
assertThat(cookieSerializer).hasFieldOrPropertyWithValue("partitioned", true);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -644,7 +644,8 @@ class WebFluxAutoConfigurationTests {
|
|||
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();
|
||||
|
@ -654,6 +655,7 @@ class WebFluxAutoConfigurationTests {
|
|||
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);
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -127,6 +132,14 @@ public class Cookie {
|
|||
this.sameSite = sameSite;
|
||||
}
|
||||
|
||||
public Boolean getPartitioned() {
|
||||
return this.partitioned;
|
||||
}
|
||||
|
||||
public void setPartitioned(Boolean partitioned) {
|
||||
this.partitioned = partitioned;
|
||||
}
|
||||
|
||||
/**
|
||||
* SameSite values.
|
||||
*/
|
||||
|
|
|
@ -60,6 +60,8 @@ import org.springframework.util.ClassUtils;
|
|||
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 = "";
|
||||
|
@ -350,6 +352,9 @@ public abstract class AbstractServletWebServerFactory extends AbstractConfigurab
|
|||
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) {
|
||||
|
|
|
@ -863,6 +863,7 @@ public abstract class AbstractServletWebServerFactoryTests {
|
|||
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()));
|
||||
|
@ -872,6 +873,7 @@ public abstract class AbstractServletWebServerFactoryTests {
|
|||
assertThat(sessionCookieConfig.getPath()).isEqualTo("/testpath");
|
||||
assertThat(sessionCookieConfig.isHttpOnly()).isTrue();
|
||||
assertThat(sessionCookieConfig.isSecure()).isTrue();
|
||||
assertThat(sessionCookieConfig.getAttribute("Partitioned")).isEqualTo("true");
|
||||
assertThat(sessionCookieConfig.getMaxAge()).isEqualTo(60);
|
||||
}
|
||||
|
||||
|
@ -1166,6 +1168,7 @@ public abstract class AbstractServletWebServerFactoryTests {
|
|||
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();
|
||||
|
@ -1178,6 +1181,7 @@ public abstract class AbstractServletWebServerFactoryTests {
|
|||
assertThat(servletContext.getSessionCookieConfig().isHttpOnly()).isTrue();
|
||||
assertThat(servletContext.getSessionCookieConfig().isSecure()).isTrue();
|
||||
assertThat(servletContext.getSessionCookieConfig().getMaxAge()).isEqualTo(60);
|
||||
assertThat(servletContext.getSessionCookieConfig().getAttribute("Partitioned")).isEqualTo("false");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue