diff --git a/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java b/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java index cfc90919c8b395f8206974b94c9296c9623a268d..4393a2825e1f465781fc07a6678ebaa2bab906bd 100644 --- a/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java +++ b/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java @@ -4517,6 +4517,10 @@ private static void populateLlapDaemonVarsSet(Set llapDaemonVarsSetLocal "llap.daemon.service.port"), LLAP_DAEMON_WEB_SSL("hive.llap.daemon.web.ssl", false, "Whether LLAP daemon web UI should use SSL.", "llap.daemon.service.ssl"), + LLAP_DAEMON_WEB_XFRAME_ENABLED("hive.llap.daemon.web.xframe.enabled", true, + "Whether to enable xframe on LLAP daemon webUI\n"), + LLAP_DAEMON_WEB_XFRAME_VALUE("hive.llap.daemon.web.xframe.value", "SAMEORIGIN", + "Configuration to allow the user to set the x_frame-options value\n"), LLAP_CLIENT_CONSISTENT_SPLITS("hive.llap.client.consistent.splits", true, "Whether to setup split locations to match nodes on which llap daemons are running, " + "instead of using the locations provided by the split itself. If there is no llap daemon " + diff --git a/common/src/java/org/apache/hive/http/HttpServer.java b/common/src/java/org/apache/hive/http/HttpServer.java index b3ce8da896d5b3eac6fd9833244e795733c26c1b..52253f94ac6c71f7d00d1c80fc6e0a2d78b3112d 100644 --- a/common/src/java/org/apache/hive/http/HttpServer.java +++ b/common/src/java/org/apache/hive/http/HttpServer.java @@ -169,6 +169,7 @@ private HttpServer(final Builder b) throws IOException { private XFrameOption xFrameOption = XFrameOption.SAMEORIGIN; private final List>> servlets = new LinkedList>>(); + private boolean disableDirListing = false; public Builder(String name) { Preconditions.checkArgument(name != null && !name.isEmpty(), "Name must be specified"); @@ -304,6 +305,10 @@ public Builder setXFrameOption(String option) { this.xFrameOption = XFrameOption.getEnum(option); return this; } + + public void setDisableDirListing(boolean disableDirListing) { + this.disableDirListing = disableDirListing; + } } public void start() throws Exception { @@ -577,10 +582,14 @@ private void createWebServer(final Builder b) throws IOException { } Map xFrameParams = setHeaders(); - if(b.xFrameEnabled){ + if (b.xFrameEnabled) { setupXframeFilter(b,xFrameParams); } + if (b.disableDirListing) { + disableDirectoryListingOnServlet(webAppContext); + } + initializeWebServer(b, threadPool.getMaxThreads()); } @@ -611,7 +620,7 @@ private void initializeWebServer(final Builder b, int queueSize) throws IOExcept webServer.setHandler(contexts); - if(b.usePAM){ + if (b.usePAM) { setupPam(b, contexts); } @@ -646,6 +655,7 @@ private void initializeWebServer(final Builder b, int queueSize) throws IOExcept staticCtx.setResourceBase(appDir + "/static"); staticCtx.addServlet(DefaultServlet.class, "/*"); staticCtx.setDisplayName("static"); + disableDirectoryListingOnServlet(staticCtx); String logDir = getLogDir(b.conf); if (logDir != null) { @@ -749,6 +759,11 @@ public void addServlet(String name, String pathSpec, webAppContext.addServlet(holder, pathSpec); } + + private static void disableDirectoryListingOnServlet(ServletContextHandler contextHandler) { + contextHandler.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false"); + } + /** * The X-FRAME-OPTIONS header in HTTP response to mitigate clickjacking * attack. diff --git a/llap-server/src/java/org/apache/hadoop/hive/llap/daemon/services/impl/LlapWebServices.java b/llap-server/src/java/org/apache/hadoop/hive/llap/daemon/services/impl/LlapWebServices.java index 3c124f9b632b7794116515d45763ac577f1fc9c1..59bdf53c48e8730bc14390cf890bba8c97432807 100644 --- a/llap-server/src/java/org/apache/hadoop/hive/llap/daemon/services/impl/LlapWebServices.java +++ b/llap-server/src/java/org/apache/hadoop/hive/llap/daemon/services/impl/LlapWebServices.java @@ -83,6 +83,13 @@ public void serviceInit(Configuration conf) { HttpServer.Builder builder = new HttpServer.Builder("llap").setPort(this.port).setHost(bindAddress); builder.setConf(new HiveConf(conf, HiveConf.class)); + builder.setDisableDirListing(true); + if (conf.getBoolean(ConfVars.LLAP_DAEMON_WEB_XFRAME_ENABLED.varname, + ConfVars.LLAP_DAEMON_WEB_XFRAME_ENABLED.defaultBoolVal)) { + builder.configureXFrame(true).setXFrameOption( + conf.get(ConfVars.LLAP_DAEMON_WEB_XFRAME_VALUE.varname, + ConfVars.LLAP_DAEMON_WEB_XFRAME_VALUE.defaultStrVal)); + } if (UserGroupInformation.isSecurityEnabled()) { LOG.info("LLAP UI useSSL=" + this.useSSL + ", auto-auth/SPNEGO=" + this.useSPNEGO + ", port=" + this.port); diff --git a/llap-server/src/test/org/apache/hadoop/hive/llap/daemon/services/impl/TestLlapWebServices.java b/llap-server/src/test/org/apache/hadoop/hive/llap/daemon/services/impl/TestLlapWebServices.java index 698a56eb0bcd392eb8e890ce4b7e599b90d68412..5df6ea8215f36590499bb4c93f48688ae9eb9233 100644 --- a/llap-server/src/test/org/apache/hadoop/hive/llap/daemon/services/impl/TestLlapWebServices.java +++ b/llap-server/src/test/org/apache/hadoop/hive/llap/daemon/services/impl/TestLlapWebServices.java @@ -27,6 +27,12 @@ import java.net.HttpURLConnection; import java.net.URL; +import com.google.common.collect.ImmutableSet; + +import static java.net.HttpURLConnection.HTTP_FORBIDDEN; +import static java.net.HttpURLConnection.HTTP_OK; +import static org.junit.Assert.assertNotNull; + public class TestLlapWebServices { private static LlapWebServices llapWS = null; @@ -45,18 +51,43 @@ public static void beforeTests() throws Exception { @Test public void testContextRootUrlRewrite() throws Exception { String contextRootURL = "http://localhost:" + llapWSPort + "/"; - String contextRootContent = getURLResponseAsString(contextRootURL); + String contextRootContent = getURLResponseAsString(contextRootURL, HTTP_OK); String indexHtmlUrl = "http://localhost:" + llapWSPort + "/index.html"; - String indexHtmlContent = getURLResponseAsString(indexHtmlUrl); + String indexHtmlContent = getURLResponseAsString(indexHtmlUrl, HTTP_OK); Assert.assertEquals(contextRootContent, indexHtmlContent); } - private String getURLResponseAsString(String baseURL) throws IOException { + @Test + public void testDirListingDisabled() throws Exception { + for (String folder : ImmutableSet.of("images", "js", "css")) { + String url = "http://localhost:" + llapWSPort + "/" + folder; + getURLResponseAsString(url, HTTP_FORBIDDEN); + } + } + + @Test + public void testBaseUrlResponseHeader() throws Exception{ + String baseURL = "http://localhost:" + llapWSPort + "/"; + URL url = new URL(baseURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS"); + String xXSSProtectionHeader = conn.getHeaderField("X-XSS-Protection"); + String xContentTypeHeader = conn.getHeaderField("X-Content-Type-Options"); + assertNotNull(xfoHeader); + assertNotNull(xXSSProtectionHeader); + assertNotNull(xContentTypeHeader); + } + + private static String getURLResponseAsString(String baseURL, int expectedStatus) + throws IOException { URL url = new URL(baseURL); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + Assert.assertEquals(expectedStatus, conn.getResponseCode()); + if (expectedStatus != HTTP_OK) { + return null; + } StringWriter writer = new StringWriter(); IOUtils.copy(conn.getInputStream(), writer, "UTF-8"); return writer.toString(); diff --git a/service/src/test/org/apache/hive/service/server/TestHS2HttpServer.java b/service/src/test/org/apache/hive/service/server/TestHS2HttpServer.java index 3047443aebe1763e8ce8f70663d3712704b12e47..6c50e8170901609675ee4716ebfdf8c1754bc5a7 100644 --- a/service/src/test/org/apache/hive/service/server/TestHS2HttpServer.java +++ b/service/src/test/org/apache/hive/service/server/TestHS2HttpServer.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; + import org.apache.commons.io.IOUtils; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.conf.HiveConf.ConfVars; @@ -50,6 +51,8 @@ import java.util.HashMap; import java.util.List; +import static java.net.HttpURLConnection.HTTP_FORBIDDEN; +import static java.net.HttpURLConnection.HTTP_OK; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -110,7 +113,7 @@ public void testStackServlet() throws Exception { String baseURL = "http://localhost:" + webUIPort + "/stacks"; URL url = new URL(baseURL); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + Assert.assertEquals(HTTP_OK, conn.getResponseCode()); BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); boolean contents = false; @@ -136,17 +139,27 @@ public void testBaseUrlResponseHeader() throws Exception{ assertNotNull(xContentTypeHeader); } - private BufferedReader getReaderForUrl(String urlString) throws Exception { + @Test + public void testDirListingDisabledOnStaticServlet() throws Exception { + String url = "http://localhost:" + webUIPort + "/static"; + getReaderForUrl(url, HTTP_FORBIDDEN); + } + + private BufferedReader getReaderForUrl(String urlString, int expectedStatus) throws Exception { URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + Assert.assertEquals(expectedStatus, conn.getResponseCode()); + if (expectedStatus != HTTP_OK) { + return null; + } + BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); return reader; } private String readFromUrl(String urlString) throws Exception { - BufferedReader reader = getReaderForUrl(urlString); + BufferedReader reader = getReaderForUrl(urlString, HTTP_OK); StringBuilder response = new StringBuilder(); String inputLine; @@ -306,7 +319,7 @@ public void testConfStrippedFromWebUI() throws Exception { private String getURLResponseAsString(String baseURL) throws IOException { URL url = new URL(baseURL); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - Assert.assertEquals("Got an HTTP response code other thank OK.", HttpURLConnection.HTTP_OK, conn.getResponseCode()); + Assert.assertEquals("Got an HTTP response code other thank OK.", HTTP_OK, conn.getResponseCode()); StringWriter writer = new StringWriter(); IOUtils.copy(conn.getInputStream(), writer, "UTF-8"); return writer.toString();