diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java index 0c055004e9cc..231dd18e3316 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java @@ -71,6 +71,7 @@ * @author Eddú Meléndez * @author Stephane Nicoll * @author Vedran Pavic + * @author Yanming Zhou * @since 1.4.0 */ @Configuration(proxyBeanMethods = false) @@ -97,10 +98,12 @@ DefaultCookieSerializer cookieSerializer(ServerProperties serverProperties, PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(cookie::getName).to(cookieSerializer::setCookieName); map.from(cookie::getDomain).to(cookieSerializer::setDomainName); + map.from(cookie::getDomainPattern).to(cookieSerializer::setDomainNamePattern); map.from(cookie::getPath).to(cookieSerializer::setCookiePath); map.from(cookie::getHttpOnly).to(cookieSerializer::setUseHttpOnlyCookie); map.from(cookie::getSecure).to(cookieSerializer::setUseSecureCookie); map.from(cookie::getMaxAge).to((maxAge) -> cookieSerializer.setCookieMaxAge((int) maxAge.getSeconds())); + map.from(cookie::getSameSite).to(cookieSerializer::setSameSite); cookieSerializerCustomizers.orderedStream().forEach((customizer) -> customizer.customize(cookieSerializer)); return cookieSerializer; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationTests.java index 25233f614497..6a48750d593f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationTests.java @@ -54,6 +54,7 @@ * @author Eddú Meléndez * @author Stephane Nicoll * @author Vedran Pavic + * @author Yanming Zhou */ class SessionAutoConfigurationTests extends AbstractSessionAutoConfigurationTests { @@ -143,7 +144,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.maxAge=10s", "server.servlet.session.cookie.sameSite=Strict") .run((context) -> { DefaultCookieSerializer cookieSerializer = context.getBean(DefaultCookieSerializer.class); assertThat(cookieSerializer).hasFieldOrPropertyWithValue("cookieName", "sid"); @@ -152,6 +153,17 @@ void sessionCookieConfigurationIsAppliedToAutoConfiguredCookieSerializer() { assertThat(cookieSerializer).hasFieldOrPropertyWithValue("useHttpOnlyCookie", false); assertThat(cookieSerializer).hasFieldOrPropertyWithValue("useSecureCookie", false); assertThat(cookieSerializer).hasFieldOrPropertyWithValue("cookieMaxAge", 10); + assertThat(cookieSerializer).hasFieldOrPropertyWithValue("sameSite", "Strict"); + }); + } + + @Test + void sessionCookieDomainPatternConfigurationIsAppliedToAutoConfiguredCookieSerializer() { + this.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class) + .withPropertyValues("server.servlet.session.cookie.domainPattern=^.+?\\\\.(\\\\w+\\\\.[a-z]+)$") + .run((context) -> { + DefaultCookieSerializer cookieSerializer = context.getBean(DefaultCookieSerializer.class); + assertThat(cookieSerializer).extracting("domainNamePattern").isNotNull(); }); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Session.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Session.java index 367072cb68a8..665984602d4f 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Session.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Session.java @@ -27,6 +27,7 @@ * Session properties. * * @author Andy Wilkinson + * @author Yanming Zhou * @since 2.0.0 */ public class Session { @@ -109,6 +110,8 @@ public static class Cookie { private String domain; + private String domainPattern; + private String path; private String comment; @@ -120,6 +123,8 @@ public static class Cookie { @DurationUnit(ChronoUnit.SECONDS) private Duration maxAge; + private String sameSite; + /** * Return the session cookie name. * @return the session cookie name @@ -140,10 +145,28 @@ public String getDomain() { return this.domain; } + /** + * Cannot set both domain and domainPattern + */ public void setDomain(String domain) { this.domain = domain; } + /** + * Return the case insensitive pattern to extract the domain name. + * @return the pattern to extract the domain + */ + public String getDomainPattern() { + return this.domainPattern; + } + + /** + * Cannot set both domain and domainPattern + */ + public void setDomainPattern(String domainPattern) { + this.domainPattern = domainPattern; + } + /** * Return the path of the session cookie. * @return the session cookie path @@ -205,6 +228,17 @@ public void setMaxAge(Duration maxAge) { this.maxAge = maxAge; } + /** + * Return the value for the {@code SameSite} cookie directive. + */ + public String getSameSite() { + return sameSite; + } + + public void setSameSite(String sameSite) { + this.sameSite = sameSite; + } + } /**