Repository: ambari Updated Branches: refs/heads/trunk 92915952a -> 31542ae31
AMBARI-13351. Security-related HTTP headers should be set separately for Ambari Views then for Ambari server UI (rlevas) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/31542ae3 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/31542ae3 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/31542ae3 Branch: refs/heads/trunk Commit: 31542ae31be265e0fa309e3a33bccccc91b4cb90 Parents: 9291595 Author: Robert Levas <[email protected]> Authored: Tue Oct 13 22:23:25 2015 -0400 Committer: Robert Levas <[email protected]> Committed: Tue Oct 13 22:25:15 2015 -0400 ---------------------------------------------------------------------- ambari-server/conf/unix/ambari.properties | 9 +- ambari-server/conf/windows/ambari.properties | 9 +- .../server/configuration/Configuration.java | 65 +++- .../server/controller/AmbariHandlerList.java | 8 +- .../ambari/server/controller/AmbariServer.java | 4 +- .../security/AbstractSecurityHeaderFilter.java | 143 ++++++++ .../AmbariServerSecurityHeaderFilter.java | 37 +++ .../AmbariViewsSecurityHeaderFilter.java | 37 +++ .../server/security/SecurityHeaderFilter.java | 121 ------- .../controller/AmbariHandlerListTest.java | 8 +- .../AbstractSecurityHeaderFilterTest.java | 329 +++++++++++++++++++ .../AmbariServerSecurityHeaderFilterTest.java | 51 +++ .../AmbariViewsSecurityHeaderFilterTest.java | 52 +++ .../security/SecurityHeaderFilterTest.java | 318 ------------------ 14 files changed, 734 insertions(+), 457 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/ambari-server/conf/unix/ambari.properties ---------------------------------------------------------------------- diff --git a/ambari-server/conf/unix/ambari.properties b/ambari-server/conf/unix/ambari.properties index 68cbf65..53af453 100644 --- a/ambari-server/conf/unix/ambari.properties +++ b/ambari-server/conf/unix/ambari.properties @@ -97,7 +97,12 @@ skip.service.checks=false rolling.upgrade.min.stack=HDP-2.2 rolling.upgrade.max.stack= -# HTTP Header settings +# HTTP Header settings for Ambari Server UI http.strict-transport-security=max-age=31536000 http.x-xss-protection=1; mode=block -http.x-frame-options=DENY \ No newline at end of file +http.x-frame-options=DENY + +# HTTP Header settings for Ambari Views +views.http.strict-transport-security=max-age=31536000 +views.http.x-xss-protection=1; mode=block +views.http.x-frame-options=SAMEORIGIN \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/ambari-server/conf/windows/ambari.properties ---------------------------------------------------------------------- diff --git a/ambari-server/conf/windows/ambari.properties b/ambari-server/conf/windows/ambari.properties index 6a98a63..570e904 100644 --- a/ambari-server/conf/windows/ambari.properties +++ b/ambari-server/conf/windows/ambari.properties @@ -87,7 +87,12 @@ ulimit.open.files=10000 ##server.jdbc.user.passwd=etc\\ambari-server\\conf\\password.dat ##server.jdbc.user.name=ambari -# HTTP Header settings +# HTTP Header settings for Ambari Server UI http.strict-transport-security=max-age=31536000 http.x-xss-protection=1; mode=block -http.x-frame-options=DENY \ No newline at end of file +http.x-frame-options=DENY + +# HTTP Header settings for Ambari Views +views.http.strict-transport-security=max-age=31536000 +views.http.x-xss-protection=1; mode=block +views.http.x-frame-options=SAMEORIGIN \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java index c653e1b..23f9803fe 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java @@ -458,7 +458,7 @@ public class Configuration { public static final String ALERTS_EXECUTION_SCHEDULER_THREADS_DEFAULT = "2"; /** - * For HTTP Response header configuration + * For HTTP Response header configuration for Ambari Server UI */ public static final String HTTP_STRICT_TRANSPORT_HEADER_VALUE_KEY = "http.strict-transport-security"; public static final String HTTP_STRICT_TRANSPORT_HEADER_VALUE_DEFAULT = "max-age=31536000"; @@ -467,6 +467,16 @@ public class Configuration { public static final String HTTP_X_XSS_PROTECTION_HEADER_VALUE_KEY = "http.x-xss-protection"; public static final String HTTP_X_XSS_PROTECTION_HEADER_VALUE_DEFAULT = "1; mode=block"; + /** + * For HTTP Response header configuration for Ambari Views + */ + public static final String VIEWS_HTTP_STRICT_TRANSPORT_HEADER_VALUE_KEY = "views.http.strict-transport-security"; + public static final String VIEWS_HTTP_STRICT_TRANSPORT_HEADER_VALUE_DEFAULT = "max-age=31536000"; + public static final String VIEWS_HTTP_X_FRAME_OPTIONS_HEADER_VALUE_KEY = "views.http.x-frame-options"; + public static final String VIEWS_HTTP_X_FRAME_OPTIONS_HEADER_VALUE_DEFAULT = "SAMEORIGIN"; + public static final String VIEWS_HTTP_X_XSS_PROTECTION_HEADER_VALUE_KEY = "views.http.x-xss-protection"; + public static final String VIEWS_HTTP_X_XSS_PROTECTION_HEADER_VALUE_DEFAULT = "1; mode=block"; + private static final Logger LOG = LoggerFactory.getLogger( Configuration.class); @@ -1035,7 +1045,7 @@ public class Configuration { } /** - * Get the value that should be set for the <code>Strict-Transport-Security</code> HTTP response header. + * Get the value that should be set for the <code>Strict-Transport-Security</code> HTTP response header for Ambari Server UI. * <p/> * By default this will be <code>max-age=31536000; includeSubDomains</code>. For example: * <p/> @@ -1052,7 +1062,7 @@ public class Configuration { } /** - * Get the value that should be set for the <code>X-Frame-Options</code> HTTP response header. + * Get the value that should be set for the <code>X-Frame-Options</code> HTTP response header for Ambari Server UI. * <p/> * By default this will be <code>DENY</code>. For example: * <p/> @@ -1067,7 +1077,7 @@ public class Configuration { } /** - * Get the value that should be set for the <code>X-XSS-Protection</code> HTTP response header. + * Get the value that should be set for the <code>X-XSS-Protection</code> HTTP response header for Ambari Server UI. * <p/> * By default this will be <code>1; mode=block</code>. For example: * <p/> @@ -1082,6 +1092,53 @@ public class Configuration { } /** + * Get the value that should be set for the <code>Strict-Transport-Security</code> HTTP response header for Ambari Views. + * <p/> + * By default this will be <code>max-age=31536000; includeSubDomains</code>. For example: + * <p/> + * <code> + * Strict-Transport-Security: max-age=31536000; includeSubDomains + * </code> + * <p/> + * This value may be ignored when {@link #getApiSSLAuthentication()} is <code>false</code>. + * + * @return the Strict-Transport-Security value - null or "" indicates that the value is not set + */ + public String getViewsStrictTransportSecurityHTTPResponseHeader() { + return properties.getProperty(VIEWS_HTTP_STRICT_TRANSPORT_HEADER_VALUE_KEY, VIEWS_HTTP_STRICT_TRANSPORT_HEADER_VALUE_DEFAULT); + } + + /** + * Get the value that should be set for the <code>X-Frame-Options</code> HTTP response header for Ambari Views. + * <p/> + * By default this will be <code>DENY</code>. For example: + * <p/> + * <code> + * X-Frame-Options: DENY + * </code> + * + * @return the X-Frame-Options value - null or "" indicates that the value is not set + */ + public String getViewsXFrameOptionsHTTPResponseHeader() { + return properties.getProperty(VIEWS_HTTP_X_FRAME_OPTIONS_HEADER_VALUE_KEY, VIEWS_HTTP_X_FRAME_OPTIONS_HEADER_VALUE_DEFAULT); + } + + /** + * Get the value that should be set for the <code>X-XSS-Protection</code> HTTP response header for Ambari Views. + * <p/> + * By default this will be <code>1; mode=block</code>. For example: + * <p/> + * <code> + * X-XSS-Protection: 1; mode=block + * </code> + * + * @return the X-XSS-Protection value - null or "" indicates that the value is not set + */ + public String getViewsXXSSProtectionHTTPResponseHeader() { + return properties.getProperty(VIEWS_HTTP_X_XSS_PROTECTION_HEADER_VALUE_KEY, VIEWS_HTTP_X_XSS_PROTECTION_HEADER_VALUE_DEFAULT); + } + + /** * Check to see if two-way SSL auth should be used between server and agents * or not * http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariHandlerList.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariHandlerList.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariHandlerList.java index 1265b6a..b33d977 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariHandlerList.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariHandlerList.java @@ -20,7 +20,7 @@ package org.apache.ambari.server.controller; import org.apache.ambari.server.api.AmbariPersistFilter; import org.apache.ambari.server.orm.entities.ViewEntity; import org.apache.ambari.server.orm.entities.ViewInstanceEntity; -import org.apache.ambari.server.security.SecurityHeaderFilter; +import org.apache.ambari.server.security.AmbariViewsSecurityHeaderFilter; import org.apache.ambari.server.view.ViewContextImpl; import org.apache.ambari.server.view.ViewInstanceHandlerList; import org.apache.ambari.server.view.ViewRegistry; @@ -95,10 +95,10 @@ public class AmbariHandlerList extends HandlerCollection implements ViewInstance DelegatingFilterProxy springSecurityFilter; /** - * The security header filter - conditionlly adds security-related headers to the HTTP response. + * The security header filter - conditionally adds security-related headers to the HTTP response for Ambari Views requests. */ @Inject - SecurityHeaderFilter securityHeaderFilter; + AmbariViewsSecurityHeaderFilter ambariViewsSecurityHeaderFilter; /** * Mapping of view instance entities to handlers. @@ -241,7 +241,7 @@ public class AmbariHandlerList extends HandlerCollection implements ViewInstance webAppContext.setClassLoader(viewInstanceDefinition.getViewEntity().getClassLoader()); webAppContext.setAttribute(ViewContext.CONTEXT_ATTRIBUTE, new ViewContextImpl(viewInstanceDefinition, viewRegistry)); webAppContext.setSessionHandler(new SharedSessionHandler(sessionManager)); - webAppContext.addFilter(new FilterHolder(securityHeaderFilter), "/*", AmbariServer.DISPATCHER_TYPES); + webAppContext.addFilter(new FilterHolder(ambariViewsSecurityHeaderFilter), "/*", AmbariServer.DISPATCHER_TYPES); webAppContext.addFilter(new FilterHolder(persistFilter), "/*", AmbariServer.DISPATCHER_TYPES); webAppContext.addFilter(new FilterHolder(springSecurityFilter), "/*", AmbariServer.DISPATCHER_TYPES); webAppContext.setAllowNullPathInfo(true); http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/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 5974494..8f3869f 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 @@ -80,9 +80,9 @@ import org.apache.ambari.server.orm.entities.MetainfoEntity; 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.CertificateManager; import org.apache.ambari.server.security.SecurityFilter; -import org.apache.ambari.server.security.SecurityHeaderFilter; import org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter; import org.apache.ambari.server.security.authorization.AmbariLdapAuthenticationProvider; import org.apache.ambari.server.security.authorization.AmbariLocalUserDetailsService; @@ -290,7 +290,7 @@ public class AmbariServer { rootServlet.setInitOrder(1); // Conditionally adds security-related headers to all HTTP responses. - root.addFilter(new FilterHolder(injector.getInstance(SecurityHeaderFilter.class)), "/*", DISPATCHER_TYPES); + root.addFilter(new FilterHolder(injector.getInstance(AmbariServerSecurityHeaderFilter.class)), "/*", DISPATCHER_TYPES); //session-per-request strategy for api and agents root.addFilter(new FilterHolder(injector.getInstance(AmbariPersistFilter.class)), "/api/*", DISPATCHER_TYPES); // root.addFilter(new FilterHolder(injector.getInstance(AmbariPersistFilter.class)), "/proxy/*", DISPATCHER_TYPES); http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/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 new file mode 100644 index 0000000..36f691c --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/AbstractSecurityHeaderFilter.java @@ -0,0 +1,143 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.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 javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * AbstractSecurityHeaderFilter is an abstract class used to help add security-related headers to + * HTTP responses. + * <p/> + * This class is to be implemented to set the values for the following headers: + * <ol> + * <li>Strict-Transport-Security</li> + * <li>X-Frame-Options</li> + * <li>X-XSS-Protection</li> + * </ol> + * <p/> + * If the value for a particular header item is empty (or null) that header will not be added to the + * set of response headers. + */ +public abstract class AbstractSecurityHeaderFilter implements Filter { + protected final static String STRICT_TRANSPORT_HEADER = "Strict-Transport-Security"; + protected final static String X_FRAME_OPTIONS_HEADER = "X-Frame-Options"; + protected final static String X_XSS_PROTECTION_HEADER = "X-XSS-Protection"; + + /** + * The logger. + */ + private final static Logger LOG = LoggerFactory.getLogger(AbstractSecurityHeaderFilter.class); + /** + * The Configuration object used to determine how Ambari is configured + */ + @Inject + private Configuration configuration; + + /** + * Indicates whether Ambari is configured for SSL (true) or not (false). By default true is assumed + * since preparing for more security will not hurt and is better than not assuming SSL is enabled + * when it is. + */ + private boolean sslEnabled = true; + /** + * The value for the Strict-Transport-Security HTTP response header. + */ + private String strictTransportSecurity = Configuration.HTTP_STRICT_TRANSPORT_HEADER_VALUE_DEFAULT; + /** + * The value for the X-Frame-Options HTTP response header. + */ + private String xFrameOptionsHeader = Configuration.HTTP_X_FRAME_OPTIONS_HEADER_VALUE_DEFAULT; + /** + * The value for the X-XSS-Protection HTTP response header. + */ + private String xXSSProtectionHeader = Configuration.HTTP_X_XSS_PROTECTION_HEADER_VALUE_DEFAULT; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + LOG.debug("Initializing {}", this.getClass().getName()); + + if (configuration == null) { + LOG.warn("The Ambari configuration object is not available, all default options will be assumed."); + } else { + processConfig(configuration); + } + } + + @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); + } + } + + filterChain.doFilter(servletRequest, servletResponse); + } + + @Override + public void destroy() { + LOG.debug("Destroying {}", this.getClass().getName()); + } + + protected abstract void processConfig(Configuration configuration); + + + protected void setSslEnabled(boolean sslEnabled) { + this.sslEnabled = sslEnabled; + } + + protected void setStrictTransportSecurity(String strictTransportSecurity) { + this.strictTransportSecurity = strictTransportSecurity; + } + + protected void setxFrameOptionsHeader(String xFrameOptionsHeader) { + this.xFrameOptionsHeader = xFrameOptionsHeader; + } + + protected void setxXSSProtectionHeader(String xXSSProtectionHeader) { + this.xXSSProtectionHeader = xXSSProtectionHeader; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/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 new file mode 100644 index 0000000..86c28ea --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariServerSecurityHeaderFilter.java @@ -0,0 +1,37 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.ambari.server.security; + +import com.google.inject.Singleton; +import org.apache.ambari.server.configuration.Configuration; + +/** + * AmbariServerSecurityHeaderFilter adds security-related headers to HTTP response messages for Ambari Server UI + */ +@Singleton +public class AmbariServerSecurityHeaderFilter extends AbstractSecurityHeaderFilter { + + @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/31542ae3/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 new file mode 100644 index 0000000..63137fb --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariViewsSecurityHeaderFilter.java @@ -0,0 +1,37 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.ambari.server.security; + +import com.google.inject.Singleton; +import org.apache.ambari.server.configuration.Configuration; + +/** + * AmbariViewsSecurityHeaderFilter adds security-related headers to HTTP response messages for Ambari Views + */ +@Singleton +public class AmbariViewsSecurityHeaderFilter extends AbstractSecurityHeaderFilter { + + @Override + protected void processConfig(Configuration configuration) { + setSslEnabled(configuration.getApiSSLAuthentication()); + setStrictTransportSecurity(configuration.getViewsStrictTransportSecurityHTTPResponseHeader()); + setxFrameOptionsHeader(configuration.getViewsXFrameOptionsHTTPResponseHeader()); + setxXSSProtectionHeader(configuration.getViewsXXSSProtectionHTTPResponseHeader()); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/ambari-server/src/main/java/org/apache/ambari/server/security/SecurityHeaderFilter.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/SecurityHeaderFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/SecurityHeaderFilter.java deleted file mode 100644 index a7479af..0000000 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/SecurityHeaderFilter.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.ambari.server.security; - -import com.google.inject.Inject; -import com.google.inject.Singleton; -import org.apache.ambari.server.configuration.Configuration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * SecurityHeaderFilter adds security-related headers to HTTP response messages - */ -@Singleton -public class SecurityHeaderFilter implements Filter { - /** - * The logger. - */ - private final static Logger LOG = LoggerFactory.getLogger(SecurityHeaderFilter.class); - - protected final static String STRICT_TRANSPORT_HEADER = "Strict-Transport-Security"; - protected final static String X_FRAME_OPTIONS_HEADER = "X-Frame-Options"; - protected final static String X_XSS_PROTECTION_HEADER = "X-XSS-Protection"; - - /** - * The Configuration object used to determing how Ambari is configured - */ - @Inject - private Configuration configuration; - - /** - * Indicates whether Ambari is configured for SSL (true) or not (false). By default true is assumed - * since preparing for more security will not hurt and is better than not assuming SSL is enabled - * when it is. - */ - private boolean sslEnabled = true; - - /** - * The value for the Strict-Transport-Security HTTP response header. - */ - private String strictTransportSecurity = Configuration.HTTP_STRICT_TRANSPORT_HEADER_VALUE_DEFAULT; - - /** - * The value for the X-Frame-Options HTTP response header. - */ - private String xFrameOptionsHeader = Configuration.HTTP_X_FRAME_OPTIONS_HEADER_VALUE_DEFAULT; - - /** - * The value for the X-XSS-Protection HTTP response header. - */ - private String xXSSProtectionHeader = Configuration.HTTP_X_XSS_PROTECTION_HEADER_VALUE_DEFAULT; - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - LOG.debug("Initializing {}", this.getClass().getName()); - - if (configuration == null) { - LOG.warn("The Ambari configuration object is not available, all default options will be assumed."); - } else { - sslEnabled = configuration.getApiSSLAuthentication(); - strictTransportSecurity = configuration.getStrictTransportSecurityHTTPResponseHeader(); - xFrameOptionsHeader = configuration.getXFrameOptionsHTTPResponseHeader(); - xXSSProtectionHeader = configuration.getXXSSProtectionHTTPResponseHeader(); - } - } - - @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 && (strictTransportSecurity != null) && !strictTransportSecurity.isEmpty()) { - httpServletResponse.setHeader(STRICT_TRANSPORT_HEADER, strictTransportSecurity); - } - - // Conditionally set the X-Frame-Options HTTP response header if a value is supplied - if ((xFrameOptionsHeader != null) && !xFrameOptionsHeader.isEmpty()) { - httpServletResponse.setHeader(X_FRAME_OPTIONS_HEADER, xFrameOptionsHeader); - } - - // Conditionally set the X-XSS-Protection HTTP response header if a value is supplied - if ((xXSSProtectionHeader != null) && !xXSSProtectionHeader.isEmpty()) { - httpServletResponse.setHeader(X_XSS_PROTECTION_HEADER, xXSSProtectionHeader); - } - } - - filterChain.doFilter(servletRequest, servletResponse); - } - - @Override - public void destroy() { - LOG.debug("Destroying {}", this.getClass().getName()); - } -} http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariHandlerListTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariHandlerListTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariHandlerListTest.java index a0cb8d0..2e2cc45 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariHandlerListTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariHandlerListTest.java @@ -22,7 +22,7 @@ import org.apache.ambari.server.api.AmbariPersistFilter; import org.apache.ambari.server.orm.entities.ViewEntity; import org.apache.ambari.server.orm.entities.ViewInstanceEntity; import org.apache.ambari.server.orm.entities.ViewInstanceEntityTest; -import org.apache.ambari.server.security.SecurityHeaderFilter; +import org.apache.ambari.server.security.AmbariViewsSecurityHeaderFilter; import org.apache.ambari.server.view.ViewRegistry; import org.easymock.Capture; import org.eclipse.jetty.server.Handler; @@ -52,7 +52,7 @@ import static org.easymock.EasyMock.verify; */ public class AmbariHandlerListTest { - private final SecurityHeaderFilter securityHeaderFilter = createNiceMock(SecurityHeaderFilter.class); + private final AmbariViewsSecurityHeaderFilter ambariViewsSecurityHeaderFilter = createNiceMock(AmbariViewsSecurityHeaderFilter.class); private final AmbariPersistFilter persistFilter = createNiceMock(AmbariPersistFilter.class); private final DelegatingFilterProxy springSecurityFilter = createNiceMock(DelegatingFilterProxy.class); @@ -87,7 +87,7 @@ public class AmbariHandlerListTest { Assert.assertTrue(handlers.contains(handler)); - Assert.assertEquals(securityHeaderFilter, securityHeaderFilterCapture.getValue().getFilter()); + Assert.assertEquals(ambariViewsSecurityHeaderFilter, securityHeaderFilterCapture.getValue().getFilter()); Assert.assertEquals(persistFilter, persistFilterCapture.getValue().getFilter()); Assert.assertEquals(springSecurityFilter, securityFilterCapture.getValue().getFilter()); @@ -161,7 +161,7 @@ public class AmbariHandlerListTest { AmbariHandlerList handlerList = new AmbariHandlerList(); handlerList.webAppContextProvider = new HandlerProvider(handler); - handlerList.securityHeaderFilter = securityHeaderFilter; + handlerList.ambariViewsSecurityHeaderFilter = ambariViewsSecurityHeaderFilter; handlerList.persistFilter = persistFilter; handlerList.springSecurityFilter = springSecurityFilter; http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/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 new file mode 100644 index 0000000..3481092 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/security/AbstractSecurityHeaderFilterTest.java @@ -0,0 +1,329 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.ambari.server.security; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import junit.framework.Assert; +import org.apache.ambari.server.configuration.Configuration; +import org.apache.ambari.server.state.stack.OsFamily; +import org.easymock.EasyMockSupport; +import org.junit.After; +import org.junit.Before; +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 static org.easymock.EasyMock.expectLastCall; + +public abstract class AbstractSecurityHeaderFilterTest extends EasyMockSupport { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private final Class<? extends AbstractSecurityHeaderFilter> filterClass; + private final Map<String, String> propertyNameMap; + private final Map<String, String> defatulPropertyValueMap; + + protected AbstractSecurityHeaderFilterTest(Class<? extends AbstractSecurityHeaderFilter> filterClass, Map<String, String> propertyNameMap, Map<String, String> defatulPropertyValueMap) { + this.filterClass = filterClass; + this.propertyNameMap = propertyNameMap; + this.defatulPropertyValueMap = defatulPropertyValueMap; + } + + @Before + public void setUp() throws Exception { + temporaryFolder.create(); + } + + @After + public void tearDown() throws Exception { + temporaryFolder.delete(); + } + + @Test + public void testDoFilter_DefaultValuesNoSSL() throws Exception { + Injector injector = Guice.createInjector(new AbstractModule() { + + @Override + protected void configure() { + Properties properties = new Properties(); + properties.setProperty(Configuration.API_USE_SSL, "false"); + + bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); + bind(Configuration.class).toInstance(new Configuration(properties)); + } + }); + + FilterConfig filterConfig = createNiceMock(FilterConfig.class); + + HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class); + + HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class); + servletResponse.setHeader(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, defatulPropertyValueMap.get(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER)); + expectLastCall().once(); + servletResponse.setHeader(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER, defatulPropertyValueMap.get(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER)); + expectLastCall().once(); + + FilterChain filterChain = createStrictMock(FilterChain.class); + filterChain.doFilter(servletRequest, servletResponse); + expectLastCall().once(); + + replayAll(); + + AbstractSecurityHeaderFilter securityFilter = injector.getInstance(filterClass); + Assert.assertNotNull(securityFilter); + + securityFilter.init(filterConfig); + securityFilter.doFilter(servletRequest, servletResponse, filterChain); + + verifyAll(); + } + + @Test + public void testDoFilter_DefaultValuesSSL() throws Exception { + final File httpPassFile = temporaryFolder.newFile(); + + Injector injector = Guice.createInjector(new AbstractModule() { + + @Override + protected void configure() { + Properties properties = new Properties(); + properties.setProperty(Configuration.API_USE_SSL, "true"); + properties.setProperty(Configuration.CLIENT_API_SSL_KSTR_DIR_NAME_KEY, httpPassFile.getParent()); + properties.setProperty(Configuration.CLIENT_API_SSL_CRT_PASS_FILE_NAME_KEY, httpPassFile.getName()); + + bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); + bind(Configuration.class).toInstance(new Configuration(properties)); + } + }); + + FilterConfig filterConfig = createNiceMock(FilterConfig.class); + + HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class); + + HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class); + servletResponse.setHeader(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER, defatulPropertyValueMap.get(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER)); + expectLastCall().once(); + servletResponse.setHeader(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, defatulPropertyValueMap.get(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER)); + expectLastCall().once(); + servletResponse.setHeader(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER, defatulPropertyValueMap.get(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER)); + expectLastCall().once(); + + FilterChain filterChain = createStrictMock(FilterChain.class); + filterChain.doFilter(servletRequest, servletResponse); + expectLastCall().once(); + + replayAll(); + + AbstractSecurityHeaderFilter securityFilter = injector.getInstance(filterClass); + Assert.assertNotNull(securityFilter); + + securityFilter.init(filterConfig); + securityFilter.doFilter(servletRequest, servletResponse, filterChain); + + verifyAll(); + } + + @Test + public void testDoFilter_CustomValuesNoSSL() throws Exception { + final File httpPassFile = temporaryFolder.newFile(); + + Injector injector = Guice.createInjector(new AbstractModule() { + + @Override + protected void configure() { + Properties properties = new Properties(); + properties.setProperty(Configuration.CLIENT_API_SSL_KSTR_DIR_NAME_KEY, httpPassFile.getParent()); + properties.setProperty(Configuration.CLIENT_API_SSL_CRT_PASS_FILE_NAME_KEY, httpPassFile.getName()); + properties.setProperty(propertyNameMap.get(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER), "custom1"); + properties.setProperty(propertyNameMap.get(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER), "custom2"); + properties.setProperty(propertyNameMap.get(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER), "custom3"); + + bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); + bind(Configuration.class).toInstance(new Configuration(properties)); + } + }); + + FilterConfig filterConfig = createNiceMock(FilterConfig.class); + + HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class); + + HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class); + servletResponse.setHeader(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, "custom2"); + expectLastCall().once(); + servletResponse.setHeader(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER, "custom3"); + expectLastCall().once(); + + FilterChain filterChain = createStrictMock(FilterChain.class); + filterChain.doFilter(servletRequest, servletResponse); + expectLastCall().once(); + + replayAll(); + + AbstractSecurityHeaderFilter securityFilter = injector.getInstance(filterClass); + Assert.assertNotNull(securityFilter); + + securityFilter.init(filterConfig); + securityFilter.doFilter(servletRequest, servletResponse, filterChain); + + verifyAll(); + } + + @Test + public void testDoFilter_CustomValuesSSL() throws Exception { + final File httpPassFile = temporaryFolder.newFile(); + + Injector injector = Guice.createInjector(new AbstractModule() { + + @Override + protected void configure() { + Properties properties = new Properties(); + properties.setProperty(Configuration.API_USE_SSL, "true"); + properties.setProperty(Configuration.CLIENT_API_SSL_KSTR_DIR_NAME_KEY, httpPassFile.getParent()); + properties.setProperty(Configuration.CLIENT_API_SSL_CRT_PASS_FILE_NAME_KEY, httpPassFile.getName()); + properties.setProperty(propertyNameMap.get(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER), "custom1"); + properties.setProperty(propertyNameMap.get(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER), "custom2"); + properties.setProperty(propertyNameMap.get(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER), "custom3"); + + bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); + bind(Configuration.class).toInstance(new Configuration(properties)); + } + }); + + FilterConfig filterConfig = createNiceMock(FilterConfig.class); + + HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class); + + HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class); + servletResponse.setHeader(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER, "custom1"); + expectLastCall().once(); + servletResponse.setHeader(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, "custom2"); + expectLastCall().once(); + servletResponse.setHeader(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER, "custom3"); + expectLastCall().once(); + + FilterChain filterChain = createStrictMock(FilterChain.class); + filterChain.doFilter(servletRequest, servletResponse); + expectLastCall().once(); + + replayAll(); + + AbstractSecurityHeaderFilter securityFilter = injector.getInstance(filterClass); + Assert.assertNotNull(securityFilter); + + securityFilter.init(filterConfig); + securityFilter.doFilter(servletRequest, servletResponse, filterChain); + + verifyAll(); + } + + @Test + public void testDoFilter_EmptyValuesNoSSL() throws Exception { + final File httpPassFile = temporaryFolder.newFile(); + + Injector injector = Guice.createInjector(new AbstractModule() { + + @Override + protected void configure() { + Properties properties = new Properties(); + properties.setProperty(Configuration.CLIENT_API_SSL_KSTR_DIR_NAME_KEY, httpPassFile.getParent()); + properties.setProperty(Configuration.CLIENT_API_SSL_CRT_PASS_FILE_NAME_KEY, httpPassFile.getName()); + properties.setProperty(propertyNameMap.get(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER), ""); + properties.setProperty(propertyNameMap.get(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER), ""); + properties.setProperty(propertyNameMap.get(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER), ""); + + bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); + bind(Configuration.class).toInstance(new Configuration(properties)); + } + }); + + FilterConfig filterConfig = createNiceMock(FilterConfig.class); + + HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class); + + HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class); + + FilterChain filterChain = createStrictMock(FilterChain.class); + filterChain.doFilter(servletRequest, servletResponse); + expectLastCall().once(); + + replayAll(); + + AbstractSecurityHeaderFilter securityFilter = injector.getInstance(filterClass); + Assert.assertNotNull(securityFilter); + + securityFilter.init(filterConfig); + securityFilter.doFilter(servletRequest, servletResponse, filterChain); + + verifyAll(); + } + + @Test + public void testDoFilter_EmptyValuesSSL() throws Exception { + final File httpPassFile = temporaryFolder.newFile(); + + Injector injector = Guice.createInjector(new AbstractModule() { + + @Override + protected void configure() { + Properties properties = new Properties(); + properties.setProperty(Configuration.API_USE_SSL, "true"); + properties.setProperty(Configuration.CLIENT_API_SSL_KSTR_DIR_NAME_KEY, httpPassFile.getParent()); + properties.setProperty(Configuration.CLIENT_API_SSL_CRT_PASS_FILE_NAME_KEY, httpPassFile.getName()); + properties.setProperty(propertyNameMap.get(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER), ""); + properties.setProperty(propertyNameMap.get(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER), ""); + properties.setProperty(propertyNameMap.get(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER), ""); + + bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); + bind(Configuration.class).toInstance(new Configuration(properties)); + } + }); + + FilterConfig filterConfig = createNiceMock(FilterConfig.class); + + HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class); + + HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class); + + FilterChain filterChain = createStrictMock(FilterChain.class); + filterChain.doFilter(servletRequest, servletResponse); + expectLastCall().once(); + + replayAll(); + + AbstractSecurityHeaderFilter securityFilter = injector.getInstance(filterClass); + Assert.assertNotNull(securityFilter); + + securityFilter.init(filterConfig); + securityFilter.doFilter(servletRequest, servletResponse, filterChain); + + verifyAll(); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/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 new file mode 100644 index 0000000..0e3313e --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariServerSecurityHeaderFilterTest.java @@ -0,0 +1,51 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.ambari.server.security; + +import org.apache.ambari.server.configuration.Configuration; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class AmbariServerSecurityHeaderFilterTest extends AbstractSecurityHeaderFilterTest { + + private static final Map<String, String> PROPERTY_NAME_MAP; + private static final Map<String, String> DEFAULT_PROPERTY_VALUE_MAP; + + static { + + Map<String, String> map; + map = new HashMap<String, String>(); + map.put(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER, Configuration.HTTP_STRICT_TRANSPORT_HEADER_VALUE_KEY); + map.put(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, Configuration.HTTP_X_FRAME_OPTIONS_HEADER_VALUE_KEY); + map.put(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER, Configuration.HTTP_X_XSS_PROTECTION_HEADER_VALUE_KEY); + PROPERTY_NAME_MAP = Collections.unmodifiableMap(map); + + map = new HashMap<String, String>(); + map.put(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER, Configuration.HTTP_STRICT_TRANSPORT_HEADER_VALUE_DEFAULT); + map.put(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, Configuration.HTTP_X_FRAME_OPTIONS_HEADER_VALUE_DEFAULT); + map.put(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER, Configuration.HTTP_X_XSS_PROTECTION_HEADER_VALUE_DEFAULT); + DEFAULT_PROPERTY_VALUE_MAP = Collections.unmodifiableMap(map); + } + + public AmbariServerSecurityHeaderFilterTest() { + super(AmbariServerSecurityHeaderFilter.class, PROPERTY_NAME_MAP, DEFAULT_PROPERTY_VALUE_MAP); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/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 new file mode 100644 index 0000000..d760962 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/security/AmbariViewsSecurityHeaderFilterTest.java @@ -0,0 +1,52 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.ambari.server.security; + +import org.apache.ambari.server.configuration.Configuration; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class AmbariViewsSecurityHeaderFilterTest extends AbstractSecurityHeaderFilterTest { + + private static final Map<String, String> PROPERTY_NAME_MAP; + private static final Map<String, String> DEFAULT_PROPERTY_VALUE_MAP; + + static { + + Map<String, String> map; + + map = new HashMap<String, String>(); + map.put(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER, Configuration.VIEWS_HTTP_STRICT_TRANSPORT_HEADER_VALUE_KEY); + map.put(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, Configuration.VIEWS_HTTP_X_FRAME_OPTIONS_HEADER_VALUE_KEY); + map.put(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER, Configuration.VIEWS_HTTP_X_XSS_PROTECTION_HEADER_VALUE_KEY); + PROPERTY_NAME_MAP = Collections.unmodifiableMap(map); + + map = new HashMap<String, String>(); + map.put(AbstractSecurityHeaderFilter.STRICT_TRANSPORT_HEADER, Configuration.VIEWS_HTTP_STRICT_TRANSPORT_HEADER_VALUE_DEFAULT); + map.put(AbstractSecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, Configuration.VIEWS_HTTP_X_FRAME_OPTIONS_HEADER_VALUE_DEFAULT); + map.put(AbstractSecurityHeaderFilter.X_XSS_PROTECTION_HEADER, Configuration.VIEWS_HTTP_X_XSS_PROTECTION_HEADER_VALUE_DEFAULT); + DEFAULT_PROPERTY_VALUE_MAP = Collections.unmodifiableMap(map); + } + + public AmbariViewsSecurityHeaderFilterTest() { + super(AmbariViewsSecurityHeaderFilter.class, PROPERTY_NAME_MAP, DEFAULT_PROPERTY_VALUE_MAP); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/31542ae3/ambari-server/src/test/java/org/apache/ambari/server/security/SecurityHeaderFilterTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/SecurityHeaderFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/SecurityHeaderFilterTest.java deleted file mode 100644 index 5e8d2af..0000000 --- a/ambari-server/src/test/java/org/apache/ambari/server/security/SecurityHeaderFilterTest.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.ambari.server.security; - -import com.google.inject.AbstractModule; -import com.google.inject.Guice; -import com.google.inject.Injector; -import junit.framework.Assert; -import org.apache.ambari.server.configuration.Configuration; -import org.apache.ambari.server.state.stack.OsFamily; -import org.easymock.EasyMockSupport; -import org.junit.After; -import org.junit.Before; -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.Properties; - -import static org.easymock.EasyMock.expectLastCall; - -public class SecurityHeaderFilterTest extends EasyMockSupport { - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Before - public void setUp() throws Exception { - temporaryFolder.create(); - } - - @After - public void tearDown() throws Exception { - temporaryFolder.delete(); - } - - @Test - public void testDoFilter_DefaultValuesNoSSL() throws Exception { - Injector injector = Guice.createInjector(new AbstractModule() { - - @Override - protected void configure() { - Properties properties = new Properties(); - properties.setProperty(Configuration.API_USE_SSL, "false"); - - bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); - bind(Configuration.class).toInstance(new Configuration(properties)); - } - }); - - FilterConfig filterConfig = createNiceMock(FilterConfig.class); - - HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class); - - HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class); - servletResponse.setHeader(SecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, Configuration.HTTP_X_FRAME_OPTIONS_HEADER_VALUE_DEFAULT); - expectLastCall().once(); - servletResponse.setHeader(SecurityHeaderFilter.X_XSS_PROTECTION_HEADER, Configuration.HTTP_X_XSS_PROTECTION_HEADER_VALUE_DEFAULT); - expectLastCall().once(); - - FilterChain filterChain = createStrictMock(FilterChain.class); - filterChain.doFilter(servletRequest, servletResponse); - expectLastCall().once(); - - replayAll(); - - SecurityHeaderFilter securityFilter = injector.getInstance(SecurityHeaderFilter.class); - Assert.assertNotNull(securityFilter); - - securityFilter.init(filterConfig); - securityFilter.doFilter(servletRequest, servletResponse, filterChain); - - verifyAll(); - } - - @Test - public void testDoFilter_DefaultValuesSSL() throws Exception { - final File httpPassFile = temporaryFolder.newFile(); - - Injector injector = Guice.createInjector(new AbstractModule() { - - @Override - protected void configure() { - Properties properties = new Properties(); - properties.setProperty(Configuration.API_USE_SSL, "true"); - properties.setProperty(Configuration.CLIENT_API_SSL_KSTR_DIR_NAME_KEY, httpPassFile.getParent()); - properties.setProperty(Configuration.CLIENT_API_SSL_CRT_PASS_FILE_NAME_KEY, httpPassFile.getName()); - - bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); - bind(Configuration.class).toInstance(new Configuration(properties)); - } - }); - - FilterConfig filterConfig = createNiceMock(FilterConfig.class); - - HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class); - - HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class); - servletResponse.setHeader(SecurityHeaderFilter.STRICT_TRANSPORT_HEADER, Configuration.HTTP_STRICT_TRANSPORT_HEADER_VALUE_DEFAULT); - expectLastCall().once(); - servletResponse.setHeader(SecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, Configuration.HTTP_X_FRAME_OPTIONS_HEADER_VALUE_DEFAULT); - expectLastCall().once(); - servletResponse.setHeader(SecurityHeaderFilter.X_XSS_PROTECTION_HEADER, Configuration.HTTP_X_XSS_PROTECTION_HEADER_VALUE_DEFAULT); - expectLastCall().once(); - - FilterChain filterChain = createStrictMock(FilterChain.class); - filterChain.doFilter(servletRequest, servletResponse); - expectLastCall().once(); - - replayAll(); - - SecurityHeaderFilter securityFilter = injector.getInstance(SecurityHeaderFilter.class); - Assert.assertNotNull(securityFilter); - - securityFilter.init(filterConfig); - securityFilter.doFilter(servletRequest, servletResponse, filterChain); - - verifyAll(); - } - - @Test - public void testDoFilter_CustomValuesNoSSL() throws Exception { - final File httpPassFile = temporaryFolder.newFile(); - - Injector injector = Guice.createInjector(new AbstractModule() { - - @Override - protected void configure() { - Properties properties = new Properties(); - properties.setProperty(Configuration.CLIENT_API_SSL_KSTR_DIR_NAME_KEY, httpPassFile.getParent()); - properties.setProperty(Configuration.CLIENT_API_SSL_CRT_PASS_FILE_NAME_KEY, httpPassFile.getName()); - properties.setProperty(Configuration.HTTP_STRICT_TRANSPORT_HEADER_VALUE_KEY, "custom1"); - properties.setProperty(Configuration.HTTP_X_FRAME_OPTIONS_HEADER_VALUE_KEY, "custom2"); - properties.setProperty(Configuration.HTTP_X_XSS_PROTECTION_HEADER_VALUE_KEY, "custom3"); - - bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); - bind(Configuration.class).toInstance(new Configuration(properties)); - } - }); - - FilterConfig filterConfig = createNiceMock(FilterConfig.class); - - HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class); - - HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class); - servletResponse.setHeader(SecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, "custom2"); - expectLastCall().once(); - servletResponse.setHeader(SecurityHeaderFilter.X_XSS_PROTECTION_HEADER, "custom3"); - expectLastCall().once(); - - FilterChain filterChain = createStrictMock(FilterChain.class); - filterChain.doFilter(servletRequest, servletResponse); - expectLastCall().once(); - - replayAll(); - - SecurityHeaderFilter securityFilter = injector.getInstance(SecurityHeaderFilter.class); - Assert.assertNotNull(securityFilter); - - securityFilter.init(filterConfig); - securityFilter.doFilter(servletRequest, servletResponse, filterChain); - - verifyAll(); - } - - @Test - public void testDoFilter_CustomValuesSSL() throws Exception { - final File httpPassFile = temporaryFolder.newFile(); - - Injector injector = Guice.createInjector(new AbstractModule() { - - @Override - protected void configure() { - Properties properties = new Properties(); - properties.setProperty(Configuration.API_USE_SSL, "true"); - properties.setProperty(Configuration.CLIENT_API_SSL_KSTR_DIR_NAME_KEY, httpPassFile.getParent()); - properties.setProperty(Configuration.CLIENT_API_SSL_CRT_PASS_FILE_NAME_KEY, httpPassFile.getName()); - properties.setProperty(Configuration.HTTP_STRICT_TRANSPORT_HEADER_VALUE_KEY, "custom1"); - properties.setProperty(Configuration.HTTP_X_FRAME_OPTIONS_HEADER_VALUE_KEY, "custom2"); - properties.setProperty(Configuration.HTTP_X_XSS_PROTECTION_HEADER_VALUE_KEY, "custom3"); - - bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); - bind(Configuration.class).toInstance(new Configuration(properties)); - } - }); - - FilterConfig filterConfig = createNiceMock(FilterConfig.class); - - HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class); - - HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class); - servletResponse.setHeader(SecurityHeaderFilter.STRICT_TRANSPORT_HEADER, "custom1"); - expectLastCall().once(); - servletResponse.setHeader(SecurityHeaderFilter.X_FRAME_OPTIONS_HEADER, "custom2"); - expectLastCall().once(); - servletResponse.setHeader(SecurityHeaderFilter.X_XSS_PROTECTION_HEADER, "custom3"); - expectLastCall().once(); - - FilterChain filterChain = createStrictMock(FilterChain.class); - filterChain.doFilter(servletRequest, servletResponse); - expectLastCall().once(); - - replayAll(); - - SecurityHeaderFilter securityFilter = injector.getInstance(SecurityHeaderFilter.class); - Assert.assertNotNull(securityFilter); - - securityFilter.init(filterConfig); - securityFilter.doFilter(servletRequest, servletResponse, filterChain); - - verifyAll(); - } - - @Test - public void testDoFilter_EmptyValuesNoSSL() throws Exception { - final File httpPassFile = temporaryFolder.newFile(); - - Injector injector = Guice.createInjector(new AbstractModule() { - - @Override - protected void configure() { - Properties properties = new Properties(); - properties.setProperty(Configuration.CLIENT_API_SSL_KSTR_DIR_NAME_KEY, httpPassFile.getParent()); - properties.setProperty(Configuration.CLIENT_API_SSL_CRT_PASS_FILE_NAME_KEY, httpPassFile.getName()); - properties.setProperty(Configuration.HTTP_STRICT_TRANSPORT_HEADER_VALUE_KEY, ""); - properties.setProperty(Configuration.HTTP_X_FRAME_OPTIONS_HEADER_VALUE_KEY, ""); - properties.setProperty(Configuration.HTTP_X_XSS_PROTECTION_HEADER_VALUE_KEY, ""); - - bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); - bind(Configuration.class).toInstance(new Configuration(properties)); - } - }); - - FilterConfig filterConfig = createNiceMock(FilterConfig.class); - - HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class); - - HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class); - - FilterChain filterChain = createStrictMock(FilterChain.class); - filterChain.doFilter(servletRequest, servletResponse); - expectLastCall().once(); - - replayAll(); - - SecurityHeaderFilter securityFilter = injector.getInstance(SecurityHeaderFilter.class); - Assert.assertNotNull(securityFilter); - - securityFilter.init(filterConfig); - securityFilter.doFilter(servletRequest, servletResponse, filterChain); - - verifyAll(); - } - - @Test - public void testDoFilter_EmptyValuesSSL() throws Exception { - final File httpPassFile = temporaryFolder.newFile(); - - Injector injector = Guice.createInjector(new AbstractModule() { - - @Override - protected void configure() { - Properties properties = new Properties(); - properties.setProperty(Configuration.API_USE_SSL, "true"); - properties.setProperty(Configuration.CLIENT_API_SSL_KSTR_DIR_NAME_KEY, httpPassFile.getParent()); - properties.setProperty(Configuration.CLIENT_API_SSL_CRT_PASS_FILE_NAME_KEY, httpPassFile.getName()); - properties.setProperty(Configuration.HTTP_STRICT_TRANSPORT_HEADER_VALUE_KEY, ""); - properties.setProperty(Configuration.HTTP_X_FRAME_OPTIONS_HEADER_VALUE_KEY, ""); - properties.setProperty(Configuration.HTTP_X_XSS_PROTECTION_HEADER_VALUE_KEY, ""); - - bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); - bind(Configuration.class).toInstance(new Configuration(properties)); - } - }); - - FilterConfig filterConfig = createNiceMock(FilterConfig.class); - - HttpServletRequest servletRequest = createStrictMock(HttpServletRequest.class); - - HttpServletResponse servletResponse = createStrictMock(HttpServletResponse.class); - - FilterChain filterChain = createStrictMock(FilterChain.class); - filterChain.doFilter(servletRequest, servletResponse); - expectLastCall().once(); - - replayAll(); - - SecurityHeaderFilter securityFilter = injector.getInstance(SecurityHeaderFilter.class); - Assert.assertNotNull(securityFilter); - - securityFilter.init(filterConfig); - securityFilter.doFilter(servletRequest, servletResponse, filterChain); - - verifyAll(); - } -} \ No newline at end of file
