Skip to content

Commit

Permalink
Fix BZ 68348 - add support for the cookie attribute partitioned
Browse files Browse the repository at this point in the history
  • Loading branch information
markt-asf committed Jan 4, 2024
1 parent be7dc9c commit 9ee98eb
Show file tree
Hide file tree
Showing 14 changed files with 176 additions and 5 deletions.
27 changes: 27 additions & 0 deletions java/org/apache/catalina/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,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.
Expand Down
7 changes: 5 additions & 2 deletions java/org/apache/catalina/authenticator/AuthenticatorBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -1078,13 +1078,16 @@ protected void register(Request request, HttpServletResponse response, Principal
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
Expand Down
9 changes: 9 additions & 0 deletions java/org/apache/catalina/authenticator/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
9 changes: 6 additions & 3 deletions java/org/apache/catalina/authenticator/SingleSignOn.java
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,17 @@ public void invoke(Request request, Response response) throws IOException, Servl
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ public static Cookie createSessionCookie(Context context, String sessionId, bool
cookie.setHttpOnly(true);
}

cookie.setAttribute(Constants.COOKIE_PARTITIONED_ATTR,
Boolean.toString(context.getUsePartitioned()));

cookie.setPath(SessionConfig.getSessionCookiePath(context));

// Other attributes
Expand Down
16 changes: 16 additions & 0 deletions java/org/apache/catalina/core/StandardContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,8 @@ public StandardContext() {
*/
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
Expand Down Expand Up @@ -1546,6 +1548,20 @@ public void setUseHttpOnly(boolean useHttpOnly) {
}


@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.
*
Expand Down
5 changes: 5 additions & 0 deletions java/org/apache/catalina/startup/FailedContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,11 @@ public void setSessionCookieName(String sessionCookieName) { /* NO-OP */ }
@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
Expand Down
7 changes: 7 additions & 0 deletions java/org/apache/tomcat/util/descriptor/web/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
34 changes: 34 additions & 0 deletions java/org/apache/tomcat/util/http/CookieProcessorBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,45 @@ public abstract class CookieProcessorBase implements CookieProcessor {

private SameSiteCookies sameSiteCookies = SameSiteCookies.UNSET;

private boolean partitioned = false;


public SameSiteCookies getSameSiteCookies() {
return sameSiteCookies;
}

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;
}
}
13 changes: 13 additions & 0 deletions java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,18 @@ public String generateHeader(jakarta.servlet.http.Cookie cookie, HttpServletRequ
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()) {
Expand All @@ -187,6 +199,7 @@ public String generateHeader(jakarta.servlet.http.Cookie cookie, HttpServletRequ
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: {
Expand Down
10 changes: 10 additions & 0 deletions test/org/apache/tomcat/unittest/TesterContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,16 @@ 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,36 @@ public void testSameSiteCookies() {
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);
Expand Down
4 changes: 4 additions & 0 deletions webapps/docs/changelog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,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">
Expand Down
7 changes: 7 additions & 0 deletions webapps/docs/config/context.xml
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,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
Expand Down

0 comments on commit 9ee98eb

Please sign in to comment.