KNOX-1346 - SNI Mismatch Failures due to Wrong Host Header
authorLarry McCay <lmccay@hortonworks.com>
Fri, 8 Jun 2018 03:53:31 +0000 (23:53 -0400)
committerLarry McCay <lmccay@hortonworks.com>
Fri, 8 Jun 2018 03:53:43 +0000 (23:53 -0400)
gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/AtlasHaDispatch.java
gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteRequest.java
gateway-provider-rewrite/src/test/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteRequestTest.java [new file with mode: 0644]

index 77eb21d..7742b28 100644 (file)
@@ -33,7 +33,6 @@ public class AtlasHaDispatch extends DefaultHaDispatch {
     private static Set<String> REQUEST_EXCLUDE_HEADERS = new HashSet<>();
 
     static {
-        REQUEST_EXCLUDE_HEADERS.add("Host");
         REQUEST_EXCLUDE_HEADERS.add("Content-Length");
     }
 
index f91035c..3a8ae65 100644 (file)
@@ -42,7 +42,9 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
 import java.net.URISyntaxException;
+import java.net.URL;
 import java.net.URLDecoder;
 import java.util.Arrays;
 import java.util.Enumeration;
@@ -79,7 +81,7 @@ public class UrlRewriteRequest extends GatewayRequestWrapper implements Resolver
     this.cookiesFilterName = config.getInitParameter( UrlRewriteServletFilter.REQUEST_COOKIES_FILTER_PARAM );
   }
 
-  private Template getSourceUrl() {
+  Template getSourceUrl() {
     Template urlTemplate;
     //KNOX-439[
     //StringBuffer urlString = super.getRequestURL();
@@ -107,7 +109,7 @@ public class UrlRewriteRequest extends GatewayRequestWrapper implements Resolver
   }
 
   // Note: Source url was added to the request attributes by the GatewayFilter doFilter method.
-  private Template getTargetUrl() {
+  Template getTargetUrl() {
     boolean rewriteRequestUrl = true;
     Template targetUrl;
     if( rewriteRequestUrl ) {
@@ -177,14 +179,32 @@ public class UrlRewriteRequest extends GatewayRequestWrapper implements Resolver
 
   @Override
   public String getHeader( String name ) {
-    String value = super.getHeader( name );
+    String value = null;
+    if (name.equalsIgnoreCase("Host")) {
+      String uri = getRequestURI();
+      try {
+        URL url = new URL(uri);
+        value = url.getHost();
+        // by the time the targetUrl is set as a request
+        // attribute it has already been rewritten just
+        // just return it from here without additional rewrite
+        return value;
+      } catch (MalformedURLException e) {
+        value = null;
+      }
+    }
+
+    value = super.getHeader( name );
+
     if( value != null ) {
       value = rewriteValue( rewriter, super.getHeader( name ), pickFirstRuleWithEqualsIgnoreCasePathMatch( headersFilterConfig, name ) );
     }
+
     return value;
   }
 
   @SuppressWarnings("unchecked")
+  @Override
   public Enumeration getHeaders( String name ) {
     return new EnumerationRewriter( rewriter, super.getHeaders( name ), pickFirstRuleWithEqualsIgnoreCasePathMatch( headersFilterConfig, name ) );
   }
diff --git a/gateway-provider-rewrite/src/test/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteRequestTest.java b/gateway-provider-rewrite/src/test/java/org/apache/knox/gateway/filter/rewrite/impl/UrlRewriteRequestTest.java
new file mode 100644 (file)
index 0000000..368a027
--- /dev/null
@@ -0,0 +1,84 @@
+/**
+ * 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.filter.rewrite.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.knox.gateway.filter.AbstractGatewayFilter;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteProcessor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteServletContextListener;
+import org.apache.knox.gateway.util.urltemplate.Template;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+public class UrlRewriteRequestTest {
+  @Test
+  public void testResolve() throws Exception {
+    
+    UrlRewriteProcessor rewriter = EasyMock.createNiceMock( UrlRewriteProcessor.class );
+
+    ServletContext context = EasyMock.createNiceMock( ServletContext.class );
+    EasyMock.expect( context.getServletContextName() ).andReturn( "test-cluster-name" ).anyTimes();
+    EasyMock.expect( context.getInitParameter( "test-init-param-name" ) ).andReturn( "test-init-param-value" ).anyTimes();
+    EasyMock.expect( context.getAttribute( UrlRewriteServletContextListener.PROCESSOR_ATTRIBUTE_NAME ) ).andReturn( rewriter ).anyTimes();
+
+    FilterConfig config = EasyMock.createNiceMock( FilterConfig.class );
+    EasyMock.expect( config.getInitParameter( "test-filter-init-param-name" ) ).andReturn( "test-filter-init-param-value" ).anyTimes();
+    EasyMock.expect( config.getServletContext() ).andReturn( context ).anyTimes();
+
+    HttpServletRequest request = EasyMock.createNiceMock( HttpServletRequest.class );
+    EasyMock.expect( request.getScheme()).andReturn("https").anyTimes();
+    EasyMock.expect( request.getServerName()).andReturn("targethost.com").anyTimes();
+    EasyMock.expect( request.getServerPort()).andReturn(80).anyTimes();
+    EasyMock.expect( request.getRequestURI()).andReturn("/").anyTimes();
+    EasyMock.expect( request.getQueryString()).andReturn(null).anyTimes();
+    EasyMock.expect( request.getHeader("Host")).andReturn("sourcehost.com").anyTimes();
+    HttpServletResponse response = EasyMock.createNiceMock( HttpServletResponse.class );
+//    EasyMock.replay( rewriter, context, config, request, response );
+    EasyMock.replay( rewriter, context, config, request, response );
+
+    // instantiate UrlRewriteRequest so that we can use it as a Template factory for targetUrl
+    UrlRewriteRequest rewriteRequest = new UrlRewriteRequest(config, request);
+    // emulate the getTargetUrl by using the sourceUrl as the targetUrl when
+    // it doesn't exist
+    Template target = rewriteRequest.getSourceUrl();
+
+    // reset the mock so that we can set the targetUrl as a request attribute for deriving
+    // host header. Also set the servername to the sourcehost which would be the knox host
+    // make sure that Host header is returned as the target host instead.
+    EasyMock.reset(request);
+    EasyMock.expect( request.getScheme()).andReturn("https").anyTimes();
+    EasyMock.expect( request.getServerName()).andReturn("sourcehost.com").anyTimes();
+    EasyMock.expect( request.getServerPort()).andReturn(80).anyTimes();
+    EasyMock.expect( request.getRequestURI()).andReturn("/").anyTimes();
+    EasyMock.expect( request.getQueryString()).andReturn(null).anyTimes();
+    EasyMock.expect( request.getHeader("Host")).andReturn("sourcehost.com").anyTimes();
+    EasyMock.expect( request.getAttribute(AbstractGatewayFilter.TARGET_REQUEST_URL_ATTRIBUTE_NAME))
+      .andReturn(target).anyTimes();
+    EasyMock.replay(request);
+
+    String hostHeader = rewriteRequest.getHeader("Host");
+
+    assertEquals(hostHeader, "targethost.com");
+  }
+}