Skip to content

CXF-9072: Support the SameSite attribute in NewCookieHeaderProvider - #3616

Merged
reta merged 4 commits into
apache:mainfrom
sharanggupta:CXF-9072-samesite-cookie
Oct 22, 2026
Merged

reta merged 4 commits into
apache:mainfrom
sharanggupta:CXF-9072-samesite-cookie

Conversation

@sharanggupta

Copy link
Copy Markdown
Contributor

https://issues.apache.org/jira/browse/CXF-9072

NewCookieHeaderProvider.fromString treats every attribute it doesn't recognize as the cookie's name=value pair, so foo=bar;SameSite=Lax is parsed as a cookie named SameSite with value Lax. toString drops SameSite, so a NewCookie built with sameSite(...) loses the attribute in the Set-Cookie header and in Response.getCookies().

Changes:

  • The first name=value pair is the cookie. Later unrecognized attributes are ignored, as in RFC 6265, section 5.2. Empty segments are skipped.
  • SameSite is parsed case-insensitively into NewCookie.SameSite. An unrecognized value is ignored.
  • toString writes SameSite=Strict|Lax|None.

Tests: new NewCookieHeaderProviderTest cases cover parsing, case-insensitivity, unknown SameSite values, unknown attributes, toString, empty segments, and a round trip. The SameSite and unknown-attribute cases fail without the change. mvn -pl rt/frontend/jaxrs -am test with NewCookieHeaderProviderTest, CookieHeaderProviderTest and ResponseImplTest passes, including checkstyle and PMD.

The JIRA issue is assigned to @reta. I'm happy to close this if you already have a fix in progress.

fromString treated any attribute it did not recognize, such as SameSite,
as the cookie's name=value pair, so "foo=bar;SameSite=Lax" was parsed as a
cookie named "SameSite". The cookie's own name=value pair now comes first
and later unrecognized attributes are ignored. SameSite is parsed
case-insensitively into NewCookie.SameSite, an unrecognized SameSite value
is ignored, and toString writes the attribute so it survives a round trip
through Response.getCookies().
With the first name=value pair now taken as the cookie, an empty leading segment such as " ; foo=bar" would have become a cookie with an empty name.
@reta

reta commented Oct 22, 2026

Copy link
Copy Markdown
Member

The JIRA issue is assigned to @reta. I'm happy to close this if you already have a fix in progress.

All good, thanks @sharanggupta !

@coheigea coheigea left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment in the code says “the cookie’s own name=value pair comes first”, but the code doesn’t actually do that. Any pair whose name matches a known attribute is still treated as that attribute, even when it’s the first segment. Under RFC 6265 §5.2, the first segment is always the cookie’s name=value, whatever the name is. Two cases show the difference:

A cookie named after an attribute (path=abc; Path=/, or version=2): this is still parsed as attributes and then rejected with IllegalArgumentException. That was already true before this PR.
A cookie named SameSite (SameSite=Lax with nothing else): it used to parse as a cookie called SameSite. With this PR it throws. This is a small new regression, though a real cookie with that name is unlikely.

The simplest fix is to take the first non-empty segment as name=value unconditionally, then run the attribute switch only on the segments after it. That makes the code match its comment and RFC 6265, and it closes both cases above.

Per RFC 6265 section 5.2 the first segment is the cookie's name=value
pair whatever its name, and only the segments after it are attributes.
A cookie named after an attribute (path=abc; Path=/) or named SameSite
was parsed as attributes and rejected as malformed. A first segment
without '=' is still rejected.
@sharanggupta

Copy link
Copy Markdown
Contributor Author

Thanks, you're right. Done in f616912: the first non-empty segment is now always the cookie's name=value pair, and only the segments after it go through the attribute switch. path=abc; Path=/ and SameSite=Lax now parse as cookies named path and SameSite. A first segment without = (Secure; foo=bar) is still rejected as malformed. There are tests for all three; they fail on the previous commit.

@coheigea
coheigea requested a review from reta October 22, 2026 05:20
Replace the switch with StringUtils.capitalize on the lower-cased enum
name. Lower-case with Locale.ROOT: under a Turkish default locale,
STRICT would otherwise become "Strıct" with a dotless i.
@reta
reta merged commit 663cf11 into apache:main Oct 22, 2026
5 checks passed
reta pushed a commit that referenced this pull request Oct 22, 2026
…3616)

* CXF-9072: Support the SameSite attribute in NewCookieHeaderProvider

fromString treated any attribute it did not recognize, such as SameSite,
as the cookie's name=value pair, so "foo=bar;SameSite=Lax" was parsed as a
cookie named "SameSite". The cookie's own name=value pair now comes first
and later unrecognized attributes are ignored. SameSite is parsed
case-insensitively into NewCookie.SameSite, an unrecognized SameSite value
is ignored, and toString writes the attribute so it survives a round trip
through Response.getCookies().

* CXF-9072: Skip empty Set-Cookie segments

With the first name=value pair now taken as the cookie, an empty leading segment such as " ; foo=bar" would have become a cookie with an empty name.

* CXF-9072: Always take the first Set-Cookie segment as the cookie

Per RFC 6265 section 5.2 the first segment is the cookie's name=value
pair whatever its name, and only the segments after it are attributes.
A cookie named after an attribute (path=abc; Path=/) or named SameSite
was parsed as attributes and rejected as malformed. A first segment
without '=' is still rejected.

* CXF-9072: Write the SameSite value with StringUtils.capitalize

Replace the switch with StringUtils.capitalize on the lower-cased enum
name. Lower-case with Locale.ROOT: under a Turkish default locale,
STRICT would otherwise become "Strıct" with a dotless i.

(cherry picked from commit 663cf11)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants