Index: src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java (revision 1756173) +++ src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java (revision ) @@ -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 static final String DISABLED = "disabled"; /** - * Request content types for CSRF checking, see JCR-3909 - */ - public static final Set CONTENT_TYPES = Collections.unmodifiableSet(new HashSet( - 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 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(); + String host = new URL(refHeader).getHost(); - // test referrer-host equals server or + // 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); + // 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 Index: src/test/java/org/apache/jackrabbit/webdav/server/WebdavServerTests.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/test/java/org/apache/jackrabbit/webdav/server/WebdavServerTests.java (revision 1756132) +++ src/test/java/org/apache/jackrabbit/webdav/server/WebdavServerTests.java (revision ) @@ -26,6 +26,7 @@ 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); Index: src/test/java/org/apache/jackrabbit/webdav/server/PostTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/test/java/org/apache/jackrabbit/webdav/server/PostTest.java (revision ) +++ src/test/java/org/apache/jackrabbit/webdav/server/PostTest.java (revision ) @@ -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). + *

+ * Required system properties: + *

+ */ + +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); + } +} Index: src/test/java/org/apache/jackrabbit/webdav/util/CSRFUtilTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/test/java/org/apache/jackrabbit/webdav/util/CSRFUtilTest.java (revision 1756173) +++ src/test/java/org/apache/jackrabbit/webdav/util/CSRFUtilTest.java (revision ) @@ -29,14 +29,11 @@ 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; /** * CSRFUtilTest... @@ -45,85 +42,64 @@ private static final String SERVER_NAME = "localhost"; - private static final String GET = "GET"; - private static final String POST = "POST"; - - private static final Set EMPTY_REFERER = new HashSet() {{ add(null); }}; - private static final List validURLs = new ArrayList(); - private static final List invalidURLs = new ArrayList(); 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 validURLs, String method, Set contentTypes) throws MalformedURLException { - if (null == contentTypes) { + private static void testValid(CSRFUtil util, Collection validURLs) throws MalformedURLException { - for (String url : validURLs) { + for (String url : validURLs) { - assertTrue(url, util.isValidRequest(createRequest(url, method, null))); + assertTrue(url, util.isValidRequest(createRequest(url))); - } + } - } else { - for (String contentType : contentTypes) { - for (String url : validURLs) { - assertTrue(url, util.isValidRequest(createRequest(url, method, contentType))); - } + } - } - } - } - private static void testInvalid(CSRFUtil util, Collection invalidURLs, String method, Set contentTypes) throws MalformedURLException { - if (null == contentTypes) { - for (String url : validURLs) { - assertFalse(url, util.isValidRequest(createRequest(url, method, null))); - } - } else { - for (String contentType : contentTypes) { + private static void testInvalid(CSRFUtil util, Collection invalidURLs) throws MalformedURLException { - for (String url : invalidURLs) { + for (String url : invalidURLs) { - assertFalse(url, util.isValidRequest(createRequest(url, method, contentType))); + 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); + + testValid(util, validURLs); + + List invalidURLs = new ArrayList(); + invalidURLs.add("http://invalidHost/test"); + invalidURLs.add("http://host1:8080/test"); + invalidURLs.add("http://user:pw@host2/test"); + testInvalid(util, invalidURLs); } 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 invalidURLs = new ArrayList(); + 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 { - CSRFUtil util = new CSRFUtil(""); - testValid(util, validURLs, POST, EMPTY_REFERER); - testInvalid(util, invalidURLs, POST, EMPTY_REFERER); - } - 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 otherHosts = new ArrayList(); + 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 @@ 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(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 @@ return 0; } public String getMethod() { - return method; + return null; } public String getPathInfo() { return null; @@ -275,7 +240,7 @@ return 0; } public String getContentType() { - return contentType; + return null; } public ServletInputStream getInputStream() throws IOException { return null; \ No newline at end of file Index: src/main/java/org/apache/jackrabbit/webdav/server/AbstractWebdavServlet.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/main/java/org/apache/jackrabbit/webdav/server/AbstractWebdavServlet.java (revision 1756132) +++ src/main/java/org/apache/jackrabbit/webdav/server/AbstractWebdavServlet.java (revision ) @@ -596,7 +596,7 @@ */ 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 @@ * @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) {