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 21aaa2d48 KNOX-3113: Changed the default HSTS header for global 
config, skips copying the HSTS header if its already set (#1008)
21aaa2d48 is described below

commit 21aaa2d48559eeb2646bde4e4185c6f16bc8aa83
Author: hanicz <[email protected]>
AuthorDate: Thu Mar 27 11:45:36 2025 +0100

    KNOX-3113: Changed the default HSTS header for global config, skips copying 
the HSTS header if its already set (#1008)
---
 .../gateway/config/impl/GatewayConfigImpl.java     |  2 +-
 .../knox/gateway/GatewayGlobalConfigTest.java      |  2 +-
 .../knox/gateway/dispatch/DefaultDispatch.java     |  5 +++
 .../knox/gateway/dispatch/DefaultDispatchTest.java | 46 ++++++++++++++++++++++
 4 files changed, 53 insertions(+), 2 deletions(-)

diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
index 9bac7aa89..c61a8c557 100644
--- 
a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
@@ -361,7 +361,7 @@ public class GatewayConfigImpl extends Configuration 
implements GatewayConfig {
 
   //Strict-Transport Option
   public static final boolean DEFAULT_STRICT_TRANSPORT_ENABLED = false;
-  public static final String DEFAULT_STRICT_TRANSPORT_OPTION = 
"max-age=31536000";
+  public static final String DEFAULT_STRICT_TRANSPORT_OPTION = 
"max-age=31536000; includeSubDomains";
 
   public static final String STRICT_TRANSPORT_ENABLED = 
GATEWAY_CONFIG_FILE_PREFIX + ".strict.transport.enabled";
   public static final String STRICT_TRANSPORT_OPTION = 
GATEWAY_CONFIG_FILE_PREFIX + ".strict.transport.option";
diff --git 
a/gateway-server/src/test/java/org/apache/knox/gateway/GatewayGlobalConfigTest.java
 
b/gateway-server/src/test/java/org/apache/knox/gateway/GatewayGlobalConfigTest.java
index 1742dcba8..dbbc29e4a 100644
--- 
a/gateway-server/src/test/java/org/apache/knox/gateway/GatewayGlobalConfigTest.java
+++ 
b/gateway-server/src/test/java/org/apache/knox/gateway/GatewayGlobalConfigTest.java
@@ -213,6 +213,6 @@ public class GatewayGlobalConfigTest {
     System.setProperty( GatewayConfigImpl.GATEWAY_HOME_VAR, getHomeDirName( 
"conf-demo/conf/gateway-site.xml" ) );
     GatewayConfig config = new GatewayConfigImpl();
     assertFalse(config.isStrictTransportEnabled());
-    assertEquals("max-age=31536000", config.getStrictTransportOption());
+    assertEquals("max-age=31536000; includeSubDomains", 
config.getStrictTransportOption());
   }
 }
diff --git 
a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java
 
b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java
index 0aba5297c..220817386 100644
--- 
a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java
+++ 
b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java
@@ -68,6 +68,7 @@ public class DefaultDispatch extends AbstractGatewayDispatch {
   /* list of cookies that should be blocked when set-cookie header is allowed 
*/
   protected static final Set<String> EXCLUDE_SET_COOKIES_DEFAULT = new 
HashSet<>(Arrays.asList("hadoop.auth", "hive.server2.auth", "impala.auth"));
 
+  protected static final String STRICT_TRANSPORT_SECURITY = 
"Strict-Transport-Security";
 
   protected static final SpiGatewayMessages LOG = 
MessagesFactory.get(SpiGatewayMessages.class);
   protected static final SpiGatewayResources RES = 
ResourcesFactory.get(SpiGatewayResources.class);
@@ -359,6 +360,10 @@ public class DefaultDispatch extends 
AbstractGatewayDispatch {
     getOutboundResponseExcludeHeaders().stream().forEach(excludeHeader ->
         excludedHeaderDirectives.put(excludeHeader, 
Collections.singleton(EXCLUDE_ALL)));
     excludedHeaderDirectives.put(SET_COOKIE, 
getOutboundResponseExcludedSetCookieHeaderDirectives());
+    //If HSTS header is already present in the response we skip adding it to 
avoid any duplication
+    if(outboundResponse.containsHeader(STRICT_TRANSPORT_SECURITY)) {
+        excludedHeaderDirectives.put(STRICT_TRANSPORT_SECURITY, 
Collections.singleton(EXCLUDE_ALL));
+    }
 
     for (Header header : inboundResponse.getAllHeaders()) {
       boolean isBlockedAuthHeader = 
Arrays.stream(header.getElements()).anyMatch(h -> 
EXCLUDE_SET_COOKIES_DEFAULT.contains(h.getName()) && 
getOutboundResponseExcludedSetCookieHeaderDirectives().contains(h.getName()) );
diff --git 
a/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/DefaultDispatchTest.java
 
b/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/DefaultDispatchTest.java
index e755f9717..60a3adfa1 100644
--- 
a/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/DefaultDispatchTest.java
+++ 
b/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/DefaultDispatchTest.java
@@ -38,6 +38,9 @@ import javax.servlet.ServletInputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.message.BasicHeader;
 import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.servlet.SynchronousServletOutputStreamAdapter;
 import org.apache.knox.test.TestUtils;
@@ -241,4 +244,47 @@ public class DefaultDispatchTest {
 
   }
 
+  @Test
+  public void testCopyResponseHeaderFieldsCopyHSTS() {
+    HttpServletResponse outboundResponse = 
EasyMock.createMock(HttpServletResponse.class);
+    HttpResponse inboundResponse = EasyMock.createMock(HttpResponse.class);
+    Header[] headers = {
+            new BasicHeader(DefaultDispatch.STRICT_TRANSPORT_SECURITY, 
"max-age=300"),
+            new BasicHeader("Test", "test")
+    };
+
+    
EasyMock.expect(outboundResponse.containsHeader(DefaultDispatch.STRICT_TRANSPORT_SECURITY)).andReturn(false).once();
+    EasyMock.expect(inboundResponse.getAllHeaders()).andReturn(headers).once();
+    outboundResponse.addHeader(DefaultDispatch.STRICT_TRANSPORT_SECURITY, 
"max-age=300");
+    EasyMock.expectLastCall().once();
+    outboundResponse.addHeader("Test", "test");
+    EasyMock.expectLastCall().once();
+    EasyMock.replay(outboundResponse, inboundResponse);
+
+    DefaultDispatch dispatch = new DefaultDispatch();
+    dispatch.copyResponseHeaderFields(outboundResponse, inboundResponse);
+
+    EasyMock.verify(outboundResponse, inboundResponse);
+  }
+
+  @Test
+  public void testCopyResponseHeaderFieldsNoCopyHSTS() {
+    HttpServletResponse outboundResponse = 
EasyMock.createMock(HttpServletResponse.class);
+    HttpResponse inboundResponse = EasyMock.createMock(HttpResponse.class);
+    Header[] headers = {
+            new BasicHeader(DefaultDispatch.STRICT_TRANSPORT_SECURITY, 
"max-age=300"),
+            new BasicHeader("Test", "test")
+    };
+
+    
EasyMock.expect(outboundResponse.containsHeader(DefaultDispatch.STRICT_TRANSPORT_SECURITY)).andReturn(true).once();
+    EasyMock.expect(inboundResponse.getAllHeaders()).andReturn(headers).once();
+    outboundResponse.addHeader("Test", "test");
+    EasyMock.expectLastCall().once();
+    EasyMock.replay(outboundResponse, inboundResponse);
+
+    DefaultDispatch dispatch = new DefaultDispatch();
+    dispatch.copyResponseHeaderFields(outboundResponse, inboundResponse);
+
+    EasyMock.verify(outboundResponse, inboundResponse);
+  }
 }

Reply via email to