You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by ji...@apache.org on 2016/07/12 21:43:44 UTC
[1/3] hadoop git commit: HADOOP-12964. Http server vulnerable to
clickjacking (haibochen via rkanter)
Repository: hadoop
Updated Branches:
refs/heads/branch-2.8 0a94c6d9d -> 35108025e
HADOOP-12964. Http server vulnerable to clickjacking (haibochen via rkanter)
(cherry picked from commit 042a3ae960883c263adc76f16d0ea3438d8b12be)
Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/2e2caeb5
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/2e2caeb5
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/2e2caeb5
Branch: refs/heads/branch-2.8
Commit: 2e2caeb50e0367926cf120ac28d5f0a65c61505c
Parents: 0a94c6d
Author: Robert Kanter <rk...@apache.org>
Authored: Tue Apr 12 14:40:43 2016 -0700
Committer: Jitendra Pandey <ji...@apache.org>
Committed: Tue Jul 12 14:37:57 2016 -0700
----------------------------------------------------------------------
.../org/apache/hadoop/http/HttpServer2.java | 29 ++++++++++++++++----
.../org/apache/hadoop/http/TestHttpServer.java | 10 +++++++
2 files changed, 33 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hadoop/blob/2e2caeb5/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
index 4ec620a..a905020 100644
--- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
+++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
@@ -55,10 +55,7 @@ import org.apache.hadoop.conf.ConfServlet;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.security.AuthenticationFilterInitializer;
-import org.apache.hadoop.security.authentication.util.FileSignerSecretProvider;
-import org.apache.hadoop.security.authentication.util.RandomSignerSecretProvider;
import org.apache.hadoop.security.authentication.util.SignerSecretProvider;
-import org.apache.hadoop.security.authentication.util.ZKSignerSecretProvider;
import org.apache.hadoop.security.ssl.SslSocketConnectorSecure;
import org.apache.hadoop.jmx.JMXJsonServlet;
import org.apache.hadoop.log.LogLevel;
@@ -98,8 +95,6 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.sun.jersey.spi.container.servlet.ServletContainer;
-import static org.apache.hadoop.security.authentication.server
- .AuthenticationFilter.*;
/**
* Create a Jetty embedded server to answer http requests. The primary goal is
* to serve up status information for the server. There are three contexts:
@@ -1152,9 +1147,11 @@ public final class HttpServer2 implements FilterContainer {
/**
* A Servlet input filter that quotes all HTML active characters in the
* parameter names and values. The goal is to quote the characters to make
- * all of the servlets resistant to cross-site scripting attacks.
+ * all of the servlets resistant to cross-site scripting attacks. It also
+ * sets X-FRAME-OPTIONS in the header to mitigate clickjacking attacks.
*/
public static class QuotingInputFilter implements Filter {
+ private static final XFrameOption X_FRAME_OPTION = XFrameOption.SAMEORIGIN;
private FilterConfig config;
public static class RequestQuoter extends HttpServletRequestWrapper {
@@ -1274,6 +1271,7 @@ public final class HttpServer2 implements FilterContainer {
} else if (mime.startsWith("application/xml")) {
httpResponse.setContentType("text/xml; charset=utf-8");
}
+ httpResponse.addHeader("X-FRAME-OPTIONS", X_FRAME_OPTION.toString());
chain.doFilter(quoted, httpResponse);
}
@@ -1290,4 +1288,23 @@ public final class HttpServer2 implements FilterContainer {
}
}
+
+ /**
+ * The X-FRAME-OPTIONS header in HTTP response to mitigate clickjacking
+ * attack.
+ */
+ public enum XFrameOption {
+ DENY("DENY") , SAMEORIGIN ("SAMEORIGIN"), ALLOWFROM ("ALLOW-FROM");
+
+ XFrameOption(String name) {
+ this.name = name;
+ }
+
+ private final String name;
+
+ @Override
+ public String toString() {
+ return this.name;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/2e2caeb5/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java
index 5b202da..9b27941 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java
@@ -235,6 +235,16 @@ public class TestHttpServer extends HttpServerFunctionalTest {
assertEquals("text/html; charset=utf-8", conn.getContentType());
}
+ @Test
+ public void testHttpResonseContainsXFrameOptions() throws IOException {
+ URL url = new URL(baseUrl, "");
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.connect();
+
+ String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS");
+ assertTrue("X-FRAME-OPTIONS is absent in the header", xfoHeader != null);
+ }
+
/**
* Dummy filter that mimics as an authentication filter. Obtains user identity
* from the request parameter user.name. Wraps around the request so that
---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org
[2/3] hadoop git commit: HADOOP-13352. Make X-FRAME-OPTIONS
configurable in HttpServer2. Contributed by Anu Engineer.
Posted by ji...@apache.org.
HADOOP-13352. Make X-FRAME-OPTIONS configurable in HttpServer2. Contributed by Anu Engineer.
Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/324923e1
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/324923e1
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/324923e1
Branch: refs/heads/branch-2.8
Commit: 324923e1bc14eb7f0b7e14b040ade8bda6901372
Parents: 2e2caeb
Author: Jitendra Pandey <ji...@apache.org>
Authored: Fri Jul 8 14:17:14 2016 -0700
Committer: Jitendra Pandey <ji...@apache.org>
Committed: Tue Jul 12 14:38:20 2016 -0700
----------------------------------------------------------------------
.../org/apache/hadoop/http/HttpServer2.java | 67 ++++++++++++++++++-
.../hadoop/http/HttpServerFunctionalTest.java | 19 ++++++
.../org/apache/hadoop/http/TestHttpServer.java | 68 ++++++++++++++++++--
3 files changed, 147 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hadoop/blob/324923e1/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
index a905020..2a46836 100644
--- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
+++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
@@ -137,6 +137,11 @@ public final class HttpServer2 implements FilterContainer {
static final String STATE_DESCRIPTION_ALIVE = " - alive";
static final String STATE_DESCRIPTION_NOT_LIVE = " - not live";
private final SignerSecretProvider secretProvider;
+ private XFrameOption xFrameOption;
+ private boolean xFrameOptionIsEnabled;
+ private static final String X_FRAME_VALUE = "xFrameOption";
+ private static final String X_FRAME_ENABLED = "X_FRAME_ENABLED";
+
/**
* Class to construct instances of HTTP server with specific options.
@@ -169,6 +174,9 @@ public final class HttpServer2 implements FilterContainer {
private String authFilterConfigurationPrefix = "hadoop.http.authentication.";
private String excludeCiphers;
+ private boolean xFrameEnabled;
+ private XFrameOption xFrameOption = XFrameOption.SAMEORIGIN;
+
public Builder setName(String name){
this.name = name;
return this;
@@ -277,6 +285,30 @@ public final class HttpServer2 implements FilterContainer {
return this;
}
+ /**
+ * Adds the ability to control X_FRAME_OPTIONS on HttpServer2.
+ * @param xFrameEnabled - True enables X_FRAME_OPTIONS false disables it.
+ * @return Builder.
+ */
+ public Builder configureXFrame(boolean xFrameEnabled) {
+ this.xFrameEnabled = xFrameEnabled;
+ return this;
+ }
+
+ /**
+ * Sets a valid X-Frame-option that can be used by HttpServer2.
+ * @param option - String DENY, SAMEORIGIN or ALLOW-FROM are the only valid
+ * options. Any other value will throw IllegalArgument
+ * Exception.
+ * @return Builder.
+ */
+ public Builder setXFrameOption(String option) {
+ this.xFrameOption = XFrameOption.getEnum(option);
+ return this;
+ }
+
+
+
public HttpServer2 build() throws IOException {
Preconditions.checkNotNull(name, "name is not set");
Preconditions.checkState(!endpoints.isEmpty(), "No endpoints specified");
@@ -343,6 +375,9 @@ public final class HttpServer2 implements FilterContainer {
this.webServer = new Server();
this.adminsAcl = b.adminsAcl;
this.webAppContext = createWebAppContext(b.name, b.conf, adminsAcl, appDir);
+ this.xFrameOptionIsEnabled = b.xFrameEnabled;
+ this.xFrameOption = b.xFrameOption;
+
try {
this.secretProvider =
constructSecretProvider(b, webAppContext.getServletContext());
@@ -399,7 +434,11 @@ public final class HttpServer2 implements FilterContainer {
addDefaultApps(contexts, appDir, conf);
- addGlobalFilter("safety", QuotingInputFilter.class.getName(), null);
+ Map<String, String> xFrameParams = new HashMap<>();
+ xFrameParams.put(X_FRAME_ENABLED,
+ String.valueOf(this.xFrameOptionIsEnabled));
+ xFrameParams.put(X_FRAME_VALUE, this.xFrameOption.toString());
+ addGlobalFilter("safety", QuotingInputFilter.class.getName(), xFrameParams);
final FilterInitializer[] initializers = getFilterInitializers(conf);
if (initializers != null) {
conf = new Configuration(conf);
@@ -1151,7 +1190,7 @@ public final class HttpServer2 implements FilterContainer {
* sets X-FRAME-OPTIONS in the header to mitigate clickjacking attacks.
*/
public static class QuotingInputFilter implements Filter {
- private static final XFrameOption X_FRAME_OPTION = XFrameOption.SAMEORIGIN;
+
private FilterConfig config;
public static class RequestQuoter extends HttpServletRequestWrapper {
@@ -1271,7 +1310,11 @@ public final class HttpServer2 implements FilterContainer {
} else if (mime.startsWith("application/xml")) {
httpResponse.setContentType("text/xml; charset=utf-8");
}
- httpResponse.addHeader("X-FRAME-OPTIONS", X_FRAME_OPTION.toString());
+
+ if(Boolean.valueOf(this.config.getInitParameter(X_FRAME_ENABLED))) {
+ httpResponse.addHeader("X-FRAME-OPTIONS",
+ this.config.getInitParameter(X_FRAME_VALUE));
+ }
chain.doFilter(quoted, httpResponse);
}
@@ -1306,5 +1349,23 @@ public final class HttpServer2 implements FilterContainer {
public String toString() {
return this.name;
}
+
+ /**
+ * We cannot use valueOf since the AllowFrom enum differs from its value
+ * Allow-From. This is a helper method that does exactly what valueof does,
+ * but allows us to handle the AllowFrom issue gracefully.
+ *
+ * @param value - String must be DENY, SAMEORIGIN or ALLOW-FROM.
+ * @return XFrameOption or throws IllegalException.
+ */
+ private static XFrameOption getEnum(String value) {
+ Preconditions.checkState(value != null && !value.isEmpty());
+ for (XFrameOption xoption : values()) {
+ if (value.equals(xoption.toString())) {
+ return xoption;
+ }
+ }
+ throw new IllegalArgumentException("Unexpected value in xFrameOption.");
+ }
}
}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/324923e1/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/HttpServerFunctionalTest.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/HttpServerFunctionalTest.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/HttpServerFunctionalTest.java
index faa27a7..f2d5541 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/HttpServerFunctionalTest.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/HttpServerFunctionalTest.java
@@ -169,6 +169,25 @@ public class HttpServerFunctionalTest extends Assert {
return localServerBuilder(webapp).setFindPort(true).setConf(conf).build();
}
+ /**
+ * Create a test server with xFrame options enabled.
+ * @param xFrameEnabled - true to enable xFrameSupport
+ * @param xFrameOptionValue - Option Value
+ * @param conf the configuration to use for the server
+ * @return
+ * @throws IOException
+ */
+ public static HttpServer2 createServer(boolean xFrameEnabled,
+ String xFrameOptionValue,
+ Configuration conf)
+ throws IOException {
+ return localServerBuilder(TEST).setFindPort(true)
+ .configureXFrame(xFrameEnabled)
+ .setXFrameOption(xFrameOptionValue)
+ .setConf(conf)
+ .build();
+ }
+
public static HttpServer2 createServer(String webapp, Configuration conf, AccessControlList adminsAcl)
throws IOException {
return localServerBuilder(webapp).setFindPort(true).setConf(conf).setACL(adminsAcl).build();
http://git-wip-us.apache.org/repos/asf/hadoop/blob/324923e1/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java
index 9b27941..d85935b 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java
@@ -31,7 +31,9 @@ import org.apache.hadoop.security.authorize.AccessControlList;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.mockito.Mockito;
import org.mockito.internal.util.reflection.Whitebox;
import org.mortbay.jetty.Connector;
@@ -68,6 +70,9 @@ public class TestHttpServer extends HttpServerFunctionalTest {
static final Log LOG = LogFactory.getLog(TestHttpServer.class);
private static HttpServer2 server;
private static final int MAX_THREADS = 10;
+
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
@SuppressWarnings("serial")
public static class EchoMapServlet extends HttpServlet {
@@ -236,15 +241,70 @@ public class TestHttpServer extends HttpServerFunctionalTest {
}
@Test
- public void testHttpResonseContainsXFrameOptions() throws IOException {
- URL url = new URL(baseUrl, "");
+ public void testHttpResonseContainsXFrameOptions() throws Exception {
+ validateXFrameOption(HttpServer2.XFrameOption.SAMEORIGIN);
+ }
+
+ @Test
+ public void testHttpResonseContainsDeny() throws Exception {
+ validateXFrameOption(HttpServer2.XFrameOption.DENY);
+ }
+
+ @Test
+ public void testHttpResonseContainsAllowFrom() throws Exception {
+ validateXFrameOption(HttpServer2.XFrameOption.ALLOWFROM);
+ }
+
+ private void validateXFrameOption(HttpServer2.XFrameOption option) throws
+ Exception {
+ Configuration conf = new Configuration();
+ boolean xFrameEnabled = true;
+ HttpServer2 httpServer = createServer(xFrameEnabled,
+ option.toString(), conf);
+ try {
+ HttpURLConnection conn = getHttpURLConnection(httpServer);
+ String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS");
+ assertTrue("X-FRAME-OPTIONS is absent in the header", xfoHeader != null);
+ assertTrue(xfoHeader.endsWith(option.toString()));
+ } finally {
+ httpServer.stop();
+ }
+ }
+
+ @Test
+ public void testHttpResonseDoesNotContainXFrameOptions() throws Exception {
+ Configuration conf = new Configuration();
+ boolean xFrameEnabled = false;
+ HttpServer2 httpServer = createServer(xFrameEnabled,
+ HttpServer2.XFrameOption.SAMEORIGIN.toString(), conf);
+ try {
+ HttpURLConnection conn = getHttpURLConnection(httpServer);
+ String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS");
+ assertTrue("Unexpected X-FRAME-OPTIONS in header", xfoHeader == null);
+ } finally {
+ httpServer.stop();
+ }
+ }
+
+ private HttpURLConnection getHttpURLConnection(HttpServer2 httpServer)
+ throws IOException {
+ httpServer.start();
+ URL newURL = getServerURL(httpServer);
+ URL url = new URL(newURL, "");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
+ return conn;
+ }
- String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS");
- assertTrue("X-FRAME-OPTIONS is absent in the header", xfoHeader != null);
+ @Test
+ public void testHttpResonseInvalidValueType() throws Exception {
+ Configuration conf = new Configuration();
+ boolean xFrameEnabled = true;
+ exception.expect(IllegalArgumentException.class);
+ createServer(xFrameEnabled, "Hadoop", conf);
}
+
/**
* Dummy filter that mimics as an authentication filter. Obtains user identity
* from the request parameter user.name. Wraps around the request so that
---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org
[3/3] hadoop git commit: HDFS-10579. HDFS web interfaces lack configs
for X-FRAME-OPTIONS protection. Contributed by Anu Engineer.
Posted by ji...@apache.org.
HDFS-10579. HDFS web interfaces lack configs for X-FRAME-OPTIONS protection. Contributed by Anu Engineer.
Conflicts:
hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/NameNodeHttpServer.java
Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/35108025
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/35108025
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/35108025
Branch: refs/heads/branch-2.8
Commit: 35108025e72d88784a7797f8d357d3cafc0c772b
Parents: 324923e
Author: Jitendra Pandey <ji...@apache.org>
Authored: Mon Jul 11 14:55:33 2016 -0700
Committer: Jitendra Pandey <ji...@apache.org>
Committed: Tue Jul 12 14:38:34 2016 -0700
----------------------------------------------------------------------
.../org/apache/hadoop/hdfs/DFSConfigKeys.java | 6 ++
.../server/datanode/web/DatanodeHttpServer.java | 10 ++
.../server/namenode/NameNodeHttpServer.java | 20 ++++
.../src/main/resources/hdfs-default.xml | 24 +++++
.../datanode/web/TestDatanodeHttpXFrame.java | 90 ++++++++++++++++++
.../namenode/TestNameNodeHttpServerXFrame.java | 97 ++++++++++++++++++++
6 files changed, 247 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hadoop/blob/35108025/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSConfigKeys.java
----------------------------------------------------------------------
diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSConfigKeys.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSConfigKeys.java
index 42f3ff7..5d924d2 100644
--- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSConfigKeys.java
+++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSConfigKeys.java
@@ -693,6 +693,12 @@ public class DFSConfigKeys extends CommonConfigurationKeys {
// Security-related configs
public static final String DFS_ENCRYPT_DATA_TRANSFER_KEY = "dfs.encrypt.data.transfer";
public static final boolean DFS_ENCRYPT_DATA_TRANSFER_DEFAULT = false;
+ public static final String DFS_XFRAME_OPTION_ENABLED = "dfs.xframe.enabled";
+ public static final boolean DFS_XFRAME_OPTION_ENABLED_DEFAULT = true;
+
+ public static final String DFS_XFRAME_OPTION_VALUE = "dfs.xframe.value";
+ public static final String DFS_XFRAME_OPTION_VALUE_DEFAULT = "SAMEORIGIN";
+
@Deprecated
public static final String DFS_ENCRYPT_DATA_TRANSFER_CIPHER_KEY_BITLENGTH_KEY =
HdfsClientConfigKeys.DFS_ENCRYPT_DATA_TRANSFER_CIPHER_KEY_BITLENGTH_KEY;
http://git-wip-us.apache.org/repos/asf/hadoop/blob/35108025/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/web/DatanodeHttpServer.java
----------------------------------------------------------------------
diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/web/DatanodeHttpServer.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/web/DatanodeHttpServer.java
index 0477028..caee6cc 100644
--- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/web/DatanodeHttpServer.java
+++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/web/DatanodeHttpServer.java
@@ -107,6 +107,16 @@ public class DatanodeHttpServer implements Closeable {
.addEndpoint(URI.create("http://localhost:0"))
.setFindPort(true);
+ final boolean xFrameEnabled = conf.getBoolean(
+ DFSConfigKeys.DFS_XFRAME_OPTION_ENABLED,
+ DFSConfigKeys.DFS_XFRAME_OPTION_ENABLED_DEFAULT);
+
+ final String xFrameOptionValue = conf.getTrimmed(
+ DFSConfigKeys.DFS_XFRAME_OPTION_VALUE,
+ DFSConfigKeys.DFS_XFRAME_OPTION_VALUE_DEFAULT);
+
+ builder.configureXFrame(xFrameEnabled).setXFrameOption(xFrameOptionValue);
+
this.infoServer = builder.build();
this.infoServer.addInternalServlet(null, "/streamFile/*", StreamFile.class);
http://git-wip-us.apache.org/repos/asf/hadoop/blob/35108025/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/NameNodeHttpServer.java
----------------------------------------------------------------------
diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/NameNodeHttpServer.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/NameNodeHttpServer.java
index a66eb96..fa93089 100644
--- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/NameNodeHttpServer.java
+++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/NameNodeHttpServer.java
@@ -29,6 +29,7 @@ import java.util.Map.Entry;
import javax.servlet.ServletContext;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdfs.DFSConfigKeys;
@@ -141,6 +142,16 @@ public class NameNodeHttpServer {
DFSConfigKeys.DFS_NAMENODE_KERBEROS_INTERNAL_SPNEGO_PRINCIPAL_KEY,
DFSConfigKeys.DFS_NAMENODE_KEYTAB_FILE_KEY);
+ final boolean xFrameEnabled = conf.getBoolean(
+ DFSConfigKeys.DFS_XFRAME_OPTION_ENABLED,
+ DFSConfigKeys.DFS_XFRAME_OPTION_ENABLED_DEFAULT);
+
+ final String xFrameOptionValue = conf.getTrimmed(
+ DFSConfigKeys.DFS_XFRAME_OPTION_VALUE,
+ DFSConfigKeys.DFS_XFRAME_OPTION_VALUE_DEFAULT);
+
+ builder.configureXFrame(xFrameEnabled).setXFrameOption(xFrameOptionValue);
+
httpServer = builder.build();
if (policy.isHttpsEnabled()) {
@@ -326,4 +337,13 @@ public class NameNodeHttpServer {
ServletContext context) {
return (StartupProgress)context.getAttribute(STARTUP_PROGRESS_ATTRIBUTE_KEY);
}
+
+ /**
+ * Returns the httpServer.
+ * @return HttpServer2
+ */
+ @VisibleForTesting
+ public HttpServer2 getHttpServer() {
+ return httpServer;
+ }
}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/35108025/hadoop-hdfs-project/hadoop-hdfs/src/main/resources/hdfs-default.xml
----------------------------------------------------------------------
diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/resources/hdfs-default.xml b/hadoop-hdfs-project/hadoop-hdfs/src/main/resources/hdfs-default.xml
index 1a38ec6..3847d06 100644
--- a/hadoop-hdfs-project/hadoop-hdfs/src/main/resources/hdfs-default.xml
+++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/resources/hdfs-default.xml
@@ -2904,6 +2904,30 @@
</description>
</property>
+ <property>
+ <name>dfs.xframe.enabled</name>
+ <value>true</value>
+ <description>
+ If true, then enables protection against clickjacking by returning
+ X_FRAME_OPTIONS header value set to SAMEORIGIN.
+ Clickjacking protection prevents an attacker from using transparent or
+ opaque layers to trick a user into clicking on a button
+ or link on another page.
+ </description>
+ </property>
+
+ <property>
+ <name>dfs.xframe.value</name>
+ <value>SAMEORIGIN</value>
+ <description>
+ This configration value allows user to specify the value for the
+ X-FRAME-OPTIONS. The possible values for this field are
+ DENY, SAMEORIGIN and ALLOW-FROM. Any other value will throw an
+ exception when namenode and datanodes are starting up.
+ </description>
+ </property>
+
+
<property>
<name>dfs.http.client.retry.policy.enabled</name>
<value>false</value>
http://git-wip-us.apache.org/repos/asf/hadoop/blob/35108025/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/datanode/web/TestDatanodeHttpXFrame.java
----------------------------------------------------------------------
diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/datanode/web/TestDatanodeHttpXFrame.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/datanode/web/TestDatanodeHttpXFrame.java
new file mode 100644
index 0000000..9ecd8ea
--- /dev/null
+++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/datanode/web/TestDatanodeHttpXFrame.java
@@ -0,0 +1,90 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.hdfs.server.datanode.web;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hdfs.DFSConfigKeys;
+import org.apache.hadoop.hdfs.HdfsConfiguration;
+import org.apache.hadoop.hdfs.MiniDFSCluster;
+import org.apache.hadoop.hdfs.server.datanode.DataNode;
+import org.apache.hadoop.http.HttpServer2;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+/**
+ * Test that X-Frame-Options works correctly with DatanodeHTTPServer.
+ */
+public class TestDatanodeHttpXFrame {
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ @Test
+ public void testDataNodeXFrameOptionsEnabled() throws Exception {
+ boolean xFrameEnabled = true;
+ MiniDFSCluster cluster = createCluster(xFrameEnabled, null);
+ HttpURLConnection conn = getConn(cluster);
+ String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS");
+ Assert.assertTrue("X-FRAME-OPTIONS is absent in the header",
+ xfoHeader != null);
+ Assert.assertTrue(xfoHeader.endsWith(HttpServer2.XFrameOption
+ .SAMEORIGIN.toString()));
+ }
+
+ @Test
+ public void testNameNodeXFrameOptionsDisabled() throws Exception {
+ boolean xFrameEnabled = false;
+ MiniDFSCluster cluster = createCluster(xFrameEnabled, null);
+ HttpURLConnection conn = getConn(cluster);
+ String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS");
+ Assert.assertTrue("unexpected X-FRAME-OPTION in header", xfoHeader == null);
+ }
+
+ @Test
+ public void testDataNodeXFramewithInvalidOptions() throws Exception {
+ exception.expect(IllegalArgumentException.class);
+ createCluster(false, "Hadoop");
+ }
+
+ private MiniDFSCluster createCluster(boolean enabled, String
+ value) throws IOException {
+ Configuration conf = new HdfsConfiguration();
+ conf.setBoolean(DFSConfigKeys.DFS_XFRAME_OPTION_ENABLED, enabled);
+ if (value != null) {
+ conf.set(DFSConfigKeys.DFS_XFRAME_OPTION_VALUE, value);
+ }
+ MiniDFSCluster cluster =
+ new MiniDFSCluster.Builder(conf).numDataNodes(1).build();
+ cluster.waitActive();
+ return cluster;
+ }
+
+ private HttpURLConnection getConn(MiniDFSCluster cluster)
+ throws IOException {
+ DataNode datanode = cluster.getDataNodes().get(0);
+ URL newURL = new URL("http://localhost:" + datanode.getInfoPort());
+ HttpURLConnection conn = (HttpURLConnection) newURL.openConnection();
+ conn.connect();
+ return conn;
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/35108025/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestNameNodeHttpServerXFrame.java
----------------------------------------------------------------------
diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestNameNodeHttpServerXFrame.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestNameNodeHttpServerXFrame.java
new file mode 100644
index 0000000..947e951
--- /dev/null
+++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestNameNodeHttpServerXFrame.java
@@ -0,0 +1,97 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.hdfs.server.namenode;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hdfs.DFSConfigKeys;
+import org.apache.hadoop.hdfs.HdfsConfiguration;
+import org.apache.hadoop.http.HttpServer2;
+import org.apache.hadoop.net.NetUtils;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * A class to test the XFrameoptions of Namenode HTTP Server. We are not reusing
+ * the TestNameNodeHTTPServer since it is a parameterized class and these
+ * following tests will run multiple times doing the same thing, if we had the
+ * code in that classs.
+ */
+public class TestNameNodeHttpServerXFrame {
+
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ public static URL getServerURL(HttpServer2 server)
+ throws MalformedURLException {
+ Assert.assertNotNull("No server", server);
+ return new URL("http://"
+ + NetUtils.getHostPortString(server.getConnectorAddress(0)));
+ }
+
+ @Test
+ public void testNameNodeXFrameOptionsEnabled() throws Exception {
+ HttpURLConnection conn = createServerwithXFrame(true, null);
+ String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS");
+ Assert.assertTrue("X-FRAME-OPTIONS is absent in the header",
+ xfoHeader != null);
+ Assert.assertTrue(xfoHeader.endsWith(HttpServer2.XFrameOption
+ .SAMEORIGIN.toString()));
+ }
+
+ @Test
+ public void testNameNodeXFrameOptionsDisabled() throws Exception {
+ HttpURLConnection conn = createServerwithXFrame(false, null);
+ String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS");
+ Assert.assertTrue("unexpected X-FRAME-OPTION in header", xfoHeader == null);
+ }
+
+ @Test
+ public void testNameNodeXFrameOptionsIllegalOption() throws Exception {
+ exception.expect(IllegalArgumentException.class);
+ createServerwithXFrame(true, "hadoop");
+ }
+
+ private HttpURLConnection createServerwithXFrame(boolean enabled, String
+ value) throws IOException {
+ Configuration conf = new HdfsConfiguration();
+ conf.set(DFSConfigKeys.DFS_NAMENODE_HTTPS_ADDRESS_KEY, "localhost:0");
+ conf.setBoolean(DFSConfigKeys.DFS_XFRAME_OPTION_ENABLED, enabled);
+ if (value != null) {
+ conf.set(DFSConfigKeys.DFS_XFRAME_OPTION_VALUE, value);
+
+ }
+ InetSocketAddress addr = InetSocketAddress.createUnresolved("localhost", 0);
+ NameNodeHttpServer server = null;
+
+ server = new NameNodeHttpServer(conf, null, addr);
+ server.start();
+
+ URL url = getServerURL(server.getHttpServer());
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.connect();
+ return conn;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org