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