You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2015/12/09 20:23:12 UTC

ambari git commit: AMBARI-14292. Security filters set the X-Frame-Options header value properly for view resources api calls (Laszlo Puskas via rlevas)

Repository: ambari
Updated Branches:
  refs/heads/trunk 89ef3b5c7 -> 05c8eb5f6


AMBARI-14292. Security filters set the X-Frame-Options header value properly for view resources api calls (Laszlo Puskas via rlevas)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/05c8eb5f
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/05c8eb5f
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/05c8eb5f

Branch: refs/heads/trunk
Commit: 05c8eb5f61ec70cd15e0772290a2e44a6502a8c0
Parents: 89ef3b5
Author: Laszlo Puskas <lp...@hortonworks.com>
Authored: Wed Dec 9 14:22:59 2015 -0500
Committer: Robert Levas <rl...@hortonworks.com>
Committed: Wed Dec 9 14:23:09 2015 -0500

----------------------------------------------------------------------
 .../ambari/server/controller/AmbariServer.java  |  6 ++
 .../security/AbstractSecurityHeaderFilter.java  | 68 +++++++++++++-------
 .../AmbariServerSecurityHeaderFilter.java       | 17 ++++-
 .../AmbariViewsSecurityHeaderFilter.java        | 12 +++-
 .../AbstractSecurityHeaderFilterTest.java       | 33 ++++++----
 .../AmbariServerSecurityHeaderFilterTest.java   | 13 +++-
 .../AmbariViewsSecurityHeaderFilterTest.java    | 15 ++++-
 7 files changed, 124 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/05c8eb5f/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 2909c31..c6f90c0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -85,6 +85,7 @@ import org.apache.ambari.server.resources.ResourceManager;
 import org.apache.ambari.server.resources.api.rest.GetResource;
 import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
 import org.apache.ambari.server.security.AmbariServerSecurityHeaderFilter;
+import org.apache.ambari.server.security.AmbariViewsSecurityHeaderFilter;
 import org.apache.ambari.server.security.CertificateManager;
 import org.apache.ambari.server.security.SecurityFilter;
 import org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter;
@@ -328,6 +329,11 @@ public class AmbariServer {
       // Conditionally adds security-related headers to all HTTP responses.
       root.addFilter(new FilterHolder(injector.getInstance(AmbariServerSecurityHeaderFilter.class)), "/*", DISPATCHER_TYPES);
 
+      // The security header filter - conditionally adds security-related headers to the HTTP response for Ambari Views
+      // requests.
+      root.addFilter(new FilterHolder(injector.getInstance(AmbariViewsSecurityHeaderFilter.class)), "/api/v1/views/*",
+          DISPATCHER_TYPES);
+
       // session-per-request strategy for api
       root.addFilter(new FilterHolder(injector.getInstance(AmbariPersistFilter.class)), "/api/*", DISPATCHER_TYPES);
       root.addFilter(new FilterHolder(new MethodOverrideFilter()), "/api/*", DISPATCHER_TYPES);

http://git-wip-us.apache.org/repos/asf/ambari/blob/05c8eb5f/ambari-server/src/main/java/org/apache/ambari/server/security/AbstractSecurityHeaderFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/AbstractSecurityHeaderFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/AbstractSecurityHeaderFilter.java
index 36f691c..10aa6ea 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/AbstractSecurityHeaderFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/AbstractSecurityHeaderFilter.java
@@ -18,11 +18,7 @@
 
 package org.apache.ambari.server.security;
 
-import com.google.inject.Inject;
-import org.apache.ambari.server.configuration.Configuration;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.io.IOException;
 
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
@@ -31,7 +27,13 @@ import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
+
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
 
 /**
  * AbstractSecurityHeaderFilter is an abstract class used to help add security-related headers to
@@ -56,6 +58,11 @@ public abstract class AbstractSecurityHeaderFilter implements Filter {
    * The logger.
    */
   private final static Logger LOG = LoggerFactory.getLogger(AbstractSecurityHeaderFilter.class);
+
+  /**
+   * Signals whether subsequent filters are allowed to override security headers
+   */
+  protected final static String DENY_HEADER_OVERRIDES_FLAG = "deny.header.overrides.flag";
   /**
    * The Configuration object used to determine how Ambari is configured
    */
@@ -95,28 +102,21 @@ public abstract class AbstractSecurityHeaderFilter implements Filter {
   @Override
   public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
 
-    if (servletResponse instanceof HttpServletResponse) {
-      HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
-      // Conditionally set the Strict-Transport-Security HTTP response header if SSL is enabled and
-      // a value is supplied
-      if (sslEnabled && !StringUtils.isEmpty(strictTransportSecurity)) {
-        httpServletResponse.setHeader(STRICT_TRANSPORT_HEADER, strictTransportSecurity);
-      }
-
-      // Conditionally set the X-Frame-Options HTTP response header if a value is supplied
-      if (!StringUtils.isEmpty(xFrameOptionsHeader)) {
-        httpServletResponse.setHeader(X_FRAME_OPTIONS_HEADER, xFrameOptionsHeader);
-      }
-
-      // Conditionally set the X-XSS-Protection HTTP response header if a value is supplied
-      if (!StringUtils.isEmpty(xXSSProtectionHeader)) {
-        httpServletResponse.setHeader(X_XSS_PROTECTION_HEADER, xXSSProtectionHeader);
-      }
+    if (checkPrerequisites(servletRequest)) {
+      doFilterInternal(servletRequest, servletResponse);
     }
 
     filterChain.doFilter(servletRequest, servletResponse);
   }
 
+  /**
+   * Checks whether the security headers need to be set, if so signals it in a request parameter.
+   *
+   * @param servletRequest the incoming request
+   * @return true if headers need to be set, false otherwise
+   */
+  protected abstract boolean checkPrerequisites(ServletRequest servletRequest);
+
   @Override
   public void destroy() {
     LOG.debug("Destroying {}", this.getClass().getName());
@@ -140,4 +140,26 @@ public abstract class AbstractSecurityHeaderFilter implements Filter {
   protected void setxXSSProtectionHeader(String xXSSProtectionHeader) {
     this.xXSSProtectionHeader = xXSSProtectionHeader;
   }
+
+  private void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse) {
+    if (servletResponse instanceof HttpServletResponse) {
+      HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
+      // Conditionally set the Strict-Transport-Security HTTP response header if SSL is enabled and
+      // a value is supplied
+      if (sslEnabled && !StringUtils.isEmpty(strictTransportSecurity)) {
+        httpServletResponse.setHeader(STRICT_TRANSPORT_HEADER, strictTransportSecurity);
+      }
+
+      if (!StringUtils.isEmpty(xFrameOptionsHeader)) {
+        // perform filter specific logic related to the X-Frame-Options HTTP response header
+        httpServletResponse.setHeader(X_FRAME_OPTIONS_HEADER, xFrameOptionsHeader);
+      }
+
+      // Conditionally set the X-XSS-Protection HTTP response header if a value is supplied
+      if (!StringUtils.isEmpty(xXSSProtectionHeader)) {
+        httpServletResponse.setHeader(X_XSS_PROTECTION_HEADER, xXSSProtectionHeader);
+      }
+    }
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/05c8eb5f/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariServerSecurityHeaderFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariServerSecurityHeaderFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariServerSecurityHeaderFilter.java
index 86c28ea..b40953b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariServerSecurityHeaderFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariServerSecurityHeaderFilter.java
@@ -18,9 +18,12 @@
 
 package org.apache.ambari.server.security;
 
-import com.google.inject.Singleton;
+import javax.servlet.ServletRequest;
+
 import org.apache.ambari.server.configuration.Configuration;
 
+import com.google.inject.Singleton;
+
 /**
  * AmbariServerSecurityHeaderFilter adds security-related headers to HTTP response messages for Ambari Server UI
  */
@@ -28,10 +31,22 @@ import org.apache.ambari.server.configuration.Configuration;
 public class AmbariServerSecurityHeaderFilter extends AbstractSecurityHeaderFilter {
 
   @Override
+  protected boolean checkPrerequisites(ServletRequest servletRequest) {
+    boolean retVal = false;
+    if (null == servletRequest.getAttribute(AbstractSecurityHeaderFilter.DENY_HEADER_OVERRIDES_FLAG)) {
+      retVal = true;
+    } else {
+      servletRequest.removeAttribute(AbstractSecurityHeaderFilter.DENY_HEADER_OVERRIDES_FLAG);
+    }
+    return retVal;
+  }
+
+  @Override
   protected void processConfig(Configuration configuration) {
     setSslEnabled(configuration.getApiSSLAuthentication());
     setStrictTransportSecurity(configuration.getStrictTransportSecurityHTTPResponseHeader());
     setxFrameOptionsHeader(configuration.getXFrameOptionsHTTPResponseHeader());
     setxXSSProtectionHeader(configuration.getXXSSProtectionHTTPResponseHeader());
   }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/05c8eb5f/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariViewsSecurityHeaderFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariViewsSecurityHeaderFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariViewsSecurityHeaderFilter.java
index 63137fb..5bff4e3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariViewsSecurityHeaderFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariViewsSecurityHeaderFilter.java
@@ -18,15 +18,25 @@
 
 package org.apache.ambari.server.security;
 
-import com.google.inject.Singleton;
+import javax.servlet.ServletRequest;
+
 import org.apache.ambari.server.configuration.Configuration;
 
+import com.google.inject.Singleton;
+
 /**
  * AmbariViewsSecurityHeaderFilter adds security-related headers to HTTP response messages for Ambari Views
  */
 @Singleton
 public class AmbariViewsSecurityHeaderFilter extends AbstractSecurityHeaderFilter {
 
+
+  @Override
+  protected boolean checkPrerequisites(ServletRequest servletRequest) {
+    servletRequest.setAttribute(AbstractSecurityHeaderFilter.DENY_HEADER_OVERRIDES_FLAG, "true");
+    return true;
+  }
+
   @Override
   protected void processConfig(Configuration configuration) {
     setSslEnabled(configuration.getApiSSLAuthentication());

http://git-wip-us.apache.org/repos/asf/ambari/blob/05c8eb5f/ambari-server/src/test/java/org/apache/ambari/server/security/AbstractSecurityHeaderFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/AbstractSecurityHeaderFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/AbstractSecurityHeaderFilterTest.java
index 3481092..48231b7 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/AbstractSecurityHeaderFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/AbstractSecurityHeaderFilterTest.java
@@ -18,10 +18,15 @@
 
 package org.apache.ambari.server.security;
 
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import junit.framework.Assert;
+import java.io.File;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.state.stack.OsFamily;
 import org.easymock.EasyMockSupport;
@@ -31,13 +36,11 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.File;
-import java.util.Map;
-import java.util.Properties;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+import junit.framework.Assert;
 
 import static org.easymock.EasyMock.expectLastCall;
 
@@ -56,6 +59,8 @@ public abstract class AbstractSecurityHeaderFilterTest extends EasyMockSupport {
     this.defatulPropertyValueMap = defatulPropertyValueMap;
   }
 
+  protected abstract void expectHttpServletRequestMock(HttpServletRequest request);
+
   @Before
   public void setUp() throws Exception {
     temporaryFolder.create();
@@ -83,6 +88,7 @@ public abstract class AbstractSecurityHeaderFilterTest extends EasyMockSupport {
     FilterConfig filterConfig = createNiceMock(FilterConfig.class);
 
     HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class);
+    expectHttpServletRequestMock(servletRequest);
 
     HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class);
     servletResponse.setHeader(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, defatulPropertyValueMap.get(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER));
@@ -126,6 +132,7 @@ public abstract class AbstractSecurityHeaderFilterTest extends EasyMockSupport {
     FilterConfig filterConfig = createNiceMock(FilterConfig.class);
 
     HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class);
+    expectHttpServletRequestMock(servletRequest);
 
     HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class);
     servletResponse.setHeader(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER, defatulPropertyValueMap.get(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER));
@@ -173,6 +180,7 @@ public abstract class AbstractSecurityHeaderFilterTest extends EasyMockSupport {
     FilterConfig filterConfig = createNiceMock(FilterConfig.class);
 
     HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class);
+    expectHttpServletRequestMock(servletRequest);
 
     HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class);
     servletResponse.setHeader(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, "custom2");
@@ -219,6 +227,7 @@ public abstract class AbstractSecurityHeaderFilterTest extends EasyMockSupport {
     FilterConfig filterConfig = createNiceMock(FilterConfig.class);
 
     HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class);
+    expectHttpServletRequestMock(servletRequest);
 
     HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class);
     servletResponse.setHeader(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER, "custom1");
@@ -266,6 +275,7 @@ public abstract class AbstractSecurityHeaderFilterTest extends EasyMockSupport {
     FilterConfig filterConfig = createNiceMock(FilterConfig.class);
 
     HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class);
+    expectHttpServletRequestMock(servletRequest);
 
     HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class);
 
@@ -308,6 +318,7 @@ public abstract class AbstractSecurityHeaderFilterTest extends EasyMockSupport {
     FilterConfig filterConfig = createNiceMock(FilterConfig.class);
 
     HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class);
+    expectHttpServletRequestMock(servletRequest);
 
     HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/05c8eb5f/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariServerSecurityHeaderFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariServerSecurityHeaderFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariServerSecurityHeaderFilterTest.java
index 0e3313e..e6a8eff 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariServerSecurityHeaderFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariServerSecurityHeaderFilterTest.java
@@ -18,12 +18,16 @@
 
 package org.apache.ambari.server.security;
 
-import org.apache.ambari.server.configuration.Configuration;
-
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.ambari.server.configuration.Configuration;
+
+import static org.easymock.EasyMock.expect;
+
 public class AmbariServerSecurityHeaderFilterTest extends AbstractSecurityHeaderFilterTest {
 
   private static final Map<String, String> PROPERTY_NAME_MAP;
@@ -48,4 +52,9 @@ public class AmbariServerSecurityHeaderFilterTest extends AbstractSecurityHeader
   public AmbariServerSecurityHeaderFilterTest() {
     super(AmbariServerSecurityHeaderFilter.class, PROPERTY_NAME_MAP, DEFAULT_PROPERTY_VALUE_MAP);
   }
+
+  @Override
+  protected void expectHttpServletRequestMock(HttpServletRequest request) {
+    expect(request.getAttribute(AbstractSecurityHeaderFilter.DENY_HEADER_OVERRIDES_FLAG)).andReturn(null);
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/05c8eb5f/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariViewsSecurityHeaderFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariViewsSecurityHeaderFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariViewsSecurityHeaderFilterTest.java
index d760962..a2882ae 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariViewsSecurityHeaderFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariViewsSecurityHeaderFilterTest.java
@@ -18,12 +18,16 @@
 
 package org.apache.ambari.server.security;
 
-import org.apache.ambari.server.configuration.Configuration;
-
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.ambari.server.configuration.Configuration;
+
+import static org.easymock.EasyMock.expectLastCall;
+
 public class AmbariViewsSecurityHeaderFilterTest extends AbstractSecurityHeaderFilterTest {
 
   private static final Map<String, String> PROPERTY_NAME_MAP;
@@ -49,4 +53,11 @@ public class AmbariViewsSecurityHeaderFilterTest extends AbstractSecurityHeaderF
   public AmbariViewsSecurityHeaderFilterTest() {
     super(AmbariViewsSecurityHeaderFilter.class, PROPERTY_NAME_MAP, DEFAULT_PROPERTY_VALUE_MAP);
   }
+
+  @Override
+  protected void expectHttpServletRequestMock(HttpServletRequest request) {
+    request.setAttribute(AbstractSecurityHeaderFilter.DENY_HEADER_OVERRIDES_FLAG, "true");
+    expectLastCall();
+
+  }
 }
\ No newline at end of file