Return-Path: X-Original-To: apmail-ambari-commits-archive@www.apache.org Delivered-To: apmail-ambari-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id A9208187EE for ; Fri, 2 Oct 2015 21:12:12 +0000 (UTC) Received: (qmail 50924 invoked by uid 500); 2 Oct 2015 21:12:06 -0000 Delivered-To: apmail-ambari-commits-archive@ambari.apache.org Received: (qmail 50814 invoked by uid 500); 2 Oct 2015 21:12:06 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 50513 invoked by uid 99); 2 Oct 2015 21:12:06 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 02 Oct 2015 21:12:06 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id A9973E09C9; Fri, 2 Oct 2015 21:12:05 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: ncole@apache.org To: commits@ambari.apache.org Date: Fri, 02 Oct 2015 21:12:13 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [09/32] ambari git commit: AMBARI-13278. Add security-related HTTP headers to keep Ambari up to date with best-practices (rlevas) AMBARI-13278. Add security-related HTTP headers to keep Ambari up to date with best-practices (rlevas) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/c4b48e9f Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/c4b48e9f Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/c4b48e9f Branch: refs/heads/branch-dev-patch-upgrade Commit: c4b48e9fa34601ec216911c700929682d2163067 Parents: 4e5489b Author: Robert Levas Authored: Thu Oct 1 11:59:52 2015 -0400 Committer: Robert Levas Committed: Thu Oct 1 11:59:52 2015 -0400 ---------------------------------------------------------------------- ambari-server/conf/unix/ambari.properties | 5 + ambari-server/conf/windows/ambari.properties | 5 + .../server/configuration/Configuration.java | 57 ++++ .../ambari/server/controller/AmbariServer.java | 4 +- .../server/security/SecurityHeaderFilter.java | 121 +++++++ .../security/SecurityHeaderFilterTest.java | 318 +++++++++++++++++++ 6 files changed, 509 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/c4b48e9f/ambari-server/conf/unix/ambari.properties ---------------------------------------------------------------------- diff --git a/ambari-server/conf/unix/ambari.properties b/ambari-server/conf/unix/ambari.properties index 75e0fe1..dedd511 100644 --- a/ambari-server/conf/unix/ambari.properties +++ b/ambari-server/conf/unix/ambari.properties @@ -92,3 +92,8 @@ skip.service.checks=false rolling.upgrade.min.stack=HDP-2.2 rolling.upgrade.max.stack= + +# HTTP Header settings +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://git-wip-us.apache.org/repos/asf/ambari/blob/c4b48e9f/ambari-server/conf/windows/ambari.properties ---------------------------------------------------------------------- diff --git a/ambari-server/conf/windows/ambari.properties b/ambari-server/conf/windows/ambari.properties index a6a5aac..6a98a63 100644 --- a/ambari-server/conf/windows/ambari.properties +++ b/ambari-server/conf/windows/ambari.properties @@ -86,3 +86,8 @@ ulimit.open.files=10000 #server.jdbc.schema=ambari ##server.jdbc.user.passwd=etc\\ambari-server\\conf\\password.dat ##server.jdbc.user.name=ambari + +# HTTP Header settings +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://git-wip-us.apache.org/repos/asf/ambari/blob/c4b48e9f/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 e3686ac..67dcfa5 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 @@ -438,6 +438,16 @@ public class Configuration { public static final String ALERTS_EXECUTION_SCHEDULER_THREADS_KEY = "alerts.execution.scheduler.maxThreads"; public static final String ALERTS_EXECUTION_SCHEDULER_THREADS_DEFAULT = "2"; + /** + * For HTTP Response header configuration + */ + 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"; + public static final String HTTP_X_FRAME_OPTIONS_HEADER_VALUE_KEY = "http.x-frame-options"; + public static final String HTTP_X_FRAME_OPTIONS_HEADER_VALUE_DEFAULT = "DENY"; + 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"; + private static final Logger LOG = LoggerFactory.getLogger( Configuration.class); @@ -1004,6 +1014,53 @@ public class Configuration { } /** + * Get the value that should be set for the Strict-Transport-Security HTTP response header. + *

+ * By default this will be max-age=31536000; includeSubDomains. For example: + *

+ * + * Strict-Transport-Security: max-age=31536000; includeSubDomains + * + *

+ * This value may be ignored when {@link #getApiSSLAuthentication()} is false. + * + * @return the Strict-Transport-Security value - null or "" indicates that the value is not set + */ + public String getStrictTransportSecurityHTTPResponseHeader() { + return properties.getProperty(HTTP_STRICT_TRANSPORT_HEADER_VALUE_KEY, HTTP_STRICT_TRANSPORT_HEADER_VALUE_DEFAULT); + } + + /** + * Get the value that should be set for the X-Frame-Options HTTP response header. + *

+ * By default this will be DENY. For example: + *

+ * + * X-Frame-Options: DENY + * + * + * @return the X-Frame-Options value - null or "" indicates that the value is not set + */ + public String getXFrameOptionsHTTPResponseHeader() { + return properties.getProperty(HTTP_X_FRAME_OPTIONS_HEADER_VALUE_KEY, HTTP_X_FRAME_OPTIONS_HEADER_VALUE_DEFAULT); + } + + /** + * Get the value that should be set for the X-XSS-Protection HTTP response header. + *

+ * By default this will be 1; mode=block. For example: + *

+ * + * X-XSS-Protection: 1; mode=block + * + * + * @return the X-XSS-Protection value - null or "" indicates that the value is not set + */ + public String getXXSSProtectionHTTPResponseHeader() { + return properties.getProperty(HTTP_X_XSS_PROTECTION_HEADER_VALUE_KEY, 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/c4b48e9f/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 3c598db..5974494 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 @@ -63,7 +63,6 @@ import org.apache.ambari.server.controller.internal.StackDefinedPropertyProvider import org.apache.ambari.server.controller.internal.StackDependencyResourceProvider; import org.apache.ambari.server.controller.internal.UserPrivilegeResourceProvider; import org.apache.ambari.server.controller.internal.ViewPermissionResourceProvider; -import org.apache.ambari.server.controller.metrics.timeline.cache.TimelineMetricCacheProvider; import org.apache.ambari.server.controller.utilities.DatabaseChecker; import org.apache.ambari.server.orm.GuiceJpaInitializer; import org.apache.ambari.server.orm.PersistenceType; @@ -83,6 +82,7 @@ import org.apache.ambari.server.resources.api.rest.GetResource; import org.apache.ambari.server.scheduler.ExecutionScheduleManager; 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; @@ -289,6 +289,8 @@ public class AmbariServer { rootServlet = agentroot.addServlet(DefaultServlet.class, "/"); rootServlet.setInitOrder(1); + // Conditionally adds security-related headers to all HTTP responses. + root.addFilter(new FilterHolder(injector.getInstance(SecurityHeaderFilter.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/c4b48e9f/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 new file mode 100644 index 0000000..a7479af --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/SecurityHeaderFilter.java @@ -0,0 +1,121 @@ +/* + * 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/c4b48e9f/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 new file mode 100644 index 0000000..5e8d2af --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/security/SecurityHeaderFilterTest.java @@ -0,0 +1,318 @@ +/* + * 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