Proposal for same site cookie value

Signed-off-by: Paulo Lopes <pmlopes@gmail.com>
This commit is contained in:
Paulo Lopes
2019-11-19 13:35:18 +01:00
parent 6b13bdc3d5
commit 9b107243e1
3 changed files with 97 additions and 1 deletions

View File

@@ -118,6 +118,16 @@ public interface Cookie {
@Fluent
Cookie setHttpOnly(boolean httpOnly);
/**
* Sets the same site of this cookie.
*
* @param policy The policy should be one of {@code Lax}, {@code Strict} or {@code None}
* @return a reference to this, so the API can be used fluently
*/
@Fluent
Cookie setSameSite(String policy);
/**
* Encode the cookie to a string. This is what is used in the Set-Cookie header
*

View File

@@ -63,6 +63,8 @@ public class CookieImpl implements ServerCookie {
private final io.netty.handler.codec.http.cookie.Cookie nettyCookie;
private boolean changed;
private boolean fromUserAgent;
// extension features
private String sameSite;
public CookieImpl(String name, String value) {
this.nettyCookie = new DefaultCookie(name, value);
@@ -136,9 +138,43 @@ public class CookieImpl implements ServerCookie {
return this;
}
@Override
public Cookie setSameSite(final String sameSite) {
if (sameSite != null) {
// validate
int length = sameSite.length();
switch (length) {
case 3:
if (!sameSite.equalsIgnoreCase("LAX")) {
throw new IllegalArgumentException("sameSite contains an invalid value: " + sameSite);
}
break;
case 4:
if (!sameSite.equalsIgnoreCase("NONE")) {
throw new IllegalArgumentException("sameSite contains an invalid value: " + sameSite);
}
break;
case 6:
if (!sameSite.equalsIgnoreCase("STRICT")) {
throw new IllegalArgumentException("sameSite contains an invalid value: " + sameSite);
}
break;
default:
throw new IllegalArgumentException("sameSite contains an invalid value: " + sameSite);
}
}
this.sameSite = sameSite;
this.changed = true;
return this;
}
@Override
public String encode() {
return ServerCookieEncoder.STRICT.encode(nettyCookie);
if (sameSite != null) {
return ServerCookieEncoder.STRICT.encode(nettyCookie) + "; SameSite=" + sameSite;
} else {
return ServerCookieEncoder.STRICT.encode(nettyCookie);
}
}
public boolean isChanged() {

View File

@@ -5403,6 +5403,56 @@ public abstract class HttpTest extends HttpTestBase {
assertEquals("foo=bar; Path=/somepath; Domain=foo.com; Secure; HTTPOnly", cookie.encode());
}
@Test
public void testCookieSameSiteFieldEncoding() throws Exception {
Cookie cookie = Cookie.cookie("foo", "bar").setSameSite("lax");
assertEquals("foo", cookie.getName());
assertEquals("bar", cookie.getValue());
assertEquals("foo=bar; SameSite=lax", cookie.encode());
cookie.setSecure(true);
assertEquals("foo=bar; Secure; SameSite=lax", cookie.encode());
cookie.setHttpOnly(true);
assertEquals("foo=bar; Secure; HTTPOnly; SameSite=lax", cookie.encode());
}
@Test
public void testCookieSameSiteFieldValidation() throws Exception {
Cookie cookie = Cookie.cookie("foo", "bar");
try {
cookie.setSameSite("Lax");
// OK
cookie.setSameSite("Strict");
// OK
cookie.setSameSite("NoNe");
// OK
cookie.setSameSite(null);
// OK
} catch (RuntimeException e) {
fail();
}
try {
cookie.setSameSite("XYZ");
fail();
} catch (RuntimeException e) {
// OK
}
try {
cookie.setSameSite("DURP");
fail();
} catch (RuntimeException e) {
// OK
}
try {
cookie.setSameSite("some random stuff");
fail();
} catch (RuntimeException e) {
// OK
}
}
@Test
public void testRemoveCookies() throws Exception {
testCookies("foo=bar", req -> {