This is an automated email from the ASF dual-hosted git repository.

fpapon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shiro.git


The following commit(s) were added to refs/heads/master by this push:
     new 3a5d881  Add SameSite option to cookies
     new 6183c5f  Merge pull request #67 from boris-petrov/same-site-cookies
3a5d881 is described below

commit 3a5d88197c4b72d7f61074dd15f87234969110b2
Author: Boris Petrov <[email protected]>
AuthorDate: Mon Jun 19 17:39:43 2017 +0300

    Add SameSite option to cookies
---
 .../java/org/apache/shiro/web/servlet/Cookie.java  | 10 ++++++
 .../org/apache/shiro/web/servlet/SimpleCookie.java | 37 +++++++++++++++++++---
 .../mgt/DefaultWebSessionManagerTest.groovy        |  1 +
 .../shiro/web/mgt/CookieRememberMeManagerTest.java |  1 +
 .../apache/shiro/web/servlet/SimpleCookieTest.java |  6 +++-
 5 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/web/src/main/java/org/apache/shiro/web/servlet/Cookie.java 
b/web/src/main/java/org/apache/shiro/web/servlet/Cookie.java
index 065b51d..94b18a0 100644
--- a/web/src/main/java/org/apache/shiro/web/servlet/Cookie.java
+++ b/web/src/main/java/org/apache/shiro/web/servlet/Cookie.java
@@ -47,6 +47,12 @@ public interface Cookie {
      */
     public static final String ROOT_PATH = "/";
 
+    public enum SameSiteOptions {
+        NONE,
+        LAX,
+        STRICT,
+    }
+
     String getName();
 
     void setName(String name);
@@ -83,6 +89,10 @@ public interface Cookie {
 
     boolean isHttpOnly();
 
+    void setSameSite(SameSiteOptions sameSite);
+
+    SameSiteOptions getSameSite();
+
     void saveTo(HttpServletRequest request, HttpServletResponse response);
 
     void removeFrom(HttpServletRequest request, HttpServletResponse response);
diff --git a/web/src/main/java/org/apache/shiro/web/servlet/SimpleCookie.java 
b/web/src/main/java/org/apache/shiro/web/servlet/SimpleCookie.java
index c8d1420..7022586 100644
--- a/web/src/main/java/org/apache/shiro/web/servlet/SimpleCookie.java
+++ b/web/src/main/java/org/apache/shiro/web/servlet/SimpleCookie.java
@@ -67,6 +67,7 @@ public class SimpleCookie implements Cookie {
     protected static final String COMMENT_ATTRIBUTE_NAME = "Comment";
     protected static final String SECURE_ATTRIBUTE_NAME = "Secure";
     protected static final String HTTP_ONLY_ATTRIBUTE_NAME = "HttpOnly";
+    protected static final String SAME_SITE_ATTRIBUTE_NAME = "SameSite";
 
     private static final transient Logger log = 
LoggerFactory.getLogger(SimpleCookie.class);
 
@@ -79,11 +80,13 @@ public class SimpleCookie implements Cookie {
     private int version;
     private boolean secure;
     private boolean httpOnly;
+    private SameSiteOptions sameSite;
 
     public SimpleCookie() {
         this.maxAge = DEFAULT_MAX_AGE;
         this.version = DEFAULT_VERSION;
         this.httpOnly = true; //most of the cookies ever used by Shiro should 
be as secure as possible.
+        this.sameSite = SameSiteOptions.LAX;
     }
 
     public SimpleCookie(String name) {
@@ -101,6 +104,7 @@ public class SimpleCookie implements Cookie {
         this.version = Math.max(DEFAULT_VERSION, cookie.getVersion());
         this.secure = cookie.isSecure();
         this.httpOnly = cookie.isHttpOnly();
+        this.sameSite = cookie.getSameSite();
     }
 
     public String getName() {
@@ -178,6 +182,14 @@ public class SimpleCookie implements Cookie {
         this.httpOnly = httpOnly;
     }
 
+    public SameSiteOptions getSameSite() {
+        return sameSite;
+    }
+
+    public void setSameSite(SameSiteOptions sameSite) {
+        this.sameSite = sameSite;
+    }
+
     /**
      * Returns the Cookie's calculated path setting.  If the {@link 
javax.servlet.http.Cookie#getPath() path} is {@code null}, then the
      * {@code request}'s {@link 
javax.servlet.http.HttpServletRequest#getContextPath() context path}
@@ -211,15 +223,16 @@ public class SimpleCookie implements Cookie {
         int version = getVersion();
         boolean secure = isSecure();
         boolean httpOnly = isHttpOnly();
+        SameSiteOptions sameSite = getSameSite();
 
-        addCookieHeader(response, name, value, comment, domain, path, maxAge, 
version, secure, httpOnly);
+        addCookieHeader(response, name, value, comment, domain, path, maxAge, 
version, secure, httpOnly, sameSite);
     }
 
     private void addCookieHeader(HttpServletResponse response, String name, 
String value, String comment,
                                  String domain, String path, int maxAge, int 
version,
-                                 boolean secure, boolean httpOnly) {
+                                 boolean secure, boolean httpOnly, 
SameSiteOptions sameSite) {
 
-        String headerValue = buildHeaderValue(name, value, comment, domain, 
path, maxAge, version, secure, httpOnly);
+        String headerValue = buildHeaderValue(name, value, comment, domain, 
path, maxAge, version, secure, httpOnly, sameSite);
         response.addHeader(COOKIE_HEADER_NAME, headerValue);
 
         if (log.isDebugEnabled()) {
@@ -238,6 +251,13 @@ public class SimpleCookie implements Cookie {
                                       String domain, String path, int maxAge, 
int version,
                                       boolean secure, boolean httpOnly) {
 
+        return buildHeaderValue(name, value, comment, domain, path, maxAge, 
version, secure, httpOnly, getSameSite());
+    }
+
+    protected String buildHeaderValue(String name, String value, String 
comment,
+                                      String domain, String path, int maxAge, 
int version,
+                                      boolean secure, boolean httpOnly, 
SameSiteOptions sameSite) {
+
         if (!StringUtils.hasText(name)) {
             throw new IllegalStateException("Cookie name cannot be 
null/empty.");
         }
@@ -255,6 +275,7 @@ public class SimpleCookie implements Cookie {
         appendVersion(sb, version);
         appendSecure(sb, secure);
         appendHttpOnly(sb, httpOnly);
+        appendSameSite(sb, sameSite);
 
         return sb.toString();
 
@@ -328,6 +349,13 @@ public class SimpleCookie implements Cookie {
         }
     }
 
+    private void appendSameSite(StringBuilder sb, SameSiteOptions sameSite) {
+        if (sameSite != null) {
+            sb.append(ATTRIBUTE_DELIMITER);
+            
sb.append(SAME_SITE_ATTRIBUTE_NAME).append(NAME_VALUE_DELIMITER).append(sameSite.toString().toLowerCase(Locale.ENGLISH));
+        }
+    }
+
     /**
      * Check whether the given {@code cookiePath} matches the {@code 
requestPath}
      *
@@ -369,8 +397,9 @@ public class SimpleCookie implements Cookie {
         int version = getVersion();
         boolean secure = isSecure();
         boolean httpOnly = false; //no need to add the extra text, plus the 
value 'deleteMe' is not sensitive at all
+        SameSiteOptions sameSite = null;
 
-        addCookieHeader(response, name, value, comment, domain, path, maxAge, 
version, secure, httpOnly);
+        addCookieHeader(response, name, value, comment, domain, path, maxAge, 
version, secure, httpOnly, sameSite);
 
         log.trace("Removed '{}' cookie by setting maxAge=0", name);
     }
diff --git 
a/web/src/test/groovy/org/apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy
 
b/web/src/test/groovy/org/apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy
index 526636c..841569f 100644
--- 
a/web/src/test/groovy/org/apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy
+++ 
b/web/src/test/groovy/org/apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy
@@ -78,6 +78,7 @@ public class DefaultWebSessionManagerTest {
         expect(cookie.getVersion()).andReturn(SimpleCookie.DEFAULT_VERSION);
         expect(cookie.isSecure()).andReturn(true);
         expect(cookie.isHttpOnly()).andReturn(true);
+        expect(cookie.getSameSite()).andReturn(Cookie.SameSiteOptions.LAX);
 
         replay(cookie);
 
diff --git 
a/web/src/test/java/org/apache/shiro/web/mgt/CookieRememberMeManagerTest.java 
b/web/src/test/java/org/apache/shiro/web/mgt/CookieRememberMeManagerTest.java
index fba8f55..81d9c5a 100644
--- 
a/web/src/test/java/org/apache/shiro/web/mgt/CookieRememberMeManagerTest.java
+++ 
b/web/src/test/java/org/apache/shiro/web/mgt/CookieRememberMeManagerTest.java
@@ -71,6 +71,7 @@ public class CookieRememberMeManagerTest {
         expect(cookie.getVersion()).andReturn(SimpleCookie.DEFAULT_VERSION);
         expect(cookie.isSecure()).andReturn(false);
         expect(cookie.isHttpOnly()).andReturn(true);
+        
expect(cookie.getSameSite()).andReturn(org.apache.shiro.web.servlet.Cookie.SameSiteOptions.LAX);
 
         UsernamePasswordToken token = new UsernamePasswordToken("user", 
"secret");
         token.setRememberMe(true);
diff --git 
a/web/src/test/java/org/apache/shiro/web/servlet/SimpleCookieTest.java 
b/web/src/test/java/org/apache/shiro/web/servlet/SimpleCookieTest.java
index 3a272aa..4d26f86 100644
--- a/web/src/test/java/org/apache/shiro/web/servlet/SimpleCookieTest.java
+++ b/web/src/test/java/org/apache/shiro/web/servlet/SimpleCookieTest.java
@@ -25,6 +25,7 @@ import org.junit.Test;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.util.Locale;
 
 import static org.easymock.EasyMock.*;
 
@@ -59,7 +60,7 @@ public class SimpleCookieTest extends TestCase {
         String path = "/somepath";
 
         String headerValue = this.cookie.buildHeaderValue(name, value, null, 
null, path,
-                0, SimpleCookie.DEFAULT_VERSION, false, false);
+                0, SimpleCookie.DEFAULT_VERSION, false, false, null);
 
         String expectedStart = new StringBuilder()
                 
.append(name).append(SimpleCookie.NAME_VALUE_DELIMITER).append(value)
@@ -89,6 +90,9 @@ public class SimpleCookieTest extends TestCase {
                 
.append(SimpleCookie.PATH_ATTRIBUTE_NAME).append(SimpleCookie.NAME_VALUE_DELIMITER).append(Cookie.ROOT_PATH)
                 .append(SimpleCookie.ATTRIBUTE_DELIMITER)
                 .append(SimpleCookie.HTTP_ONLY_ATTRIBUTE_NAME)
+                .append(SimpleCookie.ATTRIBUTE_DELIMITER)
+                
.append(SimpleCookie.SAME_SITE_ATTRIBUTE_NAME).append(SimpleCookie.NAME_VALUE_DELIMITER)
+                    
.append(Cookie.SameSiteOptions.LAX.toString().toLowerCase(Locale.ENGLISH))
                 .toString();
 
         expect(mockRequest.getContextPath()).andReturn(contextPath);

Reply via email to