HBASE-21275 - Disable TRACE HTTP method for thrift http server (branch 1 only)
Conflicts: hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java Project: http://git-wip-us.apache.org/repos/asf/hbase/repo Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/82f187ef Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/82f187ef Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/82f187ef Branch: refs/heads/branch-1.3 Commit: 82f187efba6e476cd1b88bc6ae8b238e4c670288 Parents: 10c4f59 Author: Wellington Chevreuil <wellingtonchevreuil@ChevreuilWellington-MBP15.local> Authored: Wed Oct 17 12:11:41 2018 +0100 Committer: Andrew Purtell <apurt...@apache.org> Committed: Thu Dec 13 10:22:39 2018 -0800 ---------------------------------------------------------------------- .../hadoop/hbase/thrift/ThriftServerRunner.java | 10 ++- .../hbase/thrift/TestThriftHttpServer.java | 66 ++++++++++++++++++-- 2 files changed, 69 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hbase/blob/82f187ef/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java ---------------------------------------------------------------------- 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 e13b148..76c033d 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 @@ -101,6 +101,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.Strings; import org.apache.hadoop.security.SaslRpcServer.SaslGssCallbackHandler; import org.apache.hadoop.security.UserGroupInformation; @@ -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; @@ -203,6 +205,9 @@ public class ThriftServerRunner implements Runnable { private final boolean securityEnabled; private final boolean doAsEnabled; + 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), @@ -410,11 +415,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(); http://git-wip-us.apache.org/repos/asf/hbase/blob/82f187ef/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftHttpServer.java ---------------------------------------------------------------------- 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 cf14e87..b21de38 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<String> args = new ArrayList<String>(); 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,20 @@ 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(); + } + } }