This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/10.1.x by this push: new f1203ae0b5 Fix BZ 68348 - add support for the cookie attribute partitioned f1203ae0b5 is described below commit f1203ae0b5a136fc4ce5a8749a59542af7787716 Author: Mark Thomas <ma...@apache.org> AuthorDate: Thu Jan 4 12:52:17 2024 +0000 Fix BZ 68348 - add support for the cookie attribute partitioned https://bz.apache.org/bugzilla/show_bug.cgi?id=68348 --- java/org/apache/catalina/Context.java | 27 +++++++++++++++++ .../catalina/authenticator/AuthenticatorBase.java | 7 +++-- .../apache/catalina/authenticator/Constants.java | 9 ++++++ .../catalina/authenticator/SingleSignOn.java | 9 ++++-- .../core/ApplicationSessionCookieConfig.java | 3 ++ java/org/apache/catalina/core/StandardContext.java | 16 ++++++++++ .../org/apache/catalina/startup/FailedContext.java | 5 ++++ .../tomcat/util/descriptor/web/Constants.java | 7 +++++ .../tomcat/util/http/CookieProcessorBase.java | 34 ++++++++++++++++++++++ .../tomcat/util/http/Rfc6265CookieProcessor.java | 13 +++++++++ test/org/apache/tomcat/unittest/TesterContext.java | 10 +++++++ .../util/http/TestCookieProcessorGeneration.java | 30 +++++++++++++++++++ webapps/docs/changelog.xml | 4 +++ webapps/docs/config/context.xml | 7 +++++ 14 files changed, 176 insertions(+), 5 deletions(-) diff --git a/java/org/apache/catalina/Context.java b/java/org/apache/catalina/Context.java index f9ebfe3340..fb50454dcc 100644 --- a/java/org/apache/catalina/Context.java +++ b/java/org/apache/catalina/Context.java @@ -264,6 +264,33 @@ public interface Context extends Container, ContextBind { void setUseHttpOnly(boolean useHttpOnly); + /** + * Should the {@code Partitioned} attribute be added to session cookies created for this web application. + * <p> + * The name of the attribute used to indicate a partitioned cookie as part of + * <a href="https://developers.google.com/privacy-sandbox/3pcd#partitioned">CHIPS</a> is not defined by an RFC and + * may change in a non-backwards compatible way once equivalent functionality is included in an RFC. + * + * @return {@code true} if the {@code Partitioned} attribute should be added to session cookies created for this web + * application, otherwise {@code false} + */ + boolean getUsePartitioned(); + + + /** + * Configure whether the {@code Partitioned} attribute should be added to session cookies created for this web + * application. + * <p> + * The name of the attribute used to indicate a partitioned cookie as part of + * <a href="https://developers.google.com/privacy-sandbox/3pcd#partitioned">CHIPS</a> is not defined by an RFC and + * may change in a non-backwards compatible way once equivalent functionality is included in an RFC. + * + * @param usePartitioned {@code true} if the {@code Partitioned} attribute should be added to session cookies + * created for this web application, otherwise {@code false} + */ + void setUsePartitioned(boolean usePartitioned); + + /** * Gets the domain to use for session cookies. Overrides any setting that * may be specified by the application. diff --git a/java/org/apache/catalina/authenticator/AuthenticatorBase.java b/java/org/apache/catalina/authenticator/AuthenticatorBase.java index 352f984c79..9a558d9c05 100644 --- a/java/org/apache/catalina/authenticator/AuthenticatorBase.java +++ b/java/org/apache/catalina/authenticator/AuthenticatorBase.java @@ -1078,13 +1078,16 @@ public abstract class AuthenticatorBase extends ValveBase implements Authenticat cookie.setDomain(ssoDomain); } - // Configure httpOnly on SSO cookie using same rules as session - // cookies + // Configure httpOnly on SSO cookie using same rules as session cookies if (request.getServletContext().getSessionCookieConfig().isHttpOnly() || request.getContext().getUseHttpOnly()) { cookie.setHttpOnly(true); } + // Configure Partitioned on SSO cookie using same rules as session cookies + cookie.setAttribute(Constants.COOKIE_PARTITIONED_ATTR, + Boolean.toString(request.getContext().getUsePartitioned())); + response.addCookie(cookie); // Register this principal with our SSO valve diff --git a/java/org/apache/catalina/authenticator/Constants.java b/java/org/apache/catalina/authenticator/Constants.java index 6b0778da79..5485782d5c 100644 --- a/java/org/apache/catalina/authenticator/Constants.java +++ b/java/org/apache/catalina/authenticator/Constants.java @@ -37,6 +37,15 @@ public class Constants { // Cookie name for single sign on support public static final String SINGLE_SIGN_ON_COOKIE = "JSESSIONIDSSO"; + /** + * The name of the attribute used to indicate a partitioned cookie as part of + * <a href="https://developers.google.com/privacy-sandbox/3pcd#partitioned">CHIPS</a>. This cookie attribute is not + * defined by an RFC and may change in a non-backwards compatible way once equivalent functionality is included in + * an RFC. + */ + public static final String COOKIE_PARTITIONED_ATTR = + org.apache.tomcat.util.descriptor.web.Constants.COOKIE_PARTITIONED_ATTR; + // --------------------------------------------------------- Request Notes diff --git a/java/org/apache/catalina/authenticator/SingleSignOn.java b/java/org/apache/catalina/authenticator/SingleSignOn.java index 4d302ab40b..c8f9d53c4a 100644 --- a/java/org/apache/catalina/authenticator/SingleSignOn.java +++ b/java/org/apache/catalina/authenticator/SingleSignOn.java @@ -273,14 +273,17 @@ public class SingleSignOn extends ValveBase { if (domain != null) { cookie.setDomain(domain); } - // This is going to trigger a Set-Cookie header. While the value is - // not security sensitive, ensure that expectations for secure and - // httpOnly are met + /* + * This is going to trigger a Set-Cookie header. While the value is not security sensitive, ensure that + * expectations for secure, httpOnly and Partitioned are met. + */ cookie.setSecure(request.isSecure()); if (request.getServletContext().getSessionCookieConfig().isHttpOnly() || request.getContext().getUseHttpOnly()) { cookie.setHttpOnly(true); } + cookie.setAttribute(Constants.COOKIE_PARTITIONED_ATTR, + Boolean.toString(request.getContext().getUsePartitioned())); response.addCookie(cookie); } diff --git a/java/org/apache/catalina/core/ApplicationSessionCookieConfig.java b/java/org/apache/catalina/core/ApplicationSessionCookieConfig.java index c9f6bda066..97a001b95f 100644 --- a/java/org/apache/catalina/core/ApplicationSessionCookieConfig.java +++ b/java/org/apache/catalina/core/ApplicationSessionCookieConfig.java @@ -221,6 +221,9 @@ public class ApplicationSessionCookieConfig implements SessionCookieConfig { cookie.setHttpOnly(true); } + cookie.setAttribute(Constants.COOKIE_PARTITIONED_ATTR, + Boolean.toString(context.getUsePartitioned())); + cookie.setPath(SessionConfig.getSessionCookiePath(context)); // Other attributes diff --git a/java/org/apache/catalina/core/StandardContext.java b/java/org/apache/catalina/core/StandardContext.java index e4a701872b..1eb87b2f36 100644 --- a/java/org/apache/catalina/core/StandardContext.java +++ b/java/org/apache/catalina/core/StandardContext.java @@ -638,6 +638,8 @@ public class StandardContext extends ContainerBase implements Context, Notificat */ private boolean useHttpOnly = true; + private boolean usePartitioned = false; + /** * The domain to use for session cookies. <code>null</code> indicates that the domain is controlled by the @@ -1568,6 +1570,20 @@ public class StandardContext extends ContainerBase implements Context, Notificat } + @Override + public boolean getUsePartitioned() { + return usePartitioned; + } + + + @Override + public void setUsePartitioned(boolean usePartitioned) { + boolean oldUsePartitioned = this.usePartitioned; + this.usePartitioned = usePartitioned; + support.firePropertyChange("usePartitioned", oldUsePartitioned, this.usePartitioned); + } + + /** * Gets the domain to use for session cookies. Overrides any setting that may be specified by the application. * diff --git a/java/org/apache/catalina/startup/FailedContext.java b/java/org/apache/catalina/startup/FailedContext.java index e352ce28c7..7bbfdfcfb0 100644 --- a/java/org/apache/catalina/startup/FailedContext.java +++ b/java/org/apache/catalina/startup/FailedContext.java @@ -345,6 +345,11 @@ public class FailedContext extends LifecycleMBeanBase implements Context { @Override public void setUseHttpOnly(boolean useHttpOnly) { /* NO-OP */ } + @Override + public boolean getUsePartitioned() { return false; } + @Override + public void setUsePartitioned(boolean usePartitioned) { /* NO-OP */ } + @Override public String getSessionCookieDomain() { return null; } @Override diff --git a/java/org/apache/tomcat/util/descriptor/web/Constants.java b/java/org/apache/tomcat/util/descriptor/web/Constants.java index 7b6228c638..fabf7b4baf 100644 --- a/java/org/apache/tomcat/util/descriptor/web/Constants.java +++ b/java/org/apache/tomcat/util/descriptor/web/Constants.java @@ -31,4 +31,11 @@ public class Constants { public static final String COOKIE_SECURE_ATTR = "Secure"; public static final String COOKIE_HTTP_ONLY_ATTR = "HttpOnly"; public static final String COOKIE_SAME_SITE_ATTR = "SameSite"; + /** + * The name of the attribute used to indicate a partitioned cookie as part of + * <a href="https://developers.google.com/privacy-sandbox/3pcd#partitioned">CHIPS</a>. This cookie attribute is not + * defined by an RFC and may change in a non-backwards compatible way once equivalent functionality is included in + * an RFC. + */ + public static final String COOKIE_PARTITIONED_ATTR = "Partitioned"; } diff --git a/java/org/apache/tomcat/util/http/CookieProcessorBase.java b/java/org/apache/tomcat/util/http/CookieProcessorBase.java index 00c852cc75..5815ca4cd4 100644 --- a/java/org/apache/tomcat/util/http/CookieProcessorBase.java +++ b/java/org/apache/tomcat/util/http/CookieProcessorBase.java @@ -40,6 +40,9 @@ public abstract class CookieProcessorBase implements CookieProcessor { private SameSiteCookies sameSiteCookies = SameSiteCookies.UNSET; + private boolean partitioned = false; + + public SameSiteCookies getSameSiteCookies() { return sameSiteCookies; } @@ -47,4 +50,35 @@ public abstract class CookieProcessorBase implements CookieProcessor { public void setSameSiteCookies(String sameSiteCookies) { this.sameSiteCookies = SameSiteCookies.fromString(sameSiteCookies); } + + + /** + * Should the {@code Partitioned} attribute be added by default to cookies created for this web application. + * <p> + * The name of the attribute used to indicate a partitioned cookie as part of + * <a href="https://developers.google.com/privacy-sandbox/3pcd#partitioned">CHIPS</a> is not defined by an RFC and + * may change in a non-backwards compatible way once equivalent functionality is included in an RFC. + * + * @return {@code true} if the {@code Partitioned} attribute should be added by default to cookies created for this + * web application, otherwise {@code false} + */ + public boolean getPartitioned() { + return partitioned; + } + + + /** + * Configure whether the {@code Partitioned} attribute should be added by default to cookies created for this web + * application. + * <p> + * The name of the attribute used to indicate a partitioned cookie as part of + * <a href="https://developers.google.com/privacy-sandbox/3pcd#partitioned">CHIPS</a> is not defined by an RFC and + * may change in a non-backwards compatible way once equivalent functionality is included in an RFC. + * + * @param partitioned {@code true} if the {@code Partitioned} attribute should be added by default to cookies + * created for this web application, otherwise {@code false} + */ + public void setPartitioned(boolean partitioned) { + this.partitioned = partitioned; + } } diff --git a/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java b/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java index fc4e5cbe8a..d41fa281f7 100644 --- a/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java +++ b/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java @@ -177,6 +177,18 @@ public class Rfc6265CookieProcessor extends CookieProcessorBase { header.append(cookieSameSite); } + String cookiePartitioned = cookie.getAttribute(Constants.COOKIE_PARTITIONED_ATTR); + if (cookiePartitioned == null) { + if (getPartitioned()) { + header.append("; Partitioned"); + } + } else { + if (Boolean.parseBoolean(cookiePartitioned)) { + header.append("; Partitioned"); + } + } + + // Add the remaining attributes for (Map.Entry<String,String> entry : cookie.getAttributes().entrySet()) { switch (entry.getKey()) { @@ -187,6 +199,7 @@ public class Rfc6265CookieProcessor extends CookieProcessorBase { case Constants.COOKIE_SECURE_ATTR: case Constants.COOKIE_HTTP_ONLY_ATTR: case Constants.COOKIE_SAME_SITE_ATTR: + case Constants.COOKIE_PARTITIONED_ATTR: // Handled above so NO-OP break; default: { diff --git a/test/org/apache/tomcat/unittest/TesterContext.java b/test/org/apache/tomcat/unittest/TesterContext.java index b0c624b951..1b980556cd 100644 --- a/test/org/apache/tomcat/unittest/TesterContext.java +++ b/test/org/apache/tomcat/unittest/TesterContext.java @@ -415,6 +415,16 @@ public class TesterContext implements Context { // NO-OP } + @Override + public boolean getUsePartitioned() { + return false; + } + + @Override + public void setUsePartitioned(boolean usePartitioned) { + // NO-OP + } + @Override public String getSessionCookieDomain() { return null; diff --git a/test/org/apache/tomcat/util/http/TestCookieProcessorGeneration.java b/test/org/apache/tomcat/util/http/TestCookieProcessorGeneration.java index b74a851a16..43ac4d0ffd 100644 --- a/test/org/apache/tomcat/util/http/TestCookieProcessorGeneration.java +++ b/test/org/apache/tomcat/util/http/TestCookieProcessorGeneration.java @@ -209,6 +209,36 @@ public class TestCookieProcessorGeneration { Assert.assertEquals("foo=bar; Secure; HttpOnly; SameSite=Strict", rfc6265.generateHeader(cookie, null)); } + + @Test + public void testPartitionedCookies() { + Rfc6265CookieProcessor rfc6265 = new Rfc6265CookieProcessor(); + + Cookie cookie = new Cookie("foo", "bar"); + + Assert.assertEquals("foo=bar", rfc6265.generateHeader(cookie, null)); + + rfc6265.setPartitioned(false); + + Assert.assertEquals("foo=bar", rfc6265.generateHeader(cookie, null)); + + rfc6265.setPartitioned(true); + + Assert.assertEquals("foo=bar; Partitioned", rfc6265.generateHeader(cookie, null)); + + cookie.setSecure(true); + cookie.setHttpOnly(true); + + rfc6265.setPartitioned(false); + + Assert.assertEquals("foo=bar; Secure; HttpOnly", rfc6265.generateHeader(cookie, null)); + + rfc6265.setPartitioned(true); + + Assert.assertEquals("foo=bar; Secure; HttpOnly; Partitioned", rfc6265.generateHeader(cookie, null)); + } + + private void doTest(Cookie cookie, String expectedRfc6265) { CookieProcessor rfc6265 = new Rfc6265CookieProcessor(); doTest(cookie, rfc6265, expectedRfc6265); diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 558e4bd850..a5d1ee50bc 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -139,6 +139,10 @@ used in the request line, if any, to make the check case insensitive since host names are case insensitive. (markt) </fix> + <add> + <bug>68348</bug>: Add support for the partitioned attribute for cookies + including session cookies. (markt) + </add> </changelog> </subsection> <subsection name="Web Applications"> diff --git a/webapps/docs/config/context.xml b/webapps/docs/config/context.xml index e804c8c240..c233df716f 100644 --- a/webapps/docs/config/context.xml +++ b/webapps/docs/config/context.xml @@ -654,6 +654,13 @@ <code>true</code>.</p> </attribute> + <attribute name="usePartitioned" required="false"> + <p>Should the Partitioned flag be set on session cookies? Defaults to <code>false</code>.</p> + <p>Note: The name of the attribute used to indicate a partitioned cookie as part of + <a href="https://developers.google.com/privacy-sandbox/3pcd#partitioned">CHIPS</a> is not defined by an RFC and + may change in a non-backwards compatible way once equivalent functionality is included in an RFC.</p> + </attribute> + <attribute name="useRelativeRedirects" required="false"> <p>Controls whether HTTP 1.1 and later location headers generated by a call to --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org