From 7357e630bdfc7491ad15f6f3dab8fd533090c29b Mon Sep 17 00:00:00 2001 From: Wellington Chevreuil Date: Wed, 17 Oct 2018 12:11:41 +0100 Subject: [PATCH] HBASE-21275 - Disable TRACE HTTP method for thrift http server (branch 1 only) --- .../hbase/thrift/ThriftServerRunner.java | 10 ++- .../hbase/thrift/TestThriftHttpServer.java | 67 +++++++++++++++++-- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java index 07c18a7ead..3532ab5146 100644 --- a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java +++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java @@ -100,6 +100,7 @@ import org.apache.hadoop.hbase.thrift.generated.TScan; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.ConnectionCache; import org.apache.hadoop.hbase.util.DNS; +import org.apache.hadoop.hbase.util.HttpServerUtil; import org.apache.hadoop.hbase.util.JvmPauseMonitor; import org.apache.hadoop.hbase.util.Strings; import org.apache.hadoop.security.SaslRpcServer.SaslGssCallbackHandler; @@ -128,6 +129,7 @@ import org.mortbay.jetty.Server; import org.mortbay.jetty.nio.SelectChannelConnector; import org.mortbay.jetty.servlet.Context; import org.mortbay.jetty.servlet.ServletHolder; +import org.mortbay.jetty.webapp.WebAppContext; import org.mortbay.thread.QueuedThreadPool; import com.google.common.base.Joiner; @@ -205,6 +207,9 @@ public class ThriftServerRunner implements Runnable { private final JvmPauseMonitor pauseMonitor; + static String THRIFT_HTTP_ALLOW_OPTIONS_METHOD = "hbase.thrift.http.allow.options.method"; + private static boolean THRIFT_HTTP_ALLOW_OPTIONS_METHOD_DEFAULT = false; + /** An enum of server implementation selections */ enum ImplType { HS_HA("hsha", true, THsHaServer.class, true), @@ -417,11 +422,14 @@ public class ThriftServerRunner implements Runnable { httpServer = new Server(); // Context handler - Context context = new Context(httpServer, "/", Context.SESSIONS); + Context context = new WebAppContext(); context.setContextPath("/"); + context.setResourceBase("hbase-webapps/"); String httpPath = "/*"; httpServer.setHandler(context); context.addServlet(new ServletHolder(thriftHttpServlet), httpPath); + HttpServerUtil.constrainHttpMethods(context, + conf.getBoolean(THRIFT_HTTP_ALLOW_OPTIONS_METHOD, THRIFT_HTTP_ALLOW_OPTIONS_METHOD_DEFAULT)); // set up Jetty and run the embedded server Connector connector = new SelectChannelConnector(); diff --git a/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftHttpServer.java b/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftHttpServer.java index cf14e8731e..f61e6ed221 100644 --- a/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftHttpServer.java +++ b/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftHttpServer.java @@ -18,10 +18,13 @@ */ package org.apache.hadoop.hbase.thrift; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; +import java.net.HttpURLConnection; +import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -149,6 +152,46 @@ public class TestThriftHttpServer { runThriftServer(0); } + @Test + public void testThriftServerHttpTraceForbiddenWhenOptionsDisabled() throws Exception { + // HTTP TRACE method should be disabled for security + // See https://www.owasp.org/index.php/Cross_Site_Tracing + checkHttpMethods("TRACE", HttpURLConnection.HTTP_FORBIDDEN); + } + + @Test + public void testThriftServerHttpTraceForbiddenWhenOptionsEnabled() throws Exception { + // HTTP TRACE method should be disabled for security + // See https://www.owasp.org/index.php/Cross_Site_Tracing + TEST_UTIL.getConfiguration().setBoolean(ThriftServerRunner.THRIFT_HTTP_ALLOW_OPTIONS_METHOD, + true); + checkHttpMethods("TRACE", HttpURLConnection.HTTP_FORBIDDEN); + } + + @Test + public void testThriftServerHttpOptionsForbiddenWhenOptionsDisabled() throws Exception { + // HTTP OPTIONS method should be disabled by default, so we make sure + // hbase.thrift.http.allow.options.method is not set anywhere in the config + TEST_UTIL.getConfiguration().unset(ThriftServerRunner.THRIFT_HTTP_ALLOW_OPTIONS_METHOD); + checkHttpMethods("OPTIONS", HttpURLConnection.HTTP_FORBIDDEN); + } + + @Test + public void testThriftServerHttpOptionsOkWhenOptionsEnabled() throws Exception { + TEST_UTIL.getConfiguration().setBoolean(ThriftServerRunner.THRIFT_HTTP_ALLOW_OPTIONS_METHOD, + true); + checkHttpMethods("OPTIONS", HttpURLConnection.HTTP_OK); + } + + private void waitThriftServerStartup() throws Exception{ + // wait up to 10s for the server to start + for (int i = 0; i < 100 + && ( thriftServer.serverRunner == null || thriftServer.serverRunner.httpServer == + null); i++) { + Thread.sleep(100); + } + } + private void runThriftServer(int customHeaderSize) throws Exception { List args = new ArrayList(); port = HBaseTestingUtility.randomFreePort(); @@ -159,12 +202,7 @@ public class TestThriftHttpServer { thriftServer = new ThriftServer(TEST_UTIL.getConfiguration()); startHttpServerThread(args.toArray(new String[args.size()])); - // wait up to 10s for the server to start - for (int i = 0; i < 100 - && ( thriftServer.serverRunner == null || thriftServer.serverRunner.httpServer == - null); i++) { - Thread.sleep(100); - } + waitThriftServerStartup(); try { talkToThriftServer(customHeaderSize); @@ -223,4 +261,21 @@ public class TestThriftHttpServer { throw new Exception(httpServerException); } } + + private void checkHttpMethods(String httpRequestMethod, + int httpExpectedResponse) throws Exception { + port = HBaseTestingUtility.randomFreePort(); + thriftServer = new ThriftServer(TEST_UTIL.getConfiguration()); + try { + startHttpServerThread(new String[] { "-port", String.valueOf(port), "start" }); + waitThriftServerStartup(); + final URL url = new URL("http://"+ HConstants.LOCALHOST + ":" + port); + final HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); + httpConn.setRequestMethod(httpRequestMethod); + assertEquals(httpExpectedResponse, httpConn.getResponseCode()); + } finally { + stopHttpServerThread(); + } + } } + -- 2.17.1 (Apple Git-112)