You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by lm...@apache.org on 2017/10/29 20:05:24 UTC
knox git commit: KNOX-1017 - Add support for enabling
"Strict-Transport-Security" header in Knox responses (Latha Appanna via
lmccay)
Repository: knox
Updated Branches:
refs/heads/master 710e78487 -> b60322a6e
KNOX-1017 - Add support for enabling "Strict-Transport-Security" header in Knox responses (Latha Appanna via lmccay)
Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/b60322a6
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/b60322a6
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/b60322a6
Branch: refs/heads/master
Commit: b60322a6e2ba97b9f989d1efbe5183bfbc009c56
Parents: 710e784
Author: Larry McCay <lm...@hortonworks.com>
Authored: Sun Oct 29 16:05:16 2017 -0400
Committer: Larry McCay <lm...@hortonworks.com>
Committed: Sun Oct 29 16:05:16 2017 -0400
----------------------------------------------------------------------
.../webappsec/deploy/WebAppSecContributor.java | 11 ++
.../webappsec/filter/StrictTranportFilter.java | 137 ++++++++++++++++
.../webappsec/StrictTranportFilterTest.java | 164 +++++++++++++++++++
.../home/conf/topologies/manager.xml | 1 +
gateway-release/home/templates/sandbox-apps.xml | 1 +
5 files changed, 314 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/knox/blob/b60322a6/gateway-provider-security-webappsec/src/main/java/org/apache/hadoop/gateway/webappsec/deploy/WebAppSecContributor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-webappsec/src/main/java/org/apache/hadoop/gateway/webappsec/deploy/WebAppSecContributor.java b/gateway-provider-security-webappsec/src/main/java/org/apache/hadoop/gateway/webappsec/deploy/WebAppSecContributor.java
index 3904ff1..9a1d174 100644
--- a/gateway-provider-security-webappsec/src/main/java/org/apache/hadoop/gateway/webappsec/deploy/WebAppSecContributor.java
+++ b/gateway-provider-security-webappsec/src/main/java/org/apache/hadoop/gateway/webappsec/deploy/WebAppSecContributor.java
@@ -42,6 +42,9 @@ public class WebAppSecContributor extends
private static final String XFRAME_OPTIONS_SUFFIX = "_XFRAMEOPTIONS";
private static final String XFRAME_OPTIONS_FILTER_CLASSNAME = "org.apache.hadoop.gateway.webappsec.filter.XFrameOptionsFilter";
private static final String XFRAME_OPTIONS_ENABLED = "xframe.options.enabled";
+ private static final String STRICT_TRANSPORT_SUFFIX = "_STRICTTRANSPORT";
+ private static final String STRICT_TRANSPORT_FILTER_CLASSNAME = "org.apache.hadoop.gateway.webappsec.filter.StrictTranportFilter";
+ private static final String STRICT_TRANSPORT_ENABLED = "strict.transport.enabled";
@Override
public String getRole() {
@@ -92,6 +95,14 @@ public class WebAppSecContributor extends
provisionConfig(resource, providerParams, params, "xframe.");
resource.addFilter().name( getName() + XFRAME_OPTIONS_SUFFIX ).role( getRole() ).impl( XFRAME_OPTIONS_FILTER_CLASSNAME ).params( params );
}
+
+ // HTTP Strict-Transport-Security
+ params = new ArrayList<FilterParamDescriptor>();
+ String strictTranportEnabled = map.get(STRICT_TRANSPORT_ENABLED);
+ if ( strictTranportEnabled != null && "true".equals(strictTranportEnabled)) {
+ provisionConfig(resource, providerParams, params, "strict.");
+ resource.addFilter().name( getName() + STRICT_TRANSPORT_SUFFIX).role( getRole() ).impl(STRICT_TRANSPORT_FILTER_CLASSNAME).params( params );
+ }
}
}
http://git-wip-us.apache.org/repos/asf/knox/blob/b60322a6/gateway-provider-security-webappsec/src/main/java/org/apache/hadoop/gateway/webappsec/filter/StrictTranportFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-webappsec/src/main/java/org/apache/hadoop/gateway/webappsec/filter/StrictTranportFilter.java b/gateway-provider-security-webappsec/src/main/java/org/apache/hadoop/gateway/webappsec/filter/StrictTranportFilter.java
new file mode 100644
index 0000000..28ac18a
--- /dev/null
+++ b/gateway-provider-security-webappsec/src/main/java/org/apache/hadoop/gateway/webappsec/filter/StrictTranportFilter.java
@@ -0,0 +1,137 @@
+/**
+ * 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.hadoop.gateway.webappsec.filter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+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 javax.servlet.http.HttpServletResponseWrapper;
+
+/**
+ * This filter protects proxied webapps from protocol downgrade attacks
+ * and cookie hijacking.
+ */
+public class StrictTranportFilter implements Filter {
+ private static final String STRICT_TRANSPORT = "Strict-Transport-Security";
+ private static final String CUSTOM_HEADER_PARAM = "strict.transport";
+
+ private String option = "max-age=31536000";
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#destroy()
+ */
+ @Override
+ public void destroy() {
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
+ */
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res,
+ FilterChain chain) throws IOException, ServletException {
+ ((HttpServletResponse) res).setHeader(STRICT_TRANSPORT, option);
+ chain.doFilter(req, new StrictTranportResponseWrapper((HttpServletResponse) res));
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
+ */
+ @Override
+ public void init(FilterConfig config) throws ServletException {
+ String customOption = config.getInitParameter(CUSTOM_HEADER_PARAM);
+ if (customOption != null) {
+ option = customOption;
+ }
+ }
+
+ public class StrictTranportResponseWrapper extends HttpServletResponseWrapper {
+ @Override
+ public void addHeader(String name, String value) {
+ // don't allow additional values to be added to
+ // the configured options value in topology
+ if (!name.equals(STRICT_TRANSPORT)) {
+ super.addHeader(name, value);
+ }
+ }
+
+ @Override
+ public void setHeader(String name, String value) {
+ // don't allow overwriting of configured value
+ if (!name.equals(STRICT_TRANSPORT)) {
+ super.setHeader(name, value);
+ }
+ }
+
+ /**
+ * construct a wrapper for this request
+ *
+ * @param request
+ */
+ public StrictTranportResponseWrapper(HttpServletResponse response) {
+ super(response);
+ }
+
+ @Override
+ public String getHeader(String name) {
+ String headerValue = null;
+ if (name.equals(STRICT_TRANSPORT)) {
+ headerValue = option;
+ }
+ else {
+ headerValue = super.getHeader(name);
+ }
+ return headerValue;
+ }
+
+ /**
+ * get the Header names
+ */
+ @Override
+ public Collection<String> getHeaderNames() {
+ List<String> names = (List<String>) super.getHeaderNames();
+ if (names == null) {
+ names = new ArrayList<String>();
+ }
+ names.add(STRICT_TRANSPORT);
+ return names;
+ }
+
+ @Override
+ public Collection<String> getHeaders(String name) {
+ List<String> values = (List<String>) super.getHeaders(name);
+ if (name.equals(STRICT_TRANSPORT)) {
+ if (values == null) {
+ values = new ArrayList<String>();
+ }
+ values.add(option);
+ }
+ return values;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/b60322a6/gateway-provider-security-webappsec/src/test/java/org/apache/hadoop/gateway/webappsec/StrictTranportFilterTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-webappsec/src/test/java/org/apache/hadoop/gateway/webappsec/StrictTranportFilterTest.java b/gateway-provider-security-webappsec/src/test/java/org/apache/hadoop/gateway/webappsec/StrictTranportFilterTest.java
new file mode 100644
index 0000000..0c63d7f
--- /dev/null
+++ b/gateway-provider-security-webappsec/src/test/java/org/apache/hadoop/gateway/webappsec/StrictTranportFilterTest.java
@@ -0,0 +1,164 @@
+/**
+ * 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.hadoop.gateway.webappsec;
+
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Properties;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.hadoop.gateway.webappsec.filter.StrictTranportFilter;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class StrictTranportFilterTest {
+ /**
+ *
+ */
+ private static final String STRICT_TRANSPORT = "Strict-Transport-Security";
+ String options = null;
+ Collection<String> headerNames = null;
+ Collection<String> headers = null;
+
+ @Test
+ public void testDefaultOptionsValue() throws Exception {
+ try {
+ StrictTranportFilter filter = new StrictTranportFilter();
+ Properties props = new Properties();
+ props.put("strict.transport.enabled", "true");
+ filter.init(new TestFilterConfig(props));
+
+ HttpServletRequest request = EasyMock.createNiceMock(
+ HttpServletRequest.class);
+ HttpServletResponse response = EasyMock.createNiceMock(
+ HttpServletResponse.class);
+ EasyMock.replay(request);
+ EasyMock.replay(response);
+
+ TestFilterChain chain = new TestFilterChain();
+ filter.doFilter(request, response, chain);
+ Assert.assertTrue("doFilterCalled should not be false.",
+ chain.doFilterCalled );
+ Assert.assertTrue("Options value incorrect should be max-age=31536000 but is: "
+ + options, "max-age=31536000".equals(options));
+
+ Assert.assertTrue("Strict-Transport-Security count not equal to 1.", headers.size() == 1);
+ } catch (ServletException se) {
+ fail("Should NOT have thrown a ServletException.");
+ }
+ }
+
+ @Test
+ public void testConfiguredOptionsValue() throws Exception {
+ try {
+ StrictTranportFilter filter = new StrictTranportFilter();
+ Properties props = new Properties();
+ props.put("strict.transport.enabled", "true");
+ props.put("strict.transport", "max-age=31536010; includeSubDomains");
+ filter.init(new TestFilterConfig(props));
+
+ HttpServletRequest request = EasyMock.createNiceMock(
+ HttpServletRequest.class);
+ HttpServletResponse response = EasyMock.createNiceMock(
+ HttpServletResponse.class);
+ EasyMock.replay(request);
+ EasyMock.replay(response);
+
+ TestFilterChain chain = new TestFilterChain();
+ filter.doFilter(request, response, chain);
+ Assert.assertTrue("doFilterCalled should not be false.",
+ chain.doFilterCalled );
+ Assert.assertTrue("Options value incorrect should be max-age=31536010; includeSubDomains but is: "
+ + options, "max-age=31536010; includeSubDomains".equals(options));
+
+ Assert.assertTrue("Strict-Transport-Security count not equal to 1.", headers.size() == 1);
+ } catch (ServletException se) {
+ fail("Should NOT have thrown a ServletException.");
+ }
+ }
+
+ class TestFilterConfig implements FilterConfig {
+ Properties props = null;
+
+ public TestFilterConfig(Properties props) {
+ this.props = props;
+ }
+
+ @Override
+ public String getFilterName() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.FilterConfig#getServletContext()
+ */
+ @Override
+ public ServletContext getServletContext() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.FilterConfig#getInitParameter(java.lang.String)
+ */
+ @Override
+ public String getInitParameter(String name) {
+ return props.getProperty(name, null);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.FilterConfig#getInitParameterNames()
+ */
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ return null;
+ }
+
+ }
+
+ class TestFilterChain implements FilterChain {
+ boolean doFilterCalled = false;
+
+ /* (non-Javadoc)
+ * @see javax.servlet.FilterChain#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
+ */
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response)
+ throws IOException, ServletException {
+ doFilterCalled = true;
+ options = ((HttpServletResponse)response).getHeader(STRICT_TRANSPORT);
+ headerNames = ((HttpServletResponse)response).getHeaderNames();
+ headers = ((HttpServletResponse)response).getHeaders(STRICT_TRANSPORT);
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/b60322a6/gateway-release/home/conf/topologies/manager.xml
----------------------------------------------------------------------
diff --git a/gateway-release/home/conf/topologies/manager.xml b/gateway-release/home/conf/topologies/manager.xml
index 22f8a91..08416c3 100644
--- a/gateway-release/home/conf/topologies/manager.xml
+++ b/gateway-release/home/conf/topologies/manager.xml
@@ -27,6 +27,7 @@
<param><name>csrf.customHeader</name><value>X-XSRF-Header</value></param>
<param><name>csrf.methodsToIgnore</name><value>GET,OPTIONS,HEAD</value></param>
<param><name>xframe.options.enabled</name><value>true</value></param>
+ <param><name>strict.transport.enabled</name><value>true</value></param>
</provider>
<provider>
http://git-wip-us.apache.org/repos/asf/knox/blob/b60322a6/gateway-release/home/templates/sandbox-apps.xml
----------------------------------------------------------------------
diff --git a/gateway-release/home/templates/sandbox-apps.xml b/gateway-release/home/templates/sandbox-apps.xml
index bed6470..44cb5f2 100644
--- a/gateway-release/home/templates/sandbox-apps.xml
+++ b/gateway-release/home/templates/sandbox-apps.xml
@@ -22,6 +22,7 @@
<enabled>true</enabled>
<param><name>xframe.options.enabled</name><value>true</value></param>
<param><name>csrf.enabled</name><value>true</value></param>
+ <param><name>strict.transport.enabled</name><value>true</value></param>
</provider>
<gateway>