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

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


The following commit(s) were added to refs/heads/master by this push:
     new 5a069b970 KNOX-3148: Make SameSite configurable for pac4j session 
cookies (#1042)
5a069b970 is described below

commit 5a069b97012eadfc42f493b938cc24b3e9da6055
Author: hanicz <[email protected]>
AuthorDate: Mon May 12 10:10:08 2025 +0200

    KNOX-3148: Make SameSite configurable for pac4j session cookies (#1042)
---
 .../pac4j/filter/Pac4jDispatcherFilter.java        |   5 +
 .../gateway/pac4j/session/KnoxSessionStore.java    |  30 ++--
 .../gateway/pac4j/MockHttpServletResponse.java     |  13 +-
 .../knox/gateway/pac4j/Pac4jProviderTest.java      | 173 ++++++++++-----------
 .../pac4j/filter/Pac4jDispatcherFilterTest.java    |  45 +++++-
 .../pac4j/session/KnoxSessionStoreTest.java        |   7 +-
 .../gateway/service/knoxsso/WebSSOResource.java    |  18 +--
 .../apache/knox/gateway/util/SetCookieHeader.java  | 134 ++++++++++++++++
 .../knox/gateway/util/SetCookieHeaderTest.java     | 110 +++++++++++++
 9 files changed, 416 insertions(+), 119 deletions(-)

diff --git 
a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
 
b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
index d0b7521d9..0fc6241f0 100644
--- 
a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
+++ 
b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
@@ -130,6 +130,9 @@ public class Pac4jDispatcherFilter implements Filter, 
SessionInvalidator {
   /* default value is same is KNOXSSO token ttl default */
   private static final String PAC4J_COOKIE_MAX_AGE_DEFAULT = "-1";
 
+  public static final String PAC4J_COOKIE_SAMESITE = "pac4j.cookie.samesite";
+  private static final String PAC4J_COOKIE_SAMESITE_DEFAULT = "Strict";
+
   private static final String PAC4J_CSRF_TOKEN = "pac4jCsrfToken";
   private static boolean SSL_ENABLED = true;
 
@@ -229,6 +232,8 @@ public class Pac4jDispatcherFilter implements Filter, 
SessionInvalidator {
       setSessionStoreConfig(filterConfig, 
PAC4J_SESSION_STORE_EXCLUDE_CUSTOM_ATTRIBUTES, 
PAC4J_SESSION_STORE_EXCLUDE_CUSTOM_ATTRIBUTES_DEFAULT);
       /* add cookie expiry */
       setSessionStoreConfig(filterConfig, PAC4J_COOKIE_MAX_AGE, 
PAC4J_COOKIE_MAX_AGE_DEFAULT);
+      /* add cookie samesite */
+      setSessionStoreConfig(filterConfig, PAC4J_COOKIE_SAMESITE, 
PAC4J_COOKIE_SAMESITE_DEFAULT);
       //decorating client configuration (if needed)
       PAC4J_CLIENT_CONFIGURATION_DECORATOR.decorateClients(clients, 
properties);
     }
diff --git 
a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStore.java
 
b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStore.java
index 94007954d..0ac14ac68 100644
--- 
a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStore.java
+++ 
b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStore.java
@@ -23,6 +23,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter;
 import org.apache.knox.gateway.services.security.CryptoService;
 import org.apache.knox.gateway.services.security.EncryptionResult;
+import org.apache.knox.gateway.util.SetCookieHeader;
 import org.apache.knox.gateway.util.Urls;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -48,6 +49,7 @@ import java.util.Optional;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.GZIPOutputStream;
 
+import static 
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_COOKIE_SAMESITE;
 import static 
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_SESSION_STORE_EXCLUDE_CUSTOM_ATTRIBUTES;
 import static 
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_SESSION_STORE_EXCLUDE_CUSTOM_ATTRIBUTES_DEFAULT;
 import static 
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_SESSION_STORE_EXCLUDE_GROUPS;
@@ -161,18 +163,17 @@ public class KnoxSessionStore<C extends WebContext> 
implements SessionStore<C> {
     @Override
     public void set(WebContext context, String key, Object value) {
         Object profile = value;
-        Cookie cookie;
+        SetCookieHeader setCookieHeader;
 
         if (value == null) {
-            cookie = new Cookie(PAC4J_SESSION_PREFIX + key, null);
+            setCookieHeader = new SetCookieHeader(PAC4J_SESSION_PREFIX + key, 
null);
         } else {
             if (key.contentEquals(Pac4jConstants.USER_PROFILES)) {
                 /* trim the profile object */
                 profile = clearUserProfile(value);
             }
             logger.debug("Save in session: {} = {}", key, profile);
-            cookie = new Cookie(PAC4J_SESSION_PREFIX + key,
-                compressEncryptBase64(profile));
+            setCookieHeader = new SetCookieHeader(PAC4J_SESSION_PREFIX + key, 
compressEncryptBase64(profile));
         }
         try {
             String domain = Urls
@@ -180,12 +181,14 @@ public class KnoxSessionStore<C extends WebContext> 
implements SessionStore<C> {
             if (domain == null) {
                 domain = context.getServerName();
             }
-            cookie.setDomain(domain);
+            setCookieHeader.setDomain(domain);
         } catch (final Exception e) {
             throw new TechnicalException(e);
         }
-        cookie.setHttpOnly(true);
-        cookie.setSecure(ContextHelper.isHttpsOrSecure(context));
+        setCookieHeader.setSecure(true);
+        if(ContextHelper.isHttpsOrSecure(context)) {
+            setCookieHeader.setHttpOnly(true);
+        }
 
         /*
          *  set the correct path for setting pac4j profile cookie.
@@ -198,16 +201,19 @@ public class KnoxSessionStore<C extends WebContext> 
implements SessionStore<C> {
             final String[] parts = ((JEEContext) 
context).getNativeRequest().getRequestURI()
                 .split(
                     "websso"+ Pac4jDispatcherFilter.URL_PATH_SEPARATOR + 
Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER);
-
-            cookie.setPath(parts[0]);
-
+            setCookieHeader.setPath(parts[0]);
         }
 
         /* Set cookie max age */
         if(sessionStoreConfigs != null && 
sessionStoreConfigs.containsKey(PAC4J_COOKIE_MAX_AGE)) {
-            
cookie.setMaxAge(Integer.parseInt(sessionStoreConfigs.get(PAC4J_COOKIE_MAX_AGE)));
+            
setCookieHeader.setMaxAge(Integer.parseInt(sessionStoreConfigs.get(PAC4J_COOKIE_MAX_AGE)));
         }
-        context.addResponseCookie(cookie);
+
+        if(sessionStoreConfigs != null && 
sessionStoreConfigs.containsKey(PAC4J_COOKIE_SAMESITE)) {
+            
setCookieHeader.setSameSite(sessionStoreConfigs.get(PAC4J_COOKIE_SAMESITE));
+        }
+
+        ((JEEContext) context).getNativeResponse().addHeader("Set-Cookie", 
setCookieHeader.toString());
     }
 
     /**
diff --git 
a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/MockHttpServletResponse.java
 
b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/MockHttpServletResponse.java
index 688465d55..2e7dc6ff0 100644
--- 
a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/MockHttpServletResponse.java
+++ 
b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/MockHttpServletResponse.java
@@ -25,15 +25,16 @@ import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponseWrapper;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 public class MockHttpServletResponse extends HttpServletResponseWrapper {
 
-    private List<Cookie> cookies = new ArrayList<>();
+    private final List<Cookie> cookies = new ArrayList<>();
     private int status;
-    private Map<String, String> headers = new HashMap<>();
+    private final Map<String, List<String>> headers = new HashMap<>();
 
     public MockHttpServletResponse() {
         super(setupMockResponse());
@@ -47,15 +48,17 @@ public class MockHttpServletResponse extends 
HttpServletResponseWrapper {
 
     @Override
     public void setHeader(String name, String value) {
-        headers.put(name, value);
+        headers.put(name, new ArrayList<>(Collections.singletonList(value)));
     }
 
     @Override
     public void addHeader(String name, String value) {
-        headers.put(name, value);
+        List<String> values = headers.getOrDefault(name, new ArrayList<>());
+        values.add(value);
+        headers.put(name, values);
     }
 
-    public Map<String, String> getHeaders() {
+    public Map<String, List<String>> getHeaders() {
         return headers;
     }
 
diff --git 
a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/Pac4jProviderTest.java
 
b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/Pac4jProviderTest.java
index de4b7a5c9..c4bc8d817 100644
--- 
a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/Pac4jProviderTest.java
+++ 
b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/Pac4jProviderTest.java
@@ -24,8 +24,8 @@ import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter;
 import org.apache.knox.gateway.pac4j.filter.Pac4jIdentityAdapter;
 import org.apache.knox.gateway.pac4j.session.KnoxSessionStore;
-import org.apache.knox.gateway.services.ServiceType;
 import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.services.ServiceType;
 import org.apache.knox.gateway.services.security.AliasService;
 import org.apache.knox.gateway.services.security.impl.DefaultCryptoService;
 import org.easymock.EasyMock;
@@ -38,15 +38,12 @@ import javax.servlet.FilterConfig;
 import javax.servlet.ServletContext;
 import javax.servlet.http.Cookie;
 import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
+import java.util.Optional;
 import java.util.Properties;
-import java.util.stream.Collectors;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 /**
  * This class simulates a full authentication process using pac4j.
@@ -113,18 +110,21 @@ public class Pac4jProviderTest {
         dispatcher.doFilter(request, response, filterChain);
         // it should be a redirection to the idp topology
         assertEquals(302, response.getStatus());
-        assertEquals(PAC4J_CALLBACK_URL + "?" + 
Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + 
Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS, 
response.getHeaders().get("Location"));
-        // we should have one cookie for the saved requested url
+        assertEquals(PAC4J_CALLBACK_URL + "?" + 
Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + 
Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS, 
response.getHeaders().get("Location").get(0));
+
         List<Cookie> cookies = response.getCookies();
-        assertEquals(3, cookies.size());
-        final Cookie requestedUrlCookie = cookies.stream()
-            .filter(c -> (KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL).equals(c.getName()))
-            .collect(Collectors.toList()).get(0);
-        assertEquals(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL, requestedUrlCookie.getName());
+        assertEquals(1, cookies.size());
+        Optional<String> requestedUrlSetCookie = 
response.getHeaders().get("Set-Cookie").stream()
+            .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL))
+                .findFirst();
+        assertTrue(requestedUrlSetCookie.isPresent());
+
+        assertEquals(1, response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.CSRF_TOKEN)).count());
 
         // step 2: send credentials to the callback url (callback from the 
identity provider)
         request = new MockHttpServletRequest();
-        request.setCookies(new Cookie[]{requestedUrlCookie});
+        request.setCookies(new 
Cookie[]{this.setCookieParser(requestedUrlSetCookie.get())});
         request.setRequestURL(PAC4J_CALLBACK_URL + "?" + 
Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + 
Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + 
Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS);
         request.addParameter(Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER, 
"true");
         request.addParameter(Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER, 
CLIENT_CLASS);
@@ -135,20 +135,20 @@ public class Pac4jProviderTest {
         dispatcher.doFilter(request, response, filterChain);
         // it should be a redirection to the original url
         assertEquals(302, response.getStatus());
-        assertEquals(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + 
HADOOP_SERVICE_URL, response.getHeaders().get("Location"));
-        // we should have 2 cookies among with the user profile
-        cookies = response.getCookies();
-        Map<String, String> mapCookies = new HashMap<>();
-        assertEquals(2, cookies.size());
-        for (final Cookie cookie : cookies) {
-            mapCookies.put(cookie.getName(), cookie.getValue());
-        }
-        assertNotNull(mapCookies.get(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES));
-        assertNull(mapCookies.get(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL));
+        assertEquals(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + 
HADOOP_SERVICE_URL, response.getHeaders().get("Location").get(0));
+
+        Optional<String> userProfilesSetCookie = 
response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES))
+                .findFirst();
+        requestedUrlSetCookie = 
response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL + "=null;"))
+                .findFirst();
+        assertTrue(userProfilesSetCookie.isPresent());
+        assertTrue(requestedUrlSetCookie.isPresent());
 
         // step 3: turn pac4j identity into KnoxSSO identity
         request = new MockHttpServletRequest();
-        request.setCookies(cookies.toArray(new Cookie[0]));
+        request.setCookies(new 
Cookie[]{this.setCookieParser(requestedUrlSetCookie.get()), 
this.setCookieParser(userProfilesSetCookie.get())});
         request.setRequestURL(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + 
HADOOP_SERVICE_URL);
         request.setServerName(LOCALHOST);
         response = new MockHttpServletResponse();
@@ -156,14 +156,9 @@ public class Pac4jProviderTest {
         dispatcher.doFilter(request, response, filterChain);
         assertEquals(0, response.getStatus());
         adapter.doFilter(request, response, filterChain);
-        cookies = response.getCookies();
-        assertEquals(3, cookies.size());
-        final Cookie userProfileCookie = cookies.stream()
-            .filter(c -> (KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES).equals(c.getName()))
-            .collect(Collectors.toList()).get(0);
-        // the user profile has been cleaned
-        assertEquals(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES, userProfileCookie.getName());
-        assertNull(userProfileCookie.getValue());
+
+        assertEquals(1, response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES + "=null;")).count());
         assertEquals(USERNAME, adapter.getTestIdentifier());
     }
 
@@ -218,18 +213,21 @@ public class Pac4jProviderTest {
         dispatcher.doFilter(request, response, filterChain);
         // it should be a redirection to the idp topology
         assertEquals(302, response.getStatus());
-        assertEquals(PAC4J_CALLBACK_URL + "?" + 
Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + 
Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS, 
response.getHeaders().get("Location"));
-        // we should have one cookie for the saved requested url
+        assertEquals(PAC4J_CALLBACK_URL + "?" + 
Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + 
Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS, 
response.getHeaders().get("Location").get(0));
+
         List<Cookie> cookies = response.getCookies();
-        assertEquals(3, cookies.size());
-        final Cookie requestedUrlCookie = cookies.stream()
-            .filter(c -> (KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL).equals(c.getName()))
-            .collect(Collectors.toList()).get(0);
-        assertEquals(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL, requestedUrlCookie.getName());
+        assertEquals(1, cookies.size());
+        Optional<String> requestedUrlSetCookie = 
response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL))
+                .findFirst();
+        assertTrue(requestedUrlSetCookie.isPresent());
+
+        assertEquals(1, response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.CSRF_TOKEN)).count());
 
         // step 2: send credentials to the callback url (callback from the 
identity provider)
         request = new MockHttpServletRequest();
-        request.setCookies(new Cookie[]{requestedUrlCookie});
+        request.setCookies(new 
Cookie[]{this.setCookieParser(requestedUrlSetCookie.get())});
         request.setRequestURL(PAC4J_CALLBACK_URL + "?" + 
Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + 
Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + 
Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS);
         request.addParameter(Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER, 
"true");
         request.addParameter(Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER, 
CLIENT_CLASS);
@@ -240,20 +238,20 @@ public class Pac4jProviderTest {
         dispatcher.doFilter(request, response, filterChain);
         // it should be a redirection to the original url
         assertEquals(302, response.getStatus());
-        assertEquals(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + 
HADOOP_SERVICE_URL, response.getHeaders().get("Location"));
-        // we should have 2 cookies among with the user profile
-        cookies = response.getCookies();
-        Map<String, String> mapCookies = new HashMap<>();
-        assertEquals(2, cookies.size());
-        for (final Cookie cookie : cookies) {
-            mapCookies.put(cookie.getName(), cookie.getValue());
-        }
-        assertNotNull(mapCookies.get(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES));
-        assertNull(mapCookies.get(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL));
+        assertEquals(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + 
HADOOP_SERVICE_URL, response.getHeaders().get("Location").get(0));
+
+        Optional<String> userProfilesSetCookie = 
response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES))
+                .findFirst();
+        requestedUrlSetCookie = 
response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL + "=null;"))
+                .findFirst();
+        assertTrue(userProfilesSetCookie.isPresent());
+        assertTrue(requestedUrlSetCookie.isPresent());
 
         // step 3: turn pac4j identity into KnoxSSO identity
         request = new MockHttpServletRequest();
-        request.setCookies(cookies.toArray(new Cookie[0]));
+        request.setCookies(new 
Cookie[]{this.setCookieParser(requestedUrlSetCookie.get()), 
this.setCookieParser(userProfilesSetCookie.get())});
         request.setRequestURL(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + 
HADOOP_SERVICE_URL);
         request.setServerName(LOCALHOST);
         response = new MockHttpServletResponse();
@@ -261,16 +259,12 @@ public class Pac4jProviderTest {
         dispatcher.doFilter(request, response, filterChain);
         assertEquals(0, response.getStatus());
         adapter.doFilter(request, response, filterChain);
-        cookies = response.getCookies();
-        assertEquals(3, cookies.size());
-        final Cookie userProfileCookie = cookies.stream()
-            .filter(c -> (KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES).equals(c.getName()))
-            .collect(Collectors.toList()).get(0);
-        // the user profile has been cleaned
-        assertEquals(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES, userProfileCookie.getName());
-        assertNull(userProfileCookie.getValue());
+
+        assertEquals(1, response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES + "=null;")).count());
         assertEquals(USERNAME, adapter.getTestIdentifier());
     }
+
     @Test
     public void testInvalidIdAttribute() throws Exception {
         final AliasService aliasService = 
EasyMock.createNiceMock(AliasService.class);
@@ -322,18 +316,21 @@ public class Pac4jProviderTest {
         dispatcher.doFilter(request, response, filterChain);
         // it should be a redirection to the idp topology
         assertEquals(302, response.getStatus());
-        assertEquals(PAC4J_CALLBACK_URL + "?" + 
Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + 
Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS, 
response.getHeaders().get("Location"));
-        // we should have one cookie for the saved requested url
+        assertEquals(PAC4J_CALLBACK_URL + "?" + 
Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + 
Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS, 
response.getHeaders().get("Location").get(0));
+
         List<Cookie> cookies = response.getCookies();
-        assertEquals(3, cookies.size());
-        final Cookie requestedUrlCookie = cookies.stream()
-            .filter(c -> (KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL).equals(c.getName()))
-            .collect(Collectors.toList()).get(0);
-        assertEquals(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL, requestedUrlCookie.getName());
+        assertEquals(1, cookies.size());
+        Optional<String> requestedUrlSetCookie = 
response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL))
+                .findFirst();
+        assertTrue(requestedUrlSetCookie.isPresent());
+
+        assertEquals(1, response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.CSRF_TOKEN)).count());
 
         // step 2: send credentials to the callback url (callback from the 
identity provider)
         request = new MockHttpServletRequest();
-        request.setCookies(new Cookie[]{requestedUrlCookie});
+        request.setCookies(new 
Cookie[]{this.setCookieParser(requestedUrlSetCookie.get())});
         request.setRequestURL(PAC4J_CALLBACK_URL + "?" + 
Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + 
Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + 
Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS);
         request.addParameter(Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER, 
"true");
         request.addParameter(Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER, 
CLIENT_CLASS);
@@ -344,20 +341,20 @@ public class Pac4jProviderTest {
         dispatcher.doFilter(request, response, filterChain);
         // it should be a redirection to the original url
         assertEquals(302, response.getStatus());
-        assertEquals(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + 
HADOOP_SERVICE_URL, response.getHeaders().get("Location"));
-        // we should have 2 cookies among with the user profile
-        cookies = response.getCookies();
-        Map<String, String> mapCookies = new HashMap<>();
-        assertEquals(2, cookies.size());
-        for (final Cookie cookie : cookies) {
-            mapCookies.put(cookie.getName(), cookie.getValue());
-        }
-        assertNotNull(mapCookies.get(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES));
-        assertNull(mapCookies.get(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL));
+        assertEquals(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + 
HADOOP_SERVICE_URL, response.getHeaders().get("Location").get(0));
+
+        Optional<String> userProfilesSetCookie = 
response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES))
+                .findFirst();
+        requestedUrlSetCookie = 
response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.REQUESTED_URL + "=null;"))
+                .findFirst();
+        assertTrue(userProfilesSetCookie.isPresent());
+        assertTrue(requestedUrlSetCookie.isPresent());
 
         // step 3: turn pac4j identity into KnoxSSO identity
         request = new MockHttpServletRequest();
-        request.setCookies(cookies.toArray(new Cookie[0]));
+        request.setCookies(new 
Cookie[]{this.setCookieParser(requestedUrlSetCookie.get()), 
this.setCookieParser(userProfilesSetCookie.get())});
         request.setRequestURL(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + 
HADOOP_SERVICE_URL);
         request.setServerName(LOCALHOST);
         response = new MockHttpServletResponse();
@@ -365,14 +362,9 @@ public class Pac4jProviderTest {
         dispatcher.doFilter(request, response, filterChain);
         assertEquals(0, response.getStatus());
         adapter.doFilter(request, response, filterChain);
-        cookies = response.getCookies();
-        assertEquals(3, cookies.size());
-        final Cookie userProfileCookie = cookies.stream()
-            .filter(c -> (KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES).equals(c.getName()))
-            .collect(Collectors.toList()).get(0);
-        // the user profile has been cleaned
-        assertEquals(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES, userProfileCookie.getName());
-        assertNull(userProfileCookie.getValue());
+
+        assertEquals(1, response.getHeaders().get("Set-Cookie").stream()
+                .filter(c -> 
c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + 
Pac4jConstants.USER_PROFILES + "=null;")).count());
         assertEquals(USERNAME, adapter.getTestIdentifier());
     }
 
@@ -409,6 +401,13 @@ public class Pac4jProviderTest {
         EasyMock.verify(aliasService);
     }
 
+    private Cookie setCookieParser(String setCookie) {
+        String[] cookieParts = setCookie.split(";");
+        String[] nameValuePairs = cookieParts[0].trim().split("=", 2);
+
+        return new Cookie(nameValuePairs[0].trim(), nameValuePairs[1].trim());
+    }
+
     private class FilterConfigStub implements FilterConfig {
         private ServletContext context;
         private Properties properties = new Properties();
diff --git 
a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilterTest.java
 
b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilterTest.java
index c93d969be..b965cf827 100644
--- 
a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilterTest.java
+++ 
b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilterTest.java
@@ -104,14 +104,14 @@ public class Pac4jDispatcherFilterTest {
         
EasyMock.expect(mocks.context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(mocks.gatewayConfig).anyTimes();
     }
 
-    private void verifyCookiemaxAge(FilterConfig filterConfig, String 
expectedCookieMaxAge) throws Exception {
+    private void verifyCookieConfig(FilterConfig filterConfig, String key, 
String expected) throws Exception {
         Pac4jDispatcherFilter filter = new Pac4jDispatcherFilter();
         filter.init(filterConfig);
 
         java.lang.reflect.Field configField = 
filter.getClass().getDeclaredField("sessionStoreConfigs");
         configField.setAccessible(true);
         Map<String, String> sessionStoreConfigs = (Map<String, String>) 
configField.get(filter);
-        Assert.assertEquals(expectedCookieMaxAge, 
sessionStoreConfigs.get(Pac4jDispatcherFilter.PAC4J_COOKIE_MAX_AGE));
+        Assert.assertEquals(expected, sessionStoreConfigs.get(key));
     }
 
 
@@ -129,7 +129,7 @@ public class Pac4jDispatcherFilterTest {
 
         EasyMock.replay(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
 
-        verifyCookiemaxAge(mocks.filterConfig, expectedCookieMaxAge);
+        verifyCookieConfig(mocks.filterConfig, 
Pac4jDispatcherFilter.PAC4J_COOKIE_MAX_AGE,  expectedCookieMaxAge);
 
         // Verify all mock interactions
         EasyMock.verify(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
@@ -152,7 +152,44 @@ public class Pac4jDispatcherFilterTest {
 
         EasyMock.replay(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
 
-        verifyCookiemaxAge(mocks.filterConfig, expectedCookieMaxAge);
+        verifyCookieConfig(mocks.filterConfig, 
Pac4jDispatcherFilter.PAC4J_COOKIE_MAX_AGE,  expectedCookieMaxAge);
+
+        // Verify all mock interactions
+        EasyMock.verify(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
+    }
+
+    @Test
+    public void testDefaultCookieSameSite() throws Exception {
+        final String expectedSameSite = "Strict";
+        List<String> params = new ArrayList<>();
+        params.add(Pac4jDispatcherFilter.PAC4J_CALLBACK_URL);
+        params.add("clientName");
+        params.add(SAML_KEYSTORE_PATH);
+        params.add(SAML_IDENTITY_PROVIDER_METADATA_PATH);
+
+        TestMocks mocks = createMocks();
+        setupCommonExpectations(mocks, Collections.EMPTY_LIST);
+
+        EasyMock.replay(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
+
+        verifyCookieConfig(mocks.filterConfig, 
Pac4jDispatcherFilter.PAC4J_COOKIE_SAMESITE,  expectedSameSite);
+
+        // Verify all mock interactions
+        EasyMock.verify(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
+    }
+
+    @Test
+    public void testCustomCookieSameSite() throws Exception {
+        final String expectedSameSite = "None";
+        List<String> additionalParams = new ArrayList<>();
+        additionalParams.add(Pac4jDispatcherFilter.PAC4J_COOKIE_SAMESITE);
+        TestMocks mocks = createMocks();
+        setupCommonExpectations(mocks, additionalParams);
+        
EasyMock.expect(mocks.filterConfig.getInitParameter(Pac4jDispatcherFilter.PAC4J_COOKIE_SAMESITE)).andReturn(expectedSameSite).anyTimes();
+
+        EasyMock.replay(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
+
+        verifyCookieConfig(mocks.filterConfig, 
Pac4jDispatcherFilter.PAC4J_COOKIE_SAMESITE,  expectedSameSite);
 
         // Verify all mock interactions
         EasyMock.verify(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
diff --git 
a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStoreTest.java
 
b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStoreTest.java
index 586a46a88..32cb5e405 100644
--- 
a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStoreTest.java
+++ 
b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStoreTest.java
@@ -24,11 +24,12 @@ import org.easymock.Capture;
 import org.easymock.EasyMock;
 import org.junit.Assert;
 import org.junit.Test;
-import org.pac4j.core.context.WebContext;
+import org.pac4j.core.context.JEEContext;
 import org.pac4j.core.profile.CommonProfile;
 import org.pac4j.core.util.Pac4jConstants;
 import org.pac4j.saml.profile.SAML2Profile;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -68,9 +69,11 @@ public class KnoxSessionStoreTest {
     final Map<String, String> sessionStoreConfigs = new HashMap();
 
     final Capture<org.pac4j.core.context.Cookie> captureCookieValue = 
EasyMock.newCapture();
-    final WebContext mockContext = EasyMock.createNiceMock(WebContext.class);
+    final JEEContext mockContext = EasyMock.createNiceMock(JEEContext.class);
+    final HttpServletResponse response = 
EasyMock.createNiceMock(HttpServletResponse.class);
     
EasyMock.expect(mockContext.getFullRequestURL()).andReturn("https://local.com/gateway/knoxsso/";).anyTimes();
     mockContext.addResponseCookie(EasyMock.capture(captureCookieValue));
+    
EasyMock.expect(mockContext.getNativeResponse()).andReturn(response).anyTimes();
 
     EasyMock.replay(mockContext);
 
diff --git 
a/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
 
b/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
index 641e15a7d..6856120a2 100644
--- 
a/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
+++ 
b/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
@@ -65,6 +65,7 @@ import 
org.apache.knox.gateway.services.security.token.impl.JWT;
 import org.apache.knox.gateway.session.control.ConcurrentSessionVerifier;
 import org.apache.knox.gateway.util.CookieUtils;
 import org.apache.knox.gateway.util.RegExUtils;
+import org.apache.knox.gateway.util.SetCookieHeader;
 import org.apache.knox.gateway.util.Tokens;
 import org.apache.knox.gateway.util.Urls;
 import org.apache.knox.gateway.util.WhitelistUtils;
@@ -409,23 +410,22 @@ public class WebSSOResource {
      * SameSite param. Change this back to Cookie impl. after
      * SameSite header is supported by javax.servlet.http.Cookie.
      */
-    final StringBuilder setCookie = new StringBuilder(50);
     try {
-      setCookie.append(cookieName).append('=').append(token.toString());
-      setCookie.append("; Path=/");
+      SetCookieHeader setCookieHeader = new SetCookieHeader(cookieName, 
token.toString());
+      setCookieHeader.setPath("/");
       final String domain = Urls.getDomainName(original, domainSuffix);
       if (domain != null) {
-        setCookie.append("; Domain=").append(domain);
+        setCookieHeader.setDomain(domain);
       }
-      setCookie.append("; HttpOnly");
+      setCookieHeader.setHttpOnly(true);
       if (secureOnly) {
-        setCookie.append("; Secure");
+        setCookieHeader.setSecure(true);
       }
       if (maxAge != -1) {
-        setCookie.append("; Max-Age=").append(maxAge);
+        setCookieHeader.setMaxAge(maxAge);
       }
-      setCookie.append("; SameSite=").append(this.sameSiteValue);
-      response.setHeader("Set-Cookie", setCookie.toString());
+      setCookieHeader.setSameSite(sameSiteValue);
+      response.setHeader("Set-Cookie", setCookieHeader.toString());
       LOGGER.addedJWTCookie(logSafeToken);
     } catch (Exception e) {
       LOGGER.unableAddCookieToResponse(e.getMessage(),
diff --git 
a/gateway-util-common/src/main/java/org/apache/knox/gateway/util/SetCookieHeader.java
 
b/gateway-util-common/src/main/java/org/apache/knox/gateway/util/SetCookieHeader.java
new file mode 100644
index 000000000..2a56d9048
--- /dev/null
+++ 
b/gateway-util-common/src/main/java/org/apache/knox/gateway/util/SetCookieHeader.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SetCookieHeader {
+    private final String name;
+    private final String value;
+    private final Map<String, String> attributes = new HashMap<>();
+
+    private String path;
+    private String domain;
+    private int maxAge = -1;
+    private boolean httpOnly;
+    private boolean secure;
+    private String sameSite;
+
+    public SetCookieHeader(String name, String value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public int getMaxAge() {
+        return maxAge;
+    }
+
+    public boolean isHttpOnly() {
+        return httpOnly;
+    }
+
+    public boolean isSecure() {
+        return secure;
+    }
+
+    public String getSameSite() {
+        return sameSite;
+    }
+
+    public String getAttribute(String name) {
+        return attributes.get(name);
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+
+    public void setMaxAge(int maxAge) {
+        this.maxAge = maxAge;
+    }
+
+    public void setHttpOnly(boolean httpOnly) {
+        this.httpOnly = httpOnly;
+    }
+
+    public void setSecure(boolean secure) {
+        this.secure = secure;
+    }
+
+    public void setSameSite(String sameSite) {
+        this.sameSite = sameSite;
+    }
+
+    public void setAttribute(String name, String value) {
+        attributes.put(name, value);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(name);
+        sb.append('=').append(value);
+
+        if(path != null) {
+            sb.append("; Path=").append(path);
+        }
+        if(domain != null) {
+            sb.append("; Domain=").append(domain);
+        }
+        if(maxAge != -1) {
+            sb.append("; Max-Age=").append(maxAge);
+        }
+        if(httpOnly) {
+            sb.append("; HttpOnly");
+        }
+        if(secure) {
+            sb.append("; Secure");
+        }
+        if(sameSite != null) {
+            sb.append("; SameSite=").append(sameSite);
+        }
+
+        for(Map.Entry<String, String> entry : attributes.entrySet()) {
+            sb.append("; 
").append(entry.getKey()).append('=').append(entry.getValue());
+        }
+
+        return sb.toString();
+    }
+}
diff --git 
a/gateway-util-common/src/test/java/org/apache/knox/gateway/util/SetCookieHeaderTest.java
 
b/gateway-util-common/src/test/java/org/apache/knox/gateway/util/SetCookieHeaderTest.java
new file mode 100644
index 000000000..58db606b4
--- /dev/null
+++ 
b/gateway-util-common/src/test/java/org/apache/knox/gateway/util/SetCookieHeaderTest.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class SetCookieHeaderTest {
+
+    @Test
+    public void testBasicSetCookie() {
+        SetCookieHeader setCookieHeader = new SetCookieHeader("name", "value");
+        assertEquals("name=value", setCookieHeader.toString());
+    }
+
+    @Test
+    public void testEmptyValueSetCookie() {
+        SetCookieHeader setCookieHeader = new SetCookieHeader("name", null);
+        assertEquals("name=null", setCookieHeader.toString());
+    }
+
+    @Test
+    public void testSetCookieWithPath() {
+        SetCookieHeader setCookieHeader = new SetCookieHeader("name", "value");
+        setCookieHeader.setPath("/");
+        assertEquals("name=value; Path=/", setCookieHeader.toString());
+    }
+
+    @Test
+    public void testSetCookieWithDomain() {
+        SetCookieHeader setCookieHeader = new SetCookieHeader("name", "value");
+        setCookieHeader.setDomain("example.com");
+        assertEquals("name=value; Domain=example.com", 
setCookieHeader.toString());
+    }
+
+    @Test
+    public void testSetCookieWithMaxAge() {
+        SetCookieHeader setCookieHeader = new SetCookieHeader("name", "value");
+        setCookieHeader.setMaxAge(231);
+        assertEquals("name=value; Max-Age=231", setCookieHeader.toString());
+    }
+
+    @Test
+    public void testSetCookieWithHttpOnly() {
+        SetCookieHeader setCookieHeader = new SetCookieHeader("name", "value");
+        setCookieHeader.setHttpOnly(true);
+        assertEquals("name=value; HttpOnly", setCookieHeader.toString());
+    }
+
+    @Test
+    public void testSetCookieWithSecure() {
+        SetCookieHeader setCookieHeader = new SetCookieHeader("name", "value");
+        setCookieHeader.setSecure(true);
+        assertEquals("name=value; Secure", setCookieHeader.toString());
+    }
+
+    @Test
+    public void testSetCookieWithSameSite() {
+        SetCookieHeader setCookieHeader = new SetCookieHeader("name", "value");
+        setCookieHeader.setSameSite("Strict");
+        assertEquals("name=value; SameSite=Strict", 
setCookieHeader.toString());
+    }
+
+    @Test
+    public void testSetCookieWithAdditionalAttribute() {
+        SetCookieHeader setCookieHeader = new SetCookieHeader("name", "value");
+        setCookieHeader.setAttribute("Attribute", "value");
+        assertEquals("name=value; Attribute=value", 
setCookieHeader.toString());
+    }
+
+    @Test
+    public void testSetCookieWithAll() {
+        SetCookieHeader setCookieHeader = new SetCookieHeader("name", "value");
+        setCookieHeader.setDomain("example.com");
+        setCookieHeader.setMaxAge(231);
+        setCookieHeader.setHttpOnly(true);
+        setCookieHeader.setSecure(true);
+        setCookieHeader.setPath("/path");
+        setCookieHeader.setSameSite("Lax");
+        setCookieHeader.setAttribute("Attribute", "attrValue");
+
+        String setCookieHeaderString = setCookieHeader.toString();
+
+        assertTrue("Name/value pair is incorrect", 
setCookieHeaderString.contains("name=value"));
+        assertTrue("Domain is incorrect", setCookieHeaderString.contains("; 
Domain=example.com"));
+        assertTrue("Max-Age is incorrect", setCookieHeaderString.contains("; 
Max-Age=231"));
+        assertTrue("HttpOnly is incorrect", setCookieHeaderString.contains("; 
HttpOnly"));
+        assertTrue("Secure is incorrect", setCookieHeaderString.contains("; 
Secure"));
+        assertTrue("Path is incorrect", setCookieHeaderString.contains("; 
Path=/path"));
+        assertTrue("SameSite is incorrect", setCookieHeaderString.contains("; 
SameSite=Lax"));
+        assertTrue("Additional attribute is incorrect", 
setCookieHeaderString.contains("; Attribute=attrValue"));
+    }
+}
\ No newline at end of file


Reply via email to