You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dj...@apache.org on 2016/08/17 09:55:14 UTC

svn commit: r1756604 - in /jackrabbit/trunk/jackrabbit-webdav/src: main/java/org/apache/jackrabbit/webdav/server/ main/java/org/apache/jackrabbit/webdav/util/ test/java/org/apache/jackrabbit/webdav/server/ test/java/org/apache/jackrabbit/webdav/util/

Author: dj
Date: Wed Aug 17 09:55:14 2016
New Revision: 1756604

URL: http://svn.apache.org/viewvc?rev=1756604&view=rev
Log:
JCR-4002 : CSRF in Jackrabbit-Webdav using empty content-type

Added:
    jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/server/PostTest.java   (with props)
Modified:
    jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/server/AbstractWebdavServlet.java
    jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java
    jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/server/WebdavServerTests.java
    jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/CSRFUtilTest.java

Modified: jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/server/AbstractWebdavServlet.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/server/AbstractWebdavServlet.java?rev=1756604&r1=1756603&r2=1756604&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/server/AbstractWebdavServlet.java (original)
+++ jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/server/AbstractWebdavServlet.java Wed Aug 17 09:55:14 2016
@@ -596,7 +596,7 @@ abstract public class AbstractWebdavServ
      */
     protected void doPost(WebdavRequest request, WebdavResponse response,
                           DavResource resource) throws IOException, DavException {
-        doPut(request, response, resource);
+        response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
     }
 
     /**
@@ -1384,7 +1384,6 @@ abstract public class AbstractWebdavServ
      * @param out
      * @return
      * @see #doPut(WebdavRequest, WebdavResponse, DavResource)
-     * @see #doPost(WebdavRequest, WebdavResponse, DavResource)
      * @see #doMkCol(WebdavRequest, WebdavResponse, DavResource)
      */
     protected OutputContext getOutputContext(DavServletResponse response, OutputStream out) {

Modified: jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java?rev=1756604&r1=1756603&r2=1756604&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java (original)
+++ jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java Wed Aug 17 09:55:14 2016
@@ -16,14 +16,12 @@
  */
 package org.apache.jackrabbit.webdav.util;
 
-import org.apache.jackrabbit.webdav.DavMethods;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.servlet.http.HttpServletRequest;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
@@ -39,20 +37,6 @@ public class CSRFUtil {
     public static final String DISABLED = "disabled";
 
     /**
-     * Request content types for CSRF checking, see JCR-3909
-     */
-    public static final Set<String> CONTENT_TYPES = Collections.unmodifiableSet(new HashSet<String>(
-            Arrays.asList(
-                    new String[] {
-                            "application/x-www-form-urlencoded",
-                            "multipart/form-data",
-                            "text/plain",
-                            null // no content type included in request
-                    }
-            )
-    ));
-
-    /**
      * logger instance
      */
     private static final Logger log = LoggerFactory.getLogger(CSRFUtil.class);
@@ -109,21 +93,19 @@ public class CSRFUtil {
     }
 
     public boolean isValidRequest(HttpServletRequest request) throws MalformedURLException {
-        int methodCode = DavMethods.getMethodCode(request.getMethod());
-        if (disabled || DavMethods.DAV_POST != methodCode || !CONTENT_TYPES.contains(request.getContentType())) {
+        if (disabled) {
             return true;
         } else {
-
             String refHeader = request.getHeader("Referer");
-            // empty referrer headers are not allowed for POST + relevant content types (see JCR-3909)
             if (refHeader == null) {
-                return false;
+                // empty referrer is always allowed
+                return true;
+            } else {
+                String host = new URL(refHeader).getHost();
+                // test referrer-host equelst server or
+                // if it is contained in the set of explicitly allowed host names
+                return host.equals(request.getServerName()) || allowedReferrerHosts.contains(host);
             }
-
-            String host = new URL(refHeader).getHost();
-            // test referrer-host equals server or
-            // if it is contained in the set of explicitly allowed host names
-            return host.equals(request.getServerName()) || allowedReferrerHosts.contains(host);
         }
     }
 }
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/server/PostTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/server/PostTest.java?rev=1756604&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/server/PostTest.java (added)
+++ jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/server/PostTest.java Wed Aug 17 09:55:14 2016
@@ -0,0 +1,71 @@
+/*
+ * 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.jackrabbit.webdav.server;
+
+import junit.framework.TestCase;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.apache.commons.httpclient.methods.PostMethod;
+
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ * Test cases for the WebDAV servlet not executing the POST method (CSRF protection).
+ * <p>
+ * Required system properties:
+ * <ul>
+ * <li>webdav.test.url</li>
+ * <li>webdav.test.username</li>
+ * <li>webdav.test.password</li>
+ * </ul>
+ */
+
+public class PostTest extends TestCase {
+
+    private String root;
+    private URI uri;
+    private String username, password;
+    private HttpClient client;
+
+    protected void setUp() throws Exception {
+        this.uri = URI.create(System.getProperty("webdav.test.url"));
+        this.root = this.uri.toASCIIString();
+        if (!this.root.endsWith("/")) {
+            this.root += "/";
+        }
+        this.username = System.getProperty(("webdav.test.username"), "");
+        this.password = System.getProperty(("webdav.test.password"), "");
+        this.client = new HttpClient();
+        this.client.getState().setCredentials(
+                new AuthScope(this.uri.getHost(), this.uri.getPort()),
+                new UsernamePasswordCredentials(this.username, this.password));
+        super.setUp();
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testPostDenied() throws HttpException, IOException {
+        PostMethod options = new PostMethod(this.uri.toASCIIString());
+        int status = this.client.executeMethod(options);
+        assertEquals(405, status);
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/server/PostTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/server/WebdavServerTests.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/server/WebdavServerTests.java?rev=1756604&r1=1756603&r2=1756604&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/server/WebdavServerTests.java (original)
+++ jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/server/WebdavServerTests.java Wed Aug 17 09:55:14 2016
@@ -26,6 +26,7 @@ public class WebdavServerTests extends T
         TestSuite suite = new TestSuite("WebDAV Server Tests");
 
         suite.addTestSuite(BindTest.class);
+        suite.addTestSuite(PostTest.class);
         suite.addTestSuite(RFC4918DestinationHeaderTest.class);
         suite.addTestSuite(RFC4918IfHeaderTest.class);
         suite.addTestSuite(RFC4918PropfindTest.class);

Modified: jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/CSRFUtilTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/CSRFUtilTest.java?rev=1756604&r1=1756603&r2=1756604&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/CSRFUtilTest.java (original)
+++ jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/CSRFUtilTest.java Wed Aug 17 09:55:14 2016
@@ -29,14 +29,11 @@ import java.io.UnsupportedEncodingExcept
 import java.net.MalformedURLException;
 import java.security.Principal;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Enumeration;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * <code>CSRFUtilTest</code>...
@@ -45,85 +42,64 @@ public class CSRFUtilTest extends TestCa
 
     private static final String SERVER_NAME = "localhost";
 
-    private static final String GET = "GET";
-    private static final String POST = "POST";
-
-    private static final Set<String> EMPTY_REFERER = new HashSet<String>() {{ add(null); }};
-
     private static final List<String> validURLs = new ArrayList<String>();
-    private static final List<String> invalidURLs = new ArrayList<String>();
 
     static {
+        validURLs.add(null);
         validURLs.add("http://localhost:4503/jackrabbit/server");
         validURLs.add("https://localhost:4503/jackrabbit/server");
         validURLs.add("https://localhost/jackrabbit/server");
-
-        invalidURLs.add("http://invalidHost/test");
-        invalidURLs.add("http://host1:8080/test");
-        invalidURLs.add("http://user:pw@host2/test");
     }
 
-    private static void testValid(CSRFUtil util, Collection<String> validURLs, String method, Set<String> contentTypes) throws MalformedURLException {
-        if (null == contentTypes) {
-            for (String url : validURLs) {
-                assertTrue(url, util.isValidRequest(createRequest(url, method, null)));
-            }
-        } else {
-            for (String contentType : contentTypes) {
-                for (String url : validURLs) {
-                    assertTrue(url, util.isValidRequest(createRequest(url, method, contentType)));
-                }
-            }
+    private static void testValid(CSRFUtil util, Collection<String> validURLs) throws MalformedURLException {
+        for (String url : validURLs) {
+            assertTrue(url, util.isValidRequest(createRequest(url)));
         }
     }
 
-    private static void testInvalid(CSRFUtil util, Collection<String> invalidURLs, String method, Set<String> contentTypes) throws MalformedURLException {
-        if (null == contentTypes) {
-            for (String url : validURLs) {
-                assertFalse(url, util.isValidRequest(createRequest(url, method, null)));
-            }
-        } else {
-            for (String contentType : contentTypes) {
-                for (String url : invalidURLs) {
-                    assertFalse(url, util.isValidRequest(createRequest(url, method, contentType)));
-                }
-            }
+    private static void testInvalid(CSRFUtil util, Collection<String> invalidURLs) throws MalformedURLException {
+        for (String url : invalidURLs) {
+            assertFalse(url, util.isValidRequest(createRequest(url)));
         }
     }
 
-    private static HttpServletRequest createRequest(String url, String method, String contentType) {
-        return new DummyRequest(url, SERVER_NAME, method, contentType);
+    private static HttpServletRequest createRequest(String url) {
+        return new DummyRequest(url, SERVER_NAME);
     }
 
     public void testNullConfig() throws Exception {
         CSRFUtil util = new CSRFUtil(null);
-        testValid(util, validURLs, POST, CSRFUtil.CONTENT_TYPES);
-        testInvalid(util, invalidURLs, POST, CSRFUtil.CONTENT_TYPES);
-    }
 
-    public void testEmptyConfig() throws Exception {
-        CSRFUtil util = new CSRFUtil("");
-        testValid(util, validURLs, POST, CSRFUtil.CONTENT_TYPES);
-        testInvalid(util, invalidURLs, POST, CSRFUtil.CONTENT_TYPES);
-    }
+        testValid(util, validURLs);
 
-    public void testNoReferrer() throws Exception {
-        CSRFUtil util = new CSRFUtil("");
-        testValid(util, validURLs, POST, CSRFUtil.CONTENT_TYPES);
-        assertFalse("no referrer", util.isValidRequest(createRequest(null, POST, "text/plain")));
+        List<String> invalidURLs = new ArrayList<String>();
+        invalidURLs.add("http://invalidHost/test");
+        invalidURLs.add("http://host1:8080/test");
+        invalidURLs.add("http://user:pw@host2/test");
+        testInvalid(util, invalidURLs);
     }
 
-    public void testNoContentType() throws Exception {
+    public void testEmptyConfig() throws Exception {
         CSRFUtil util = new CSRFUtil("");
-        testValid(util, validURLs, POST, EMPTY_REFERER);
-        testInvalid(util, invalidURLs, POST, EMPTY_REFERER);
+        testValid(util, validURLs);
+
+        List<String> invalidURLs = new ArrayList<String>();
+        invalidURLs.add("http://invalidHost/test");
+        invalidURLs.add("http://host1:8080/test");
+        invalidURLs.add("http://user:pw@host2/test");
+        testInvalid(util, invalidURLs);
     }
 
     public void testDisabledConfig() throws Exception {
         CSRFUtil util = new CSRFUtil(CSRFUtil.DISABLED);
-        testValid(util, validURLs, POST, CSRFUtil.CONTENT_TYPES);
+        testValid(util, validURLs);
+
         // since test is disabled any other referer host must be allowed
-        testValid(util, invalidURLs, POST, CSRFUtil.CONTENT_TYPES);
+        List<String> otherHosts = new ArrayList<String>();
+        otherHosts.add("http://validHost:80/test");
+        otherHosts.add("http://host1/test");
+        otherHosts.add("https://user:pw@host2/test");
+        testValid(util, otherHosts);
     }
 
     public void testConfig() throws Exception {
@@ -145,31 +121,20 @@ public class CSRFUtilTest extends TestCa
 
         for (String config : configs) {
             CSRFUtil util = new CSRFUtil(config);
-            testValid(util, validURLs, POST, CSRFUtil.CONTENT_TYPES);
-            testValid(util, otherHosts, POST, CSRFUtil.CONTENT_TYPES);
-            testInvalid(util, invalidURLs, POST, CSRFUtil.CONTENT_TYPES);
+            testValid(util, validURLs);
+            testValid(util, otherHosts);
+            testInvalid(util, invalidURLs);
         }
     }
 
-    public void testMethodsAndMediaType() throws Exception {
-        CSRFUtil util = new CSRFUtil("");
-        testValid(util, invalidURLs, GET, CSRFUtil.CONTENT_TYPES);
-        testValid(util, invalidURLs, POST, new HashSet<String>(Arrays.asList(new String[] {"application/json"})));
-        testInvalid(util, invalidURLs, POST, CSRFUtil.CONTENT_TYPES);
-    }
-
     private static final class DummyRequest implements HttpServletRequest {
 
         private final String referer;
         private final String serverName;
-        private final String method;
-        private final String contentType;
 
-        private DummyRequest(String referer, String serverName, String method, String contentType) {
+        private DummyRequest(String referer, String serverName) {
             this.referer = referer;
             this.serverName = serverName;
-            this.method = method;
-            this.contentType = contentType;
         }
 
         //---------------------------------------------< HttpServletRequest >---
@@ -206,7 +171,7 @@ public class CSRFUtilTest extends TestCa
             return 0;
         }
         public String getMethod() {
-            return method;
+            return null;
         }
         public String getPathInfo() {
             return null;
@@ -275,7 +240,7 @@ public class CSRFUtilTest extends TestCa
             return 0;
         }
         public String getContentType() {
-            return contentType;
+            return null;
         }
         public ServletInputStream getInputStream() throws IOException {
             return null;