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

more 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 06c3f8c4c KNOX-3134: Set Secure and HttpOnly attributes for 
pac4jCsrfToken Cookie (#1029)
06c3f8c4c is described below

commit 06c3f8c4c28b63b060528272dc8e6c023598416d
Author: hanicz <[email protected]>
AuthorDate: Tue Apr 29 19:37:31 2025 +0200

    KNOX-3134: Set Secure and HttpOnly attributes for pac4jCsrfToken Cookie 
(#1029)
    
    * KNOX-3134: Set Secure and HttpOnly attributes for pac4jCsrfToken Cookie
    
    * KNOX-3134: Pac4jProviderTest nullpointer fix
---
 .../pac4j/filter/Pac4jDispatcherFilter.java        | 27 +++++++-
 .../knox/gateway/pac4j/Pac4jProviderTest.java      |  9 +++
 .../pac4j/filter/Pac4jDispatcherFilterTest.java    | 76 ++++++++++++++++++++--
 3 files changed, 106 insertions(+), 6 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 7f1670ed0..d0b7521d9 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
@@ -57,8 +57,10 @@ import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
 
 import java.io.IOException;
 import java.util.Enumeration;
@@ -128,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";
 
+  private static final String PAC4J_CSRF_TOKEN = "pac4jCsrfToken";
+  private static boolean SSL_ENABLED = true;
+
   private CallbackFilter callbackFilter;
 
   private SecurityFilter securityFilter;
@@ -250,6 +255,8 @@ public class Pac4jDispatcherFilter implements Filter, 
SessionInvalidator {
 
     SessionInvalidators.KNOX_SSO_INVALIDATOR.registerSessionInvalidator(this);
 
+    GatewayConfig gatewayConfig = (GatewayConfig) 
context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
+    SSL_ENABLED = gatewayConfig.isSSLEnabled();
   }
 
   /**
@@ -320,7 +327,6 @@ public class Pac4jDispatcherFilter implements Filter, 
SessionInvalidator {
 
   @Override
   public void doFilter( ServletRequest servletRequest, ServletResponse 
servletResponse, FilterChain filterChain) throws IOException, ServletException {
-
     final HttpServletRequest request = (HttpServletRequest) servletRequest;
     request.setAttribute(PAC4J_CONFIG, securityFilter.getSharedConfig());
 
@@ -333,7 +339,7 @@ public class Pac4jDispatcherFilter implements Filter, 
SessionInvalidator {
     } else {
       // otherwise just apply security and requires authentication
       // apply RequiresAuthenticationFilter
-      securityFilter.doFilter(servletRequest, servletResponse, filterChain);
+      securityFilter.doFilter(servletRequest, new 
Pac4jSetCookieResponseWrapper((HttpServletResponse) servletResponse), 
filterChain);
     }
   }
 
@@ -350,4 +356,21 @@ public class Pac4jDispatcherFilter implements Filter, 
SessionInvalidator {
     
SessionInvalidators.KNOX_SSO_INVALIDATOR.unregisterSessionInvalidator(this);
   }
 
+  static class Pac4jSetCookieResponseWrapper extends 
HttpServletResponseWrapper {
+
+    Pac4jSetCookieResponseWrapper(HttpServletResponse response) {
+      super(response);
+    }
+
+    @Override
+    public void addCookie(Cookie cookie) {
+      if(cookie.getName().equals(PAC4J_CSRF_TOKEN)) {
+        cookie.setHttpOnly(true);
+        if(SSL_ENABLED) {
+          cookie.setSecure(true);
+        }
+      }
+      super.addCookie(cookie);
+    }
+  }
 }
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 e73d8feab..de4b7a5c9 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
@@ -20,6 +20,7 @@ package org.apache.knox.gateway.pac4j;
 import org.apache.knox.gateway.audit.api.AuditContext;
 import org.apache.knox.gateway.audit.api.AuditService;
 import org.apache.knox.gateway.audit.api.Auditor;
+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;
@@ -80,6 +81,8 @@ public class Pac4jProviderTest {
         EasyMock.replay(services);
 
         final ServletContext context = 
EasyMock.createNiceMock(ServletContext.class);
+        GatewayConfig gatewayConfig = 
EasyMock.createNiceMock(GatewayConfig.class);
+        
EasyMock.expect(context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(gatewayConfig);
         
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
         
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE)).andReturn(CLUSTER_NAME);
         EasyMock.replay(context);
@@ -182,6 +185,8 @@ public class Pac4jProviderTest {
         EasyMock.replay(services);
 
         final ServletContext context = 
EasyMock.createNiceMock(ServletContext.class);
+        GatewayConfig gatewayConfig = 
EasyMock.createNiceMock(GatewayConfig.class);
+        
EasyMock.expect(context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(gatewayConfig);
         
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
         
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE)).andReturn(CLUSTER_NAME);
         EasyMock.replay(context);
@@ -284,6 +289,8 @@ public class Pac4jProviderTest {
         EasyMock.replay(services);
 
         final ServletContext context = 
EasyMock.createNiceMock(ServletContext.class);
+        GatewayConfig gatewayConfig = 
EasyMock.createNiceMock(GatewayConfig.class);
+        
EasyMock.expect(context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(gatewayConfig);
         
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
         
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE)).andReturn(CLUSTER_NAME);
         EasyMock.replay(context);
@@ -386,8 +393,10 @@ public class Pac4jProviderTest {
         EasyMock.replay(services);
 
         ServletContext context = EasyMock.createNiceMock(ServletContext.class);
+        GatewayConfig gatewayConfig = 
EasyMock.createNiceMock(GatewayConfig.class);
         
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
         
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE)).andReturn(CLUSTER_NAME);
+        
EasyMock.expect(context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(gatewayConfig);
         EasyMock.replay(context);
 
         new Pac4jDispatcherFilter().init(
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 19d20f427..c93d969be 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
@@ -17,6 +17,7 @@
  */
 package org.apache.knox.gateway.pac4j.filter;
 
+import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.pac4j.session.KnoxSessionStore;
 import org.apache.knox.gateway.services.GatewayServices;
 import org.apache.knox.gateway.services.ServiceType;
@@ -30,12 +31,16 @@ import org.junit.Test;
 
 import javax.servlet.FilterConfig;
 import javax.servlet.ServletContext;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
 import java.security.KeyStore;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static 
org.pac4j.config.client.PropertiesConstants.SAML_IDENTITY_PROVIDER_METADATA_PATH;
 import static org.pac4j.config.client.PropertiesConstants.SAML_KEYSTORE_PATH;
 
@@ -53,6 +58,7 @@ public class Pac4jDispatcherFilterTest {
         MasterService masterService;
         FilterConfig filterConfig;
         KeyStore ks;
+        GatewayConfig gatewayConfig;
     }
 
     private TestMocks createMocks() throws Exception {
@@ -65,6 +71,7 @@ public class Pac4jDispatcherFilterTest {
         mocks.keystoreService = EasyMock.createNiceMock(KeystoreService.class);
         mocks.masterService = EasyMock.createNiceMock(MasterService.class);
         mocks.filterConfig = EasyMock.createNiceMock(FilterConfig.class);
+        mocks.gatewayConfig = EasyMock.createNiceMock(GatewayConfig.class);
         return mocks;
     }
 
@@ -94,6 +101,7 @@ public class Pac4jDispatcherFilterTest {
         
EasyMock.expect(mocks.filterConfig.getInitParameter("clientName")).andReturn("SAML2Client").anyTimes();
         
EasyMock.expect(mocks.aliasService.getPasswordFromAliasForCluster(TEST_CLUSTER_NAME,
 KnoxSessionStore.PAC4J_PASSWORD, true))
                 
.andReturn(KnoxSessionStore.PAC4J_PASSWORD.toCharArray()).anyTimes();
+        
EasyMock.expect(mocks.context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(mocks.gatewayConfig).anyTimes();
     }
 
     private void verifyCookiemaxAge(FilterConfig filterConfig, String 
expectedCookieMaxAge) throws Exception {
@@ -119,12 +127,12 @@ public class Pac4jDispatcherFilterTest {
         setupCommonExpectations(mocks, additionalParams);
         
EasyMock.expect(mocks.filterConfig.getInitParameter(Pac4jDispatcherFilter.PAC4J_COOKIE_MAX_AGE)).andReturn(expectedCookieMaxAge).anyTimes();
 
-        EasyMock.replay(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig);
+        EasyMock.replay(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
 
         verifyCookiemaxAge(mocks.filterConfig, expectedCookieMaxAge);
 
         // Verify all mock interactions
-        EasyMock.verify(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig);
+        EasyMock.verify(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
     }
 
     /**
@@ -142,11 +150,71 @@ public class Pac4jDispatcherFilterTest {
         TestMocks mocks = createMocks();
         setupCommonExpectations(mocks, Collections.EMPTY_LIST);
 
-        EasyMock.replay(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig);
+        EasyMock.replay(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
 
         verifyCookiemaxAge(mocks.filterConfig, expectedCookieMaxAge);
 
         // Verify all mock interactions
-        EasyMock.verify(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig);
+        EasyMock.verify(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
+    }
+
+    @Test
+    public void testPAC4JSetCookieResponseWrapperStaysTrue() throws Exception {
+        HttpServletResponse response = 
EasyMock.createNiceMock(HttpServletResponse.class);
+        Cookie cookie = new Cookie("pac4jCsrfToken", "pac4j_value");
+        cookie.setSecure(true);
+        cookie.setHttpOnly(true);
+        TestMocks mocks = createMocks();
+        setupCommonExpectations(mocks, Collections.EMPTY_LIST);
+        
EasyMock.expect(mocks.gatewayConfig.isSSLEnabled()).andReturn(false).anyTimes();
+        EasyMock.replay(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
+
+        Pac4jDispatcherFilter filter = new Pac4jDispatcherFilter();
+        filter.init(mocks.filterConfig);
+        Pac4jDispatcherFilter.Pac4jSetCookieResponseWrapper wrapper = new 
Pac4jDispatcherFilter.Pac4jSetCookieResponseWrapper(response);
+        wrapper.addCookie(cookie);
+
+        assertTrue(cookie.getSecure());
+        assertTrue(cookie.isHttpOnly());
+    }
+
+    @Test
+    public void testPAC4JSetCookieResponseWrapperFalseToTrue() throws 
Exception {
+        HttpServletResponse response = 
EasyMock.createNiceMock(HttpServletResponse.class);
+        Cookie cookie = new Cookie("pac4jCsrfToken", "pac4j_value");
+        cookie.setSecure(false);
+        cookie.setHttpOnly(false);
+        TestMocks mocks = createMocks();
+        setupCommonExpectations(mocks, Collections.EMPTY_LIST);
+        
EasyMock.expect(mocks.gatewayConfig.isSSLEnabled()).andReturn(true).anyTimes();
+        EasyMock.replay(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
+
+        Pac4jDispatcherFilter filter = new Pac4jDispatcherFilter();
+        filter.init(mocks.filterConfig);
+        Pac4jDispatcherFilter.Pac4jSetCookieResponseWrapper wrapper = new 
Pac4jDispatcherFilter.Pac4jSetCookieResponseWrapper(response);
+        wrapper.addCookie(cookie);
+
+        assertTrue(cookie.getSecure());
+        assertTrue(cookie.isHttpOnly());
+    }
+
+    @Test
+    public void testPAC4JSetCookieResponseWrapperNoSSL() throws Exception {
+        HttpServletResponse response = 
EasyMock.createNiceMock(HttpServletResponse.class);
+        Cookie cookie = new Cookie("pac4jCsrfToken", "pac4j_value");
+        cookie.setSecure(false);
+        cookie.setHttpOnly(false);
+        TestMocks mocks = createMocks();
+        setupCommonExpectations(mocks, Collections.EMPTY_LIST);
+        
EasyMock.expect(mocks.gatewayConfig.isSSLEnabled()).andReturn(false).anyTimes();
+        EasyMock.replay(mocks.context, mocks.services, mocks.cryptoService, 
mocks.aliasService, mocks.keystoreService, mocks.masterService, 
mocks.filterConfig, mocks.gatewayConfig);
+
+        Pac4jDispatcherFilter filter = new Pac4jDispatcherFilter();
+        filter.init(mocks.filterConfig);
+        Pac4jDispatcherFilter.Pac4jSetCookieResponseWrapper wrapper = new 
Pac4jDispatcherFilter.Pac4jSetCookieResponseWrapper(response);
+        wrapper.addCookie(cookie);
+
+        assertFalse(cookie.getSecure());
+        assertTrue(cookie.isHttpOnly());
     }
 }

Reply via email to