jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r1152258 - in /jackrabbit/trunk: jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/ jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/simple/ jackrabbit-standalone/src/main/resources/WEB-INF/ jackrabbit-web...
Date Fri, 29 Jul 2011 15:16:18 GMT
Author: angela
Date: Fri Jul 29 15:16:16 2011
New Revision: 1152258

URL: http://svn.apache.org/viewvc?rev=1152258&view=rev
Log:
JCR-3036 - WebDAV/DaveX Servlets susceptible to CSRF Attacks (apply patch provided by lars
krapf with minor modifications)
In addition: minor improvement moving common init-code to AbstractWebdavServlet

Added:
    jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java
  (with props)
    jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/
    jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/CSRFUtilTest.java
  (with props)
    jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/TestAll.java
  (with props)
Modified:
    jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/JCRWebdavServerServlet.java
    jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/simple/SimpleWebdavServlet.java
    jackrabbit/trunk/jackrabbit-standalone/src/main/resources/WEB-INF/web.xml
    jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/web.xml
    jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/server/AbstractWebdavServlet.java

Modified: jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/JCRWebdavServerServlet.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/JCRWebdavServerServlet.java?rev=1152258&r1=1152257&r2=1152258&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/JCRWebdavServerServlet.java
(original)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/JCRWebdavServerServlet.java
Fri Jul 29 15:16:16 2011
@@ -60,20 +60,6 @@ public abstract class JCRWebdavServerSer
     public static final String INIT_PARAM_RESOURCE_PATH_PREFIX = "resource-path-prefix";
 
     /**
-     * Name of the optional init parameter that defines the value of the
-     * 'WWW-Authenticate' header.<p/>
-     * If the parameter is omitted the default value
-     * {@link #DEFAULT_AUTHENTICATE_HEADER "Basic Realm=Jackrabbit Webdav Server"}
-     * is used.
-     *
-     * @see #getAuthenticateHeaderValue()
-     */
-    public static final String INIT_PARAM_AUTHENTICATE_HEADER = "authenticate-header";
-
-    /** the 'missing-auth-mapping' init parameter */
-    public final static String INIT_PARAM_MISSING_AUTH_MAPPING = "missing-auth-mapping";
-
-    /**
      * Optional 'concurrency-level' parameter defining the concurrency level
      * within the jcr-server. If the parameter is omitted the internal default
      * value (50) is used.
@@ -88,7 +74,6 @@ public abstract class JCRWebdavServerSer
     public static final String CTX_ATTR_RESOURCE_PATH_PREFIX = "jackrabbit.webdav.jcr.resourcepath";
 
     private String pathPrefix;
-    private String authenticate_header;
 
     private JCRWebdavServer server;
     private DavResourceFactory resourceFactory;
@@ -114,12 +99,6 @@ public abstract class JCRWebdavServerSer
         getServletContext().setAttribute(CTX_ATTR_RESOURCE_PATH_PREFIX, pathPrefix);
         log.debug(INIT_PARAM_RESOURCE_PATH_PREFIX + " = " + pathPrefix);
 
-        authenticate_header = getInitParameter(INIT_PARAM_AUTHENTICATE_HEADER);
-        if (authenticate_header == null) {
-            authenticate_header = DEFAULT_AUTHENTICATE_HEADER;
-        }
-        log.debug(INIT_PARAM_AUTHENTICATE_HEADER + " = " + authenticate_header);
-
         txMgr = new TxLockManagerImpl();
         subscriptionMgr = new SubscriptionManagerImpl();
         txMgr.addTransactionListener((SubscriptionManagerImpl) subscriptionMgr);
@@ -249,18 +228,6 @@ public abstract class JCRWebdavServerSer
     }
 
     /**
-     * Returns the init param of the servlet configuration or
-     * {@link #DEFAULT_AUTHENTICATE_HEADER} as default value.
-     *
-     * @return corresponding init parameter or {@link #DEFAULT_AUTHENTICATE_HEADER}.
-     * @see #INIT_PARAM_AUTHENTICATE_HEADER
-     */
-    @Override
-    public String getAuthenticateHeaderValue() {
-        return authenticate_header;
-    }
-
-    /**
      * Modified variant needed for JCR move and copy that isn't compliant to
      * WebDAV. The latter requires both methods to fail if the destination already
      * exists and Overwrite is set to F (false); in JCR however this depends on

Modified: jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/simple/SimpleWebdavServlet.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/simple/SimpleWebdavServlet.java?rev=1152258&r1=1152257&r2=1152258&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/simple/SimpleWebdavServlet.java
(original)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/simple/SimpleWebdavServlet.java
Fri Jul 29 15:16:16 2011
@@ -66,20 +66,6 @@ public abstract class SimpleWebdavServle
     public static final String INIT_PARAM_RESOURCE_PATH_PREFIX = "resource-path-prefix";
 
     /**
-     * Name of the optional init parameter that defines the value of the
-     * 'WWW-Authenticate' header.<p/>
-     * If the parameter is omitted the default value
-     * {@link #DEFAULT_AUTHENTICATE_HEADER "Basic Realm=Jackrabbit Webdav Server"}
-     * is used.
-     *
-     * @see #getAuthenticateHeaderValue()
-     */
-    public static final String INIT_PARAM_AUTHENTICATE_HEADER = "authenticate-header";
-
-    /** the 'missing-auth-mapping' init parameter */
-    public final static String INIT_PARAM_MISSING_AUTH_MAPPING = "missing-auth-mapping";
-
-    /**
      * Name of the init parameter that specify a separate configuration used
      * for filtering the resources displayed.
      */
@@ -105,11 +91,6 @@ public abstract class SimpleWebdavServle
     private String resourcePathPrefix;
 
     /**
-     * Header value as specified in the {@link #INIT_PARAM_AUTHENTICATE_HEADER} parameter.
-     */
-    private String authenticate_header;
-
-    /**
      * Map used to remember any webdav lock created without being reflected
      * in the underlying repository.
      * This is needed because some clients rely on a successful locking
@@ -162,12 +143,6 @@ public abstract class SimpleWebdavServle
         getServletContext().setAttribute(CTX_ATTR_RESOURCE_PATH_PREFIX, resourcePathPrefix);
         log.info(INIT_PARAM_RESOURCE_PATH_PREFIX + " = '" + resourcePathPrefix + "'");
 
-        authenticate_header = getInitParameter(INIT_PARAM_AUTHENTICATE_HEADER);
-        if (authenticate_header == null) {
-            authenticate_header = DEFAULT_AUTHENTICATE_HEADER;
-        }
-        log.info("WWW-Authenticate header = '" + authenticate_header + "'");
-
         config = new ResourceConfig(getDetector());
         String configParam = getInitParameter(INIT_PARAM_RESOURCE_CONFIG);
         if (configParam != null) {
@@ -387,20 +362,6 @@ public abstract class SimpleWebdavServle
     }
 
     /**
-     * Returns the header value retrieved from the {@link #INIT_PARAM_AUTHENTICATE_HEADER}
-     * init parameter. If the parameter is missing, the value defaults to
-     * {@link #DEFAULT_AUTHENTICATE_HEADER}.
-     *
-     * @return the header value retrieved from the corresponding init parameter
-     * or {@link #DEFAULT_AUTHENTICATE_HEADER}.
-     * @see AbstractWebdavServlet#getAuthenticateHeaderValue()
-     */
-    @Override
-    public String getAuthenticateHeaderValue() {
-        return authenticate_header;
-    }
-
-    /**
      * Returns the resource configuration to be applied
      *
      * @return the resource configuration.

Modified: jackrabbit/trunk/jackrabbit-standalone/src/main/resources/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-standalone/src/main/resources/WEB-INF/web.xml?rev=1152258&r1=1152257&r2=1152258&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-standalone/src/main/resources/WEB-INF/web.xml (original)
+++ jackrabbit/trunk/jackrabbit-standalone/src/main/resources/WEB-INF/web.xml Fri Jul 29 15:16:16
2011
@@ -44,7 +44,6 @@
             The webdav servlet that connects HTTP request to the repository.
         </description>
         <servlet-class>org.apache.jackrabbit.j2ee.SimpleWebdavServlet</servlet-class>
-
         <init-param>
             <param-name>resource-path-prefix</param-name>
             <param-value>/repository</param-value>
@@ -59,6 +58,22 @@
                 Defines various dav-resource configuration parameters.
             </description>
         </init-param>
+        <!--
+            Optional parameter to define the behaviour of the referrer-based CSRF protection
+        -->
+        <!--
+        <init-param>
+            <param-name>csrf-protection</param-name>
+            <param-value>host1.domain.com,host2.domain.org</param-value>
+            <description>
+                Defines the behaviour of the referrer based CSRF protection
+                1) If omitted or left empty the (default) behaviour is to allow only requests
with
+                   an empty referrer header or a referrer host equal to the server host
+                2) May also contain a comma separated list of additional allowed referrer
hosts
+                3) If set to 'disabled' no referrer checking will be performed at all
+            </description>
+        </init-param>
+        -->
         <load-on-startup>3</load-on-startup>
     </servlet>
 
@@ -133,6 +148,22 @@
         	<description>Number of concurrent requests expected. Default value is 50.</description>
         </init-param>
         -->
+        <!--
+            Optional parameter to define the behaviour of the referrer-based CSRF protection
+        -->
+        <!--
+        <init-param>
+            <param-name>csrf-protection</param-name>
+            <param-value>host1.domain.com,host2.domain.org</param-value>
+            <description>
+                Defines the behaviour of the referrer based CSRF protection
+                1) If omitted or left empty the (default) behaviour is to allow only requests
with
+                   an empty referrer header or a referrer host equal to the server host
+                2) May also contain a comma separated list of additional allowed referrer
hosts
+                3) If set to 'disabled' no referrer checking will be performed at all
+            </description>
+        </init-param>
+        -->
         <load-on-startup>5</load-on-startup>
     </servlet>
 

Modified: jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/web.xml?rev=1152258&r1=1152257&r2=1152258&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/web.xml (original)
+++ jackrabbit/trunk/jackrabbit-webapp/src/main/webapp/WEB-INF/web.xml Fri Jul 29 15:16:16
2011
@@ -147,7 +147,7 @@
           <description>
             If this is set, the RepositoryAccessServlet expects a Repository in the ServletContext

             attribute having this name. This allows servlets of this module to be used with
repositories
-            intialized by the jackrabbit-jcr-servlet module utilities.
+            initialized by the jackrabbit-jcr-servlet module utilities.
           </description>
         </init-param>
          -->
@@ -210,7 +210,7 @@
              <description>
                  Defines how a missing authorization header should be handled.
                  1) If this init-param is missing, a 401 response is generated.
-                    This is suiteable for clients (eg. webdav clients) for which
+                    This is suitable for clients (eg. webdav clients) for which
                     sending a proper authorization header is not possible if the
                     server never sent a 401.
                  2) If this init-param is present with an empty value,
@@ -237,7 +237,7 @@
         -->
         <!--
             Parameter used to configure behaviour of webdav resources such as:
-            - destinction between collections and non-collections
+            - distinction between collections and non-collections
             - resource filtering
         -->
         <init-param>
@@ -247,6 +247,22 @@
                 Defines various dav-resource configuration parameters.
             </description>
         </init-param>
+       <!--
+            Optional parameter to define the behaviour of the referrer-based CSRF protection
+        -->
+        <!--
+        <init-param>
+            <param-name>csrf-protection</param-name>
+            <param-value>host1.domain.com,host2.domain.org</param-value>
+            <description>
+                Defines the behaviour of the referrer based CSRF protection
+                1) If omitted or left empty the (default) behaviour is to allow only requests
with
+                   an empty referrer header or a referrer host equal to the server host
+                2) May also contain a comma separated list of additional allowed referrer
hosts
+                3) If set to 'disabled' no referrer checking will be performed at all
+            </description>
+        </init-param>
+        -->
         <load-on-startup>4</load-on-startup>
     </servlet>
 
@@ -265,7 +281,7 @@
             <description>
                 Defines how a missing authorization header should be handled.
                  1) If this init-param is missing, a 401 response is generated.
-                    This is suiteable for clients (eg. webdav clients) for which
+                    This is suitable for clients (eg. webdav clients) for which
                     sending a proper authorization header is not possible if the
                     server never sent a 401.
                  2) If this init-param is present with an empty value,
@@ -321,7 +337,22 @@
         	<param-value>50</param-value>
         	<description>Number of concurrent requests expected. Default value is 50.</description>
         </init-param -->
-        <load-on-startup>5</load-on-startup>
+        <!--
+            Optional parameter to define the behaviour of the referrer-based CSRF protection
+        -->
+        <!--
+        <init-param>
+            <param-name>csrf-protection</param-name>
+            <param-value>host1.domain.com,host2.domain.org</param-value>
+            <description>
+                Defines the behaviour of the referrer based CSRF protection
+                1) If omitted or left empty the (default) behaviour is to allow only requests
with
+                   an empty referrer header or a referrer host equal to the server host
+                2) May also contain a comma separated list of additional allowed referrer
hosts
+                3) If set to 'disabled' no referrer checking will be performed at all
+            </description>
+        </init-param>
+        -->       <load-on-startup>5</load-on-startup>
     </servlet>
 
     <!-- ====================================================================== -->

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=1152258&r1=1152257&r2=1152258&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
Fri Jul 29 15:16:16 2011
@@ -62,6 +62,7 @@ import org.apache.jackrabbit.webdav.secu
 import org.apache.jackrabbit.webdav.security.AclResource;
 import org.apache.jackrabbit.webdav.transaction.TransactionInfo;
 import org.apache.jackrabbit.webdav.transaction.TransactionResource;
+import org.apache.jackrabbit.webdav.util.CSRFUtil;
 import org.apache.jackrabbit.webdav.version.ActivityResource;
 import org.apache.jackrabbit.webdav.version.DeltaVConstants;
 import org.apache.jackrabbit.webdav.version.DeltaVResource;
@@ -101,6 +102,20 @@ abstract public class AbstractWebdavServ
      */
     private static Logger log = LoggerFactory.getLogger(AbstractWebdavServlet.class);
 
+    /** the 'missing-auth-mapping' init parameter */
+    public final static String INIT_PARAM_MISSING_AUTH_MAPPING = "missing-auth-mapping";
+
+    /**
+     * Name of the optional init parameter that defines the value of the
+     * 'WWW-Authenticate' header.<p/>
+     * If the parameter is omitted the default value
+     * {@link #DEFAULT_AUTHENTICATE_HEADER "Basic Realm=Jackrabbit Webdav Server"}
+     * is used.
+     *
+     * @see #getAuthenticateHeaderValue()
+     */
+    public static final String INIT_PARAM_AUTHENTICATE_HEADER = "authenticate-header";
+
     /**
      * Default value for the 'WWW-Authenticate' header, that is set, if request
      * results in a {@link DavServletResponse#SC_UNAUTHORIZED 401 (Unauthorized)}
@@ -111,6 +126,43 @@ abstract public class AbstractWebdavServ
     public static final String DEFAULT_AUTHENTICATE_HEADER = "Basic realm=\"Jackrabbit Webdav
Server\"";
 
     /**
+     * Name of the parameter that specifies the configuration of the CSRF protection.
+     * May contain a comma-separated list of allowed referrer hosts.
+     * If the parameter is omitted or left empty the behaviour is to only allow requests
which have an empty referrer
+     * or a referrer host equal to the server host.
+     * If the parameter is set to 'disabled' no referrer checks will be performed at all.
+     */
+    public static final String INIT_PARAM_CSRF_PROTECTION = "csrf-protection";
+
+
+    /**
+     * Header value as specified in the {@link #INIT_PARAM_AUTHENTICATE_HEADER} parameter.
+     */
+    private String authenticate_header;
+
+    /**
+     * CSRF protection utility
+     */
+    private CSRFUtil csrfUtil;
+
+    @Override
+    public void init() throws ServletException {
+        super.init();
+
+        // authenticate header
+        authenticate_header = getInitParameter(INIT_PARAM_AUTHENTICATE_HEADER);
+        if (authenticate_header == null) {
+            authenticate_header = DEFAULT_AUTHENTICATE_HEADER;
+        }
+        log.info(INIT_PARAM_AUTHENTICATE_HEADER + " = " + authenticate_header);
+        
+        // read csrf protection params
+        String csrfParam = getInitParameter(INIT_PARAM_CSRF_PROTECTION);
+        csrfUtil = new CSRFUtil(csrfParam);
+        log.info(INIT_PARAM_CSRF_PROTECTION + " = " + csrfParam);
+    }
+
+    /**
      * Checks if the precondition for this request and resource is valid.
      *
      * @param request
@@ -163,11 +215,15 @@ abstract public class AbstractWebdavServ
 
     /**
      * Returns the value of the 'WWW-Authenticate' header, that is returned in
-     * case of 401 error.
+     * case of 401 error: the value is retrireved from the corresponding init
+     * param or defaults to {@link #DEFAULT_AUTHENTICATE_HEADER}.
      *
-     * @return value of the 'WWW-Authenticate' header
+     * @return corresponding init parameter or {@link #DEFAULT_AUTHENTICATE_HEADER}.
+     * @see #INIT_PARAM_AUTHENTICATE_HEADER
      */
-    abstract public String getAuthenticateHeaderValue();
+    public String getAuthenticateHeaderValue() {
+        return authenticate_header;
+    }
 
     /**
      * Service the given request.
@@ -192,10 +248,16 @@ abstract public class AbstractWebdavServ
                 return;
             }
 
+            // perform referrer host checks if CSRF protection is enabled
+            if (!csrfUtil.isValidRequest(webdavRequest)) {
+                webdavResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
+                return;
+            }
+
             // check matching if=header for lock-token relevant operations
             DavResource resource = getResourceFactory().createResource(webdavRequest.getRequestLocator(),
webdavRequest, webdavResponse);
             if (!isPreconditionValid(webdavRequest, resource)) {
-                webdavResponse.sendError(DavServletResponse.SC_PRECONDITION_FAILED);
+                webdavResponse.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
                 return;
             }
             if (!execute(webdavRequest, webdavResponse, methodCode, resource)) {

Added: 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=1152258&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java
(added)
+++ jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java
Fri Jul 29 15:16:16 2011
@@ -0,0 +1,111 @@
+/*
+ * 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.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * <code>CSRFUtil</code>...
+ */
+public class CSRFUtil {
+
+    /**
+     * Constant used to
+     */
+    public static final String DISABLED = "disabled";
+
+    /**
+     * logger instance
+     */
+    private static final Logger log = LoggerFactory.getLogger(CSRFUtil.class);
+
+    /**
+     * Disable referrer based CSRF protection
+     */
+    private final boolean disabled;
+
+    /**
+     * Additional allowed referrer hosts for CSRF protection
+     */
+    private final Set<String> allowedReferrerHosts;
+
+    /**
+     * Creates a new instance from the specified configuration, which defines
+     * the behaviour of the referrer based CSRF protection as follows:
+     * <ol>
+     * <li>If config is <code>null</code> or empty string the default
+     * behaviour is to allow only requests with an empty referrer header or a
+     * referrer host equal to the server host</li>
+     * <li>A comma separated list of additional allowed referrer hosts which are
+     * valid in addition to default behaviour (see above).</li>
+     * <li>The value {@link #DISABLED} may be used to disable the referrer checking
altogether</li>
+     * </ol>
+     *
+     * @param config The configuration value which may be any of the following:
+     * <ul>
+     * <li><code>null</code> or empty string for the default behaviour,
which
+     * only allows requests with an empty referrer header or a
+     * referrer host equal to the server host</li>
+     * <li>A comma separated list of additional allowed referrer hosts which are
+     * valid in addition to default behaviour (see above).</li>
+     * <li>{@link #DISABLED} in order to disable the referrer checking altogether</li>
+     * </ul>
+     */
+    public CSRFUtil(String config) {
+        if (config == null || config.length() == 0) {
+            disabled = false;
+            allowedReferrerHosts = Collections.emptySet();
+        } else {
+            if (DISABLED.equalsIgnoreCase(config.trim())) {
+                disabled = true;
+                allowedReferrerHosts = Collections.emptySet();
+            } else {
+                disabled = false;
+                String[] allowed = config.split(",");
+                allowedReferrerHosts = new HashSet<String>(allowed.length);       
        
+                for (String entry : allowed) {
+                    allowedReferrerHosts.add(entry.trim());
+                }
+            }
+        }
+    }
+
+    public boolean isValidRequest(HttpServletRequest request) throws MalformedURLException
{
+        if (disabled) {
+            return true;
+        } else {
+            String refHeader = request.getHeader("Referer");
+            if (refHeader == null) {
+                // 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);
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/util/CSRFUtil.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: 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=1152258&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/CSRFUtilTest.java
(added)
+++ jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/CSRFUtilTest.java
Fri Jul 29 15:16:16 2011
@@ -0,0 +1,300 @@
+/*
+ * 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.util;
+
+import junit.framework.TestCase;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * <code>CSRFUtilTest</code>...
+ */
+public class CSRFUtilTest extends TestCase {
+
+    private static final String SERVER_NAME = "localhost";
+
+    private static final List<String> validURLs = 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");
+    }
+
+    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)
throws MalformedURLException {
+        for (String url : invalidURLs) {
+            assertFalse(url, util.isValidRequest(createRequest(url)));
+        }
+    }
+
+    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);
+
+        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 testEmptyConfig() throws Exception {
+        CSRFUtil util = new CSRFUtil("");
+        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);
+
+        // since test is disabled any other referer host must be allowed
+        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 {
+        List<String> configs = new ArrayList<String>();
+        configs.add("host1,host2");
+        configs.add(" host1 , host2 ");
+        configs.add("\rhost1,\rhost2\r");
+
+        // hosts listed in the config must be valid
+        List<String> otherHosts = new ArrayList<String>();
+        otherHosts.add("http://host1:80/test");
+        otherHosts.add("http://host1/test");
+        otherHosts.add("https://user:pw@host2/test");
+
+        List<String> invalidURLs = new ArrayList<String>();
+        invalidURLs.add("http://invalidHost/test");
+        invalidURLs.add("http://host3:8080/test");
+        invalidURLs.add("https://user:pw@host4/test");
+
+        for (String config : configs) {
+            CSRFUtil util = new CSRFUtil(config);
+            testValid(util, validURLs);
+            testValid(util, otherHosts);
+            testInvalid(util, invalidURLs);
+        }
+    }
+
+    private static final class DummyRequest implements HttpServletRequest {
+
+        private final String referer;
+        private final String serverName;
+
+        private DummyRequest(String referer, String serverName) {
+            this.referer = referer;
+            this.serverName = serverName;
+        }
+
+        //---------------------------------------------< HttpServletRequest >---
+
+        public String getHeader(String name) {
+            if ("Referer".equalsIgnoreCase(name)) {
+                return referer;
+            } else {
+                return null;
+            }
+        }
+
+        public String getServerName() {
+            return serverName;
+        }
+
+        //---------------------------------------------------------< unused >---
+        public String getAuthType() {
+            return null;
+        }
+        public Cookie[] getCookies() {
+            return new Cookie[0];
+        }
+        public long getDateHeader(String name) {
+            return 0;
+        }
+        public Enumeration getHeaders(String name) {
+            return null;
+        }
+        public Enumeration getHeaderNames() {
+            return null;
+        }
+        public int getIntHeader(String name) {
+            return 0;
+        }
+        public String getMethod() {
+            return null;
+        }
+        public String getPathInfo() {
+            return null;
+        }
+        public String getPathTranslated() {
+            return null;
+        }
+        public String getContextPath() {
+            return null;
+        }
+        public String getQueryString() {
+            return null;
+        }
+        public String getRemoteUser() {
+            return null;
+        }
+        public boolean isUserInRole(String role) {
+            return false;
+        }
+        public Principal getUserPrincipal() {
+            return null;
+        }
+        public String getRequestedSessionId() {
+            return null;
+        }
+        public String getRequestURI() {
+            return null;
+        }
+        public StringBuffer getRequestURL() {
+            return null;
+        }
+        public String getServletPath() {
+            return null;
+        }
+        public HttpSession getSession(boolean create) {
+            return null;
+        }
+        public HttpSession getSession() {
+            return null;
+        }
+        public boolean isRequestedSessionIdValid() {
+            return false;
+        }
+        public boolean isRequestedSessionIdFromCookie() {
+            return false;
+        }
+        public boolean isRequestedSessionIdFromURL() {
+            return false;
+        }
+        public boolean isRequestedSessionIdFromUrl() {
+            return false;
+        }
+        public Object getAttribute(String name) {
+            return null;
+        }
+        public Enumeration getAttributeNames() {
+            return null;
+        }
+        public String getCharacterEncoding() {
+            return null;
+        }
+        public void setCharacterEncoding(String s) throws UnsupportedEncodingException {
+
+        }
+        public int getContentLength() {
+            return 0;
+        }
+        public String getContentType() {
+            return null;
+        }
+        public ServletInputStream getInputStream() throws IOException {
+            return null;
+        }
+        public String getParameter(String name) {
+            return null;
+        }
+        public Enumeration getParameterNames() {
+            return null;
+        }
+        public String[] getParameterValues(String name) {
+            return new String[0];
+        }
+        public Map getParameterMap() {
+            return null;
+        }
+        public String getProtocol() {
+            return null;
+        }
+        public String getScheme() {
+            return null;
+        }
+        public int getServerPort() {
+            return 0;
+        }
+        public BufferedReader getReader() throws IOException {
+            return null;
+        }
+        public String getRemoteAddr() {
+            return null;
+        }
+        public String getRemoteHost() {
+            return null;
+        }
+        public void setAttribute(String name, Object o) {
+
+        }
+        public void removeAttribute(String name) {
+
+        }
+        public Locale getLocale() {
+            return null;
+        }
+        public Enumeration getLocales() {
+            return null;
+        }
+        public boolean isSecure() {
+            return false;
+        }
+        public RequestDispatcher getRequestDispatcher(String path) {
+            return null;
+        }
+        public String getRealPath(String path) {
+            return null;
+        }
+    }
+}
\ No newline at end of file

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

Propchange: jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/CSRFUtilTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/TestAll.java?rev=1152258&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/TestAll.java
(added)
+++ jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/TestAll.java
Fri Jul 29 15:16:16 2011
@@ -0,0 +1,39 @@
+/*
+ * 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.util;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite that includes all testcases for package org.apache.jackrabbit.webdav.util.
+ */
+public class TestAll extends TestCase {
+
+    /**
+     * Returns a <code>Test</code> suite that executes all tests inside this
+     * package.
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite("org.apache.jackrabbit.webdav.util tests");
+
+        suite.addTestSuite(CSRFUtilTest.class);
+
+        return suite;
+    }
+}

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

Propchange: jackrabbit/trunk/jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/util/TestAll.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL



Mime
View raw message