diff --git a/framework/src/play/data/validation/ValidationPlugin.java b/framework/src/play/data/validation/ValidationPlugin.java index 3fa6bb486d..53e95d49d7 100644 --- a/framework/src/play/data/validation/ValidationPlugin.java +++ b/framework/src/play/data/validation/ValidationPlugin.java @@ -159,7 +159,7 @@ static void save() { if (Validation.errors().isEmpty()) { // Only send "delete cookie" header when the cookie was present in the request if(Http.Request.current().cookies.containsKey(Scope.COOKIE_PREFIX + "_ERRORS") || !Scope.SESSION_SEND_ONLY_IF_CHANGED) { - Http.Response.current().setCookie(Scope.COOKIE_PREFIX + "_ERRORS", "", null, "/", 0, Scope.COOKIE_SECURE, Scope.SESSION_HTTPONLY, Scope.SESSION_SAMESITE); + Http.Response.current().setCookie(Scope.COOKIE_PREFIX + "_ERRORS", "", null, "/", 0, Scope.COOKIE_SECURE, Scope.SESSION_HTTPONLY, null); } return; } @@ -179,7 +179,7 @@ static void save() { } } String errorsData = URLEncoder.encode(errors.toString(), "utf-8"); - Http.Response.current().setCookie(Scope.COOKIE_PREFIX + "_ERRORS", errorsData, null, "/", null, Scope.COOKIE_SECURE, Scope.SESSION_HTTPONLY, Scope.SESSION_SAMESITE); + Http.Response.current().setCookie(Scope.COOKIE_PREFIX + "_ERRORS", errorsData, null, "/", null, Scope.COOKIE_SECURE, Scope.SESSION_HTTPONLY, null); } catch (Exception e) { throw new UnexpectedException("Errors serializationProblem", e); } diff --git a/framework/src/play/mvc/Http.java b/framework/src/play/mvc/Http.java index c1fc627ce1..85e70378ac 100644 --- a/framework/src/play/mvc/Http.java +++ b/framework/src/play/mvc/Http.java @@ -5,7 +5,6 @@ import java.io.InputStream; import java.io.Serializable; import java.lang.reflect.Method; -import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -166,7 +165,7 @@ public static class Cookie implements Serializable { /** * See https://owasp.org/www-community/SameSite */ - public String sameSite; + public SAMESITE sameSite; } /** @@ -711,7 +710,7 @@ public void setContentTypeIfNotSet(String contentType) { * @param value * Cookie value */ - public void setCookie(String name, String value, String sameSite) { + public void setCookie(String name, String value, SAMESITE sameSite) { setCookie(name, value, null, "/", null, false, sameSite); } @@ -747,15 +746,15 @@ public void removeCookie(String name, String path) { * @param duration * the cookie duration (Ex: 3d) */ - public void setCookie(String name, String value, String duration, String sameSite) { + public void setCookie(String name, String value, String duration, SAMESITE sameSite) { setCookie(name, value, null, "/", Time.parseDuration(duration), false, sameSite); } - public void setCookie(String name, String value, String domain, String path, Integer maxAge, boolean secure, String sameSite) { + public void setCookie(String name, String value, String domain, String path, Integer maxAge, boolean secure, SAMESITE sameSite) { setCookie(name, value, domain, path, maxAge, secure, false, sameSite); } - public void setCookie(String name, String value, String domain, String path, Integer maxAge, boolean secure, boolean httpOnly, String sameSite) { + public void setCookie(String name, String value, String domain, String path, Integer maxAge, boolean secure, boolean httpOnly, SAMESITE sameSite) { path = Play.ctxPath + path; if (cookies.containsKey(name) && cookies.get(name).path.equals(path) && ((cookies.get(name).domain == null && domain == null) || (cookies.get(name).domain.equals(domain)))) { @@ -1023,4 +1022,20 @@ public WebSocketFrame(byte[] data) { public static class WebSocketClose extends WebSocketEvent { } + + public enum SAMESITE { + STRICT("Strict"), + LAX("Lax"), + NONE("None"); + + private final String value; + + SAMESITE(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } } diff --git a/framework/src/play/mvc/Scope.java b/framework/src/play/mvc/Scope.java index bbd5c5b596..d2636577ae 100644 --- a/framework/src/play/mvc/Scope.java +++ b/framework/src/play/mvc/Scope.java @@ -32,7 +32,8 @@ public class Scope { .equals("true"); public static boolean SESSION_SEND_ONLY_IF_CHANGED = Play.configuration .getProperty("application.session.sendOnlyIfChanged", "false").toLowerCase().equals("true"); - public static final String SESSION_SAMESITE = Play.configuration.getProperty("application.session.sameSite"); + public static final Http.SAMESITE SESSION_SAMESITE = Play.configuration.getProperty("application.session.cookie.sameSite") != null ? + Http.SAMESITE.valueOf(Play.configuration.getProperty("application.session.cookie.sameSite").toUpperCase()) : null; public static SessionStore sessionStore = createSessionStore(); diff --git a/framework/src/play/server/PlayHandler.java b/framework/src/play/server/PlayHandler.java index 1a956faef1..cc738979f2 100644 --- a/framework/src/play/server/PlayHandler.java +++ b/framework/src/play/server/PlayHandler.java @@ -375,8 +375,8 @@ protected static void addToResponse(Response response, HttpResponse nettyRespons } c.setHttpOnly(cookie.httpOnly); String encodedCookie = ServerCookieEncoder.STRICT.encode(c); - if(cookie.sameSite != null) { - encodedCookie += "; SameSite=" + cookie.sameSite; + if (cookie.sameSite != null) { + encodedCookie += "; SameSite=" + cookie.sameSite.getValue(); } nettyResponse.headers().add(SET_COOKIE, encodedCookie); } @@ -796,8 +796,8 @@ public static void serve500(Exception e, ChannelHandlerContext ctx, HttpRequest } c.setHttpOnly(cookie.httpOnly); String encodedCookie = ServerCookieEncoder.STRICT.encode(c); - if(cookie.sameSite != null) { - encodedCookie += "; SameSite=" + cookie.sameSite; + if (cookie.sameSite != null) { + encodedCookie += "; SameSite=" + cookie.sameSite.getValue(); } nettyResponse.headers().add(SET_COOKIE, encodedCookie); } diff --git a/framework/test-src/play/mvc/HttpResponseTest.java b/framework/test-src/play/mvc/HttpResponseTest.java index 8a76ed96c5..e2ac257b38 100644 --- a/framework/test-src/play/mvc/HttpResponseTest.java +++ b/framework/test-src/play/mvc/HttpResponseTest.java @@ -27,12 +27,12 @@ public void verifySameSiteCookie() { Http.Cookie.defaultDomain = ".abc.com"; response = new Http.Response(); - response.setCookie("testCookie", "testValue", "lax"); - assertThat(response.cookies.get("testCookie").sameSite).isEqualTo("lax"); + response.setCookie("testCookie", "testValue", Http.SAMESITE.LAX); + assertThat(response.cookies.get("testCookie").sameSite).isEqualTo(Http.SAMESITE.LAX); Http.Cookie.defaultDomain = ".abc.com"; response = new Http.Response(); - response.setCookie("testCookie", "testValue", "strict"); - assertThat(response.cookies.get("testCookie").sameSite).isEqualTo("strict"); + response.setCookie("testCookie", "testValue", Http.SAMESITE.STRICT); + assertThat(response.cookies.get("testCookie").sameSite).isEqualTo(Http.SAMESITE.STRICT); } } diff --git a/resources/application-skel/conf/application.conf b/resources/application-skel/conf/application.conf index 012026f187..8f175519b3 100644 --- a/resources/application-skel/conf/application.conf +++ b/resources/application-skel/conf/application.conf @@ -48,7 +48,7 @@ date.format=yyyy-MM-dd # application.session.cookie=PLAY # application.session.maxAge=1h # application.session.secure=false -# application.session.sameSite=lax +# application.session.cookie.sameSite=lax # Session/Cookie sharing between subdomain # ~~~~~~~~~~~~~~~~~~~~~~