This is an automated email from the ASF dual-hosted git repository.

andras pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/oozie.git


The following commit(s) were added to refs/heads/master by this push:
     new 31548c8  OOZIE-3427 [core] Use best practices in HTTP response headers 
(asalamon74 via andras.piros)
31548c8 is described below

commit 31548c89370ca54a6616aa4f0019d877a5338503
Author: Andras Piros <[email protected]>
AuthorDate: Thu Feb 7 20:27:11 2019 +0100

    OOZIE-3427 [core] Use best practices in HTTP response headers (asalamon74 
via andras.piros)
---
 .../oozie/servlet/HttpResponseHeaderFilter.java    | 83 ++++++++++++++++++++++
 .../apache/oozie/servlet/DagServletTestCase.java   |  5 +-
 .../servlet/TestAuthFilterAuthOozieClient.java     |  3 +-
 .../servlet/TestBulkMonitorWebServiceAPI.java      |  5 +-
 .../servlet/TestHttpResponseHeaderFilter.java      | 62 ++++++++++++++++
 release-log.txt                                    |  1 +
 .../java/org/apache/oozie/server/FilterMapper.java |  6 +-
 .../oozie/server/TestEmbeddedOozieServer.java      |  5 +-
 webapp/src/main/webapp/WEB-INF/web.xml             | 10 +++
 9 files changed, 172 insertions(+), 8 deletions(-)

diff --git 
a/core/src/main/java/org/apache/oozie/servlet/HttpResponseHeaderFilter.java 
b/core/src/main/java/org/apache/oozie/servlet/HttpResponseHeaderFilter.java
new file mode 100644
index 0000000..e57cb26
--- /dev/null
+++ b/core/src/main/java/org/apache/oozie/servlet/HttpResponseHeaderFilter.java
@@ -0,0 +1,83 @@
+/**
+ * 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.oozie.servlet;
+
+import com.google.common.annotations.VisibleForTesting;
+
+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;
+
+/**
+ * Filter that adds headers to the HTTP response
+ */
+public class HttpResponseHeaderFilter implements Filter {
+    @VisibleForTesting
+    static final String X_FRAME_OPTIONS = "X-Frame-Options";
+    @VisibleForTesting
+    static final String X_FRAME_OPTION_DENY = "DENY";
+
+    /**
+     * Initializes the filter.
+     * <p>
+     * This implementation is a NOP.
+     *
+     * @param config filter configuration.
+     *
+     * @throws ServletException thrown if the filter could not be initialized.
+     */
+    @Override
+    public void init(FilterConfig config) throws ServletException {
+    }
+
+    /**
+     * Sets the X-Frame-Options response header
+     *
+     * @param request servlet request.
+     * @param response servlet response.
+     * @param chain filter chain.
+     *
+     * @throws IOException thrown if an IO error occurrs.
+     * @throws ServletException thrown if a servet error occurrs.
+     */
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain)
+        throws IOException, ServletException {
+        chain.doFilter(request, response);
+        if (response instanceof HttpServletResponse) {
+            final HttpServletResponse httpResponse = (HttpServletResponse) 
response;
+            httpResponse.addHeader(X_FRAME_OPTIONS, X_FRAME_OPTION_DENY);
+        }
+    }
+
+    /**
+     * Destroys the filter.
+     * <p>
+     * This implementation is a NOP.
+     */
+    @Override
+    public void destroy() {
+    }
+}
diff --git 
a/core/src/test/java/org/apache/oozie/servlet/DagServletTestCase.java 
b/core/src/test/java/org/apache/oozie/servlet/DagServletTestCase.java
index ce731a1..bf6685d 100644
--- a/core/src/test/java/org/apache/oozie/servlet/DagServletTestCase.java
+++ b/core/src/test/java/org/apache/oozie/servlet/DagServletTestCase.java
@@ -87,8 +87,9 @@ public abstract class DagServletTestCase extends 
XDataTestCase {
             for (int i = 0; i < servletPath.length; i++) {
                 container.addServletEndpoint(servletPath[i], servletClass[i]);
             }
-            container.addFilter("*", HostnameFilter.class);
-            container.addFilter("*", AuthFilter.class);
+            container.addFilter("/*", HostnameFilter.class);
+            container.addFilter("/*", AuthFilter.class);
+            container.addFilter("/*", HttpResponseHeaderFilter.class);
             setSystemProperty("user.name", getTestUser());
             container.start();
             assertions.call();
diff --git 
a/core/src/test/java/org/apache/oozie/servlet/TestAuthFilterAuthOozieClient.java
 
b/core/src/test/java/org/apache/oozie/servlet/TestAuthFilterAuthOozieClient.java
index bc469e2..0f9a9ea 100644
--- 
a/core/src/test/java/org/apache/oozie/servlet/TestAuthFilterAuthOozieClient.java
+++ 
b/core/src/test/java/org/apache/oozie/servlet/TestAuthFilterAuthOozieClient.java
@@ -104,8 +104,9 @@ public class TestAuthFilterAuthOozieClient extends 
XTestCase {
             container.addServletEndpoint("/versions", 
HeaderTestingVersionServlet.class);
             String version = "/v" + XOozieClient.WS_PROTOCOL_VERSION;
             container.addServletEndpoint(version + "/admin/*", 
V1AdminServlet.class);
-            container.addFilter("*", HostnameFilter.class);
+            container.addFilter("/*", HostnameFilter.class);
             container.addFilter("/*", AuthFilter.class);
+            container.addFilter("/*", HttpResponseHeaderFilter.class);
             container.start();
             assertions.call();
             return getCacheFile(container.getContextURL());
diff --git 
a/core/src/test/java/org/apache/oozie/servlet/TestBulkMonitorWebServiceAPI.java 
b/core/src/test/java/org/apache/oozie/servlet/TestBulkMonitorWebServiceAPI.java
index b4054b0..159fba6 100644
--- 
a/core/src/test/java/org/apache/oozie/servlet/TestBulkMonitorWebServiceAPI.java
+++ 
b/core/src/test/java/org/apache/oozie/servlet/TestBulkMonitorWebServiceAPI.java
@@ -126,8 +126,9 @@ public class TestBulkMonitorWebServiceAPI extends 
XDataTestCase {
             for (int i = 0; i < servletPath.length; i++) {
                 container.addServletEndpoint(servletPath[i], servletClass[i]);
             }
-            container.addFilter("*", HostnameFilter.class);
-            container.addFilter("*", AuthFilter.class);
+            container.addFilter("/*", HostnameFilter.class);
+            container.addFilter("/*", AuthFilter.class);
+            container.addFilter("/*", HttpResponseHeaderFilter.class);
             setSystemProperty("user.name", getTestUser());
             container.start();
             assertions.call();
diff --git 
a/core/src/test/java/org/apache/oozie/servlet/TestHttpResponseHeaderFilter.java 
b/core/src/test/java/org/apache/oozie/servlet/TestHttpResponseHeaderFilter.java
new file mode 100644
index 0000000..65447c6
--- /dev/null
+++ 
b/core/src/test/java/org/apache/oozie/servlet/TestHttpResponseHeaderFilter.java
@@ -0,0 +1,62 @@
+/**
+ * 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.oozie.servlet;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.verify;
+
+public class TestHttpResponseHeaderFilter {
+
+    @Test
+    public void testXFrameOptionAgainstClickjackingAdded() throws Exception {
+        ServletRequest request = Mockito.mock(ServletRequest.class);
+        HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+        doNothing().when(response).addHeader(any(String.class), 
any(String.class));
+
+        final AtomicBoolean invoked = new AtomicBoolean();
+
+        FilterChain chain = new FilterChain() {
+            @Override
+            public void doFilter(ServletRequest servletRequest, 
ServletResponse servletResponse) {
+                invoked.set(true);
+            }
+        };
+
+        Filter filter = new HttpResponseHeaderFilter();
+        filter.init(null);
+        filter.doFilter(request, response, chain);
+        verify( response).addHeader(HttpResponseHeaderFilter.X_FRAME_OPTIONS, 
HttpResponseHeaderFilter.X_FRAME_OPTION_DENY);
+        assertTrue("Filter is not invoked", invoked.get());
+        filter.destroy();
+    }
+
+
+}
\ No newline at end of file
diff --git a/release-log.txt b/release-log.txt
index 339b930..2dcdf06 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -1,5 +1,6 @@
 -- Oozie 5.2.0 release (trunk - unreleased)
 
+OOZIE-3427 [core] Use best practices in HTTP response headers (asalamon74 via 
andras.piros)
 OOZIE-2949 Escape quotes whitespaces in Sqoop <command> field (asalamon74 via 
kmarton) 
 OOZIE-3426 [core] V1JobsServlet should log HDFS related error when trying to 
save workflow definition (asalamon74 via andras.piros)
 OOZIE-3417 [FS Action] Refactor and optimize FsActionExecutor.java decision 
making part (nobigo via asalamon74, kmarton)
diff --git a/server/src/main/java/org/apache/oozie/server/FilterMapper.java 
b/server/src/main/java/org/apache/oozie/server/FilterMapper.java
index 3dc9be8..b5d59fd 100644
--- a/server/src/main/java/org/apache/oozie/server/FilterMapper.java
+++ b/server/src/main/java/org/apache/oozie/server/FilterMapper.java
@@ -21,6 +21,7 @@ package org.apache.oozie.server;
 import com.google.common.base.Preconditions;
 import com.google.inject.Inject;
 import org.apache.oozie.servlet.AuthFilter;
+import org.apache.oozie.servlet.HttpResponseHeaderFilter;
 import org.apache.oozie.servlet.HostnameFilter;
 import org.eclipse.jetty.servlet.FilterHolder;
 import org.eclipse.jetty.webapp.WebAppContext;
@@ -41,6 +42,7 @@ public class FilterMapper {
      * */
     void addFilters() {
         mapFilter(new FilterHolder(new HostnameFilter()), "/*");
+        mapFilter(new FilterHolder(new HttpResponseHeaderFilter()), "/*");
 
         FilterHolder authFilter = new FilterHolder(new AuthFilter());
         mapFilter(authFilter, "/versions/*");
@@ -55,8 +57,8 @@ public class FilterMapper {
         mapFilter(authFilter, "/error/*");
     }
 
-    private void mapFilter(FilterHolder authFilter, String pathSpec) {
-        servletContextHandler.addFilter(authFilter, pathSpec,
+    private void mapFilter(FilterHolder filterHolder, String pathSpec) {
+        servletContextHandler.addFilter(filterHolder, pathSpec,
                 EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, 
DispatcherType.INCLUDE));
     }
 }
diff --git 
a/server/src/test/java/org/apache/oozie/server/TestEmbeddedOozieServer.java 
b/server/src/test/java/org/apache/oozie/server/TestEmbeddedOozieServer.java
index 58543e6..d9784ac 100644
--- a/server/src/test/java/org/apache/oozie/server/TestEmbeddedOozieServer.java
+++ b/server/src/test/java/org/apache/oozie/server/TestEmbeddedOozieServer.java
@@ -46,8 +46,8 @@ import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -113,6 +113,7 @@ public class TestEmbeddedOozieServer {
 
         embeddedOozieServer.setup();
         verify(mockJspHandler).setupWebAppContext(isA(WebAppContext.class));
+        verify(oozieFilterMapper).addFilters();
 
         // trustore parameters will have to be set even in case of an insecure 
setup
         Assert.assertEquals(confTruststoreFile, 
System.getProperty("javax.net.ssl.trustStore"));
@@ -130,6 +131,7 @@ public class TestEmbeddedOozieServer {
 
         embeddedOozieServer.setup();
         verify(mockJspHandler).setupWebAppContext(isA(WebAppContext.class));
+        verify(oozieFilterMapper).addFilters();
 
         Assert.assertEquals(truststorePath2, 
System.getProperty("javax.net.ssl.trustStore"));
         verify(mockConfiguration, 
never()).get(EmbeddedOozieServer.OOZIE_HTTPS_TRUSTSTORE_FILE);
@@ -148,6 +150,7 @@ public class TestEmbeddedOozieServer {
         embeddedOozieServer.setup();
 
         verify(mockJspHandler).setupWebAppContext(isA(WebAppContext.class));
+        verify(oozieFilterMapper).addFilters();
         verify(mockSSLServerConnectorFactory).createSecureServerConnector(
                 isA(Integer.class), isA(Configuration.class), 
isA(Server.class));
         Assert.assertEquals(confTruststoreFile, 
System.getProperty("javax.net.ssl.trustStore"));
diff --git a/webapp/src/main/webapp/WEB-INF/web.xml 
b/webapp/src/main/webapp/WEB-INF/web.xml
index 2edbdf1..59b9cd5 100644
--- a/webapp/src/main/webapp/WEB-INF/web.xml
+++ b/webapp/src/main/webapp/WEB-INF/web.xml
@@ -271,6 +271,11 @@
         <filter-class>org.apache.oozie.servlet.AuthFilter</filter-class>
     </filter>
 
+    <filter>
+        <filter-name>httpresponseFilter</filter-name>
+        
<filter-class>org.apache.oozie.servlet.HttpResponseHeaderFilter</filter-class>
+    </filter>
+
     <filter-mapping>
         <filter-name>hostnameFilter</filter-name>
         <url-pattern>/*</url-pattern>
@@ -316,4 +321,9 @@
         <url-pattern>/docs/*</url-pattern>
     </filter-mapping>
 
+    <filter-mapping>
+        <filter-name>httpresponseFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
 </web-app>

Reply via email to