From c60578d9829f29cf77b250d238a9e38dc0b513d7 Mon Sep 17 00:00:00 2001 From: Ashish Singhi Date: Thu, 10 May 2018 22:39:43 +0530 Subject: [PATCH] HBASE-20004 Client is not able to execute REST queries in a secure cluster Signed-off-by: Ashish Singhi --- .../hadoop/hbase/http/HttpServerUtil.java | 20 ++++++++++++------- .../apache/hadoop/hbase/rest/RESTServer.java | 7 ++++++- .../hbase/rest/HBaseRESTTestingUtility.java | 2 +- .../hbase/thrift/ThriftServerRunner.java | 6 +++++- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServerUtil.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServerUtil.java index 777ced009b8..e41daf31079 100644 --- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServerUtil.java +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServerUtil.java @@ -31,8 +31,10 @@ public final class HttpServerUtil { /** * Add constraints to a Jetty Context to disallow undesirable Http methods. * @param ctxHandler The context to modify + * @param allowOptionsMethod if true then OPTIONS method will not be set in constraint mapping */ - public static void constrainHttpMethods(ServletContextHandler ctxHandler) { + public static void constrainHttpMethods(ServletContextHandler ctxHandler, + boolean allowOptionsMethod) { Constraint c = new Constraint(); c.setAuthenticate(true); @@ -41,13 +43,17 @@ public final class HttpServerUtil { cmt.setMethod("TRACE"); cmt.setPathSpec("/*"); - ConstraintMapping cmo = new ConstraintMapping(); - cmo.setConstraint(c); - cmo.setMethod("OPTIONS"); - cmo.setPathSpec("/*"); - ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler(); - securityHandler.setConstraintMappings(new ConstraintMapping[]{ cmt, cmo }); + + if (!allowOptionsMethod) { + ConstraintMapping cmo = new ConstraintMapping(); + cmo.setConstraint(c); + cmo.setMethod("OPTIONS"); + cmo.setPathSpec("/*"); + securityHandler.setConstraintMappings(new ConstraintMapping[] { cmt, cmo }); + } else { + securityHandler.setConstraintMappings(new ConstraintMapping[] { cmt }); + } ctxHandler.setSecurityHandler(securityHandler); } diff --git a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java index 591eae9f02a..cad63a4ff09 100644 --- a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java +++ b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java @@ -95,6 +95,10 @@ public class RESTServer implements Constants { private static final String PATH_SPEC_ANY = "/*"; + static String REST_HTTP_ALLOW_OPTIONS_METHOD = "hbase.rest.http.allow.options.method"; + // HTTP OPTIONS method is commonly used in REST APIs for negotiation. So it is enabled by default. + private static boolean REST_HTTP_ALLOW_OPTIONS_METHOD_DEFAULT = true; + private static void printUsageAndExit(Options options, int exitCode) { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("hbase rest start", "", options, @@ -341,7 +345,8 @@ public class RESTServer implements Constants { ctxHandler.addFilter(filter, PATH_SPEC_ANY, EnumSet.of(DispatcherType.REQUEST)); } addCSRFFilter(ctxHandler, conf); - HttpServerUtil.constrainHttpMethods(ctxHandler); + HttpServerUtil.constrainHttpMethods(ctxHandler, servlet.getConfiguration() + .getBoolean(REST_HTTP_ALLOW_OPTIONS_METHOD, REST_HTTP_ALLOW_OPTIONS_METHOD_DEFAULT)); // Put up info server. int port = conf.getInt("hbase.rest.info.port", 8085); diff --git a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/HBaseRESTTestingUtility.java b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/HBaseRESTTestingUtility.java index 273010a334d..38c734df0eb 100644 --- a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/HBaseRESTTestingUtility.java +++ b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/HBaseRESTTestingUtility.java @@ -93,7 +93,7 @@ public class HBaseRESTTestingUtility { conf.set(RESTServer.REST_CSRF_BROWSER_USERAGENTS_REGEX_KEY, ".*"); RESTServer.addCSRFFilter(ctxHandler, conf); - HttpServerUtil.constrainHttpMethods(ctxHandler); + HttpServerUtil.constrainHttpMethods(ctxHandler, true); // start the server server.start(); 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 1db9256bd62..49f20a23b17 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 @@ -224,6 +224,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 */ public enum ImplType { HS_HA("hsha", true, THsHaServer.class, true), @@ -458,7 +461,8 @@ public class ThriftServerRunner implements Runnable { ServletContextHandler ctxHandler = new ServletContextHandler(httpServer, "/", ServletContextHandler.SESSIONS); ctxHandler.addServlet(new ServletHolder(thriftHttpServlet), "/*"); - HttpServerUtil.constrainHttpMethods(ctxHandler); + HttpServerUtil.constrainHttpMethods(ctxHandler, + conf.getBoolean(THRIFT_HTTP_ALLOW_OPTIONS_METHOD, THRIFT_HTTP_ALLOW_OPTIONS_METHOD_DEFAULT)); // set up Jetty and run the embedded server HttpConfiguration httpConfig = new HttpConfiguration();