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 79f0deb93 KNOX-3254 - Allow control the Secure flag in pac4j session
cookies (#1148)
79f0deb93 is described below
commit 79f0deb935d45eb8d8302ce0eed1ad08aa00a5c8
Author: Sandor Molnar <[email protected]>
AuthorDate: Fri Feb 20 12:32:39 2026 +0100
KNOX-3254 - Allow control the Secure flag in pac4j session cookies (#1148)
---
.../pac4j/filter/Pac4jDispatcherFilter.java | 6 +++
.../gateway/pac4j/session/KnoxSessionStore.java | 5 +-
.../pac4j/session/KnoxSessionStoreTest.java | 60 ++++++++++++++++++++++
3 files changed, 70 insertions(+), 1 deletion(-)
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 51727733d..1f90c1568 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
@@ -113,6 +113,8 @@ public class Pac4jDispatcherFilter implements Filter,
SessionInvalidator {
/* A comma seperated list of attributes that needed to be excluded */
public static final String PAC4J_SESSION_STORE_EXCLUDE_CUSTOM_ATTRIBUTES =
"pac4j.session.store.exclude.custom.attributes";
+ public static final String PAC4J_SESSION_STORE_SECURE_COOKIE =
"pac4j.session.store.secure.cookie";
+
public static final String
PAC4J_SESSION_STORE_EXCLUDE_CUSTOM_ATTRIBUTES_DEFAULT = "";
public static final String PAC4J_SESSION_STORE_EXCLUDE_GROUPS_DEFAULT =
"true";
@@ -236,6 +238,10 @@ public class Pac4jDispatcherFilter implements Filter,
SessionInvalidator {
if(StringUtils.isNotBlank(filterConfig.getInitParameter(PAC4J_COOKIE_SAMESITE)))
{
setSessionStoreConfig(filterConfig, PAC4J_COOKIE_SAMESITE, null);
}
+ /* control the Secure flag */
+ if
(StringUtils.isNotBlank(filterConfig.getInitParameter(PAC4J_SESSION_STORE_SECURE_COOKIE)))
{
+ setSessionStoreConfig(filterConfig, PAC4J_SESSION_STORE_SECURE_COOKIE,
null);
+ }
//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 4b9c365b3..700ceaf65 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
@@ -58,6 +58,7 @@ import static
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_S
import static
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_SESSION_STORE_EXCLUDE_ROLES;
import static
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_SESSION_STORE_EXCLUDE_ROLES_DEFAULT;
import static
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_COOKIE_MAX_AGE;
+import static
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_SESSION_STORE_SECURE_COOKIE;
/**
* Specific session store where data are saved into cookies (and not in
memory).
@@ -184,7 +185,9 @@ public class KnoxSessionStore implements SessionStore {
} catch (final Exception e) {
throw new TechnicalException(e);
}
- setCookieHeader.setSecure(true);
+ final String secureCookieSettings =
sessionStoreConfigs.get(PAC4J_SESSION_STORE_SECURE_COOKIE);
+ final boolean secureFlag = secureCookieSettings == null ?
WebContextHelper.isHttpsOrSecure(context) :
Boolean.parseBoolean(secureCookieSettings);
+ setCookieHeader.setSecure(secureFlag);
if (WebContextHelper.isHttpsOrSecure(context)) {
setCookieHeader.setHttpOnly(true);
}
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 d48a4261d..1ad63b150 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
@@ -46,6 +46,7 @@ import static
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_S
import static
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_SESSION_STORE_EXCLUDE_PERMISSIONS_DEFAULT;
import static
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_SESSION_STORE_EXCLUDE_ROLES;
import static
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_SESSION_STORE_EXCLUDE_ROLES_DEFAULT;
+import static
org.apache.knox.gateway.pac4j.filter.Pac4jDispatcherFilter.PAC4J_SESSION_STORE_SECURE_COOKIE;
import static
org.apache.knox.gateway.pac4j.session.KnoxSessionStore.PAC4J_PASSWORD;
import static
org.apache.knox.gateway.pac4j.session.KnoxSessionStore.PAC4J_SESSION_PREFIX;
@@ -163,6 +164,65 @@ public class KnoxSessionStoreTest {
Assert.assertNotNull(samlProfile.getAttribute("https://knox.apache.org/SAML/Attributes/groups2"));
}
+ @Test
+ public void testSecureCookieSettings() throws Exception {
+ final AliasService aliasService =
EasyMock.createNiceMock(AliasService.class);
+ EasyMock.expect(aliasService.getPasswordFromAliasForCluster(CLUSTER_NAME,
PAC4J_PASSWORD)).andReturn(PAC4J_PASSWORD.toCharArray()).anyTimes();
+ EasyMock.replay(aliasService);
+
+ final DefaultCryptoService cryptoService = new DefaultCryptoService();
+ cryptoService.setAliasService(aliasService);
+
+ final Map<String, CommonProfile> profile = new HashMap<>();
+ profile.put("SAML2Client", new SAML2Profile());
+
+ // 1. Test when pac4j.session.store.secure.cookie is explicitly set to true
+ runSecureCookieTest(cryptoService, profile, "true",
"http://local.com/gateway/knoxsso/", true, "Secure flag should be true when
explicitly set");
+
+ // 2. Test when pac4j.session.store.secure.cookie is explicitly set to
false
+ runSecureCookieTest(cryptoService, profile, "false",
"https://local.com/gateway/knoxsso/", false, "Secure flag should be false when
explicitly set");
+
+ // 3. Test default behavior for HTTPS request
+ runSecureCookieTest(cryptoService, profile, null,
"https://local.com/gateway/knoxsso/", true, "Secure flag should be true for
HTTPS request by default");
+
+ // 4. Test default behavior for HTTP request
+ runSecureCookieTest(cryptoService, profile, null,
"http://local.com/gateway/knoxsso/", false, "Secure flag should be false for
HTTP request by default");
+ }
+
+ private void runSecureCookieTest(CryptoService cryptoService, Map<String,
CommonProfile> profile,
+ String secureCookieValue, String requestUrl, boolean expectSecureFlag,
String assertMessage) {
+ final Map<String, String> sessionStoreConfigs = new HashMap<>();
+ if (secureCookieValue != null) {
+ sessionStoreConfigs.put(PAC4J_SESSION_STORE_SECURE_COOKIE,
secureCookieValue);
+ }
+
+ final Capture<String> capturedHeader = EasyMock.newCapture();
+ final HttpServletResponse mockResponse =
EasyMock.createNiceMock(HttpServletResponse.class);
+ mockResponse.addHeader(EasyMock.eq("Set-Cookie"),
EasyMock.capture(capturedHeader));
+ EasyMock.replay(mockResponse);
+
+ final JEEContext mockContext = EasyMock.createNiceMock(JEEContext.class);
+
EasyMock.expect(mockContext.getNativeResponse()).andReturn(mockResponse).anyTimes();
+
EasyMock.expect(mockContext.getFullRequestURL()).andReturn(requestUrl).anyTimes();
+ if (requestUrl.startsWith("https")) {
+ EasyMock.expect(mockContext.getScheme()).andReturn("https").anyTimes();
+ EasyMock.expect(mockContext.isSecure()).andReturn(true).anyTimes();
+ } else {
+ EasyMock.expect(mockContext.getScheme()).andReturn("http").anyTimes();
+ EasyMock.expect(mockContext.isSecure()).andReturn(false).anyTimes();
+ }
+ EasyMock.replay(mockContext);
+
+ final KnoxSessionStore sessionStore = new KnoxSessionStore(cryptoService,
CLUSTER_NAME, null, sessionStoreConfigs);
+ sessionStore.set(mockContext, Pac4jConstants.USER_PROFILES, profile);
+
+ if (expectSecureFlag) {
+ Assert.assertTrue(assertMessage,
capturedHeader.getValue().contains("Secure"));
+ } else {
+ Assert.assertFalse(assertMessage,
capturedHeader.getValue().contains("Secure"));
+ }
+ }
+
@Test
public void testNullCookieValue() throws AliasServiceException {
final CryptoService cryptoService =
EasyMock.createNiceMock(CryptoService.class);