Really, actually, merge r23802 and r23803 from trunk to the
artem-soc-work branch.

Branch: artem-soc-work
(I tried to do this in r23805, but botched the copy. Sorry!)




git-svn-id: https://svn.apache.org/repos/asf/subversion/branches/artem-soc-work@863880 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/subversion/mod_dav_svn/authz.c b/subversion/mod_dav_svn/authz.c
index a332d88..e4a1a76 100644
--- a/subversion/mod_dav_svn/authz.c
+++ b/subversion/mod_dav_svn/authz.c
@@ -18,10 +18,12 @@
 
 #include <http_request.h>
 #include <http_log.h>
+#include <http_protocol.h>
 
 #include "svn_pools.h"
 #include "svn_path.h"
 
+#include "svn_dav.h"
 #include "dav_svn.h"
 
 
@@ -58,15 +60,31 @@
   /* Build a Version Resource uri representing (rev, path). */
   uri = dav_svn__build_uri(repos, uri_type, rev, path, FALSE, pool);
 
-  /* Check if GET would work against this uri. */
-  subreq = ap_sub_req_method_uri("GET", uri, r, r->output_filters);
-
-  if (subreq)
+  if (dav_svn__get_native_authz_file(r))
     {
-      if (subreq->status == HTTP_OK)
+      /* Do native auhorization lookup - read access */
+      dav_error *err = dav_svn__check_access(repos->repo_name,
+                                             path,
+                                             r,
+                                             svn_authz_read);
+
+      if (! err)
         allowed = TRUE;
 
-      ap_destroy_sub_req(subreq);
+      /* XXX: need to cleanup dav_error? */
+    }
+  else
+    {
+      /* Check if GET would work against this uri. */
+      subreq = ap_sub_req_method_uri("GET", uri, r, r->output_filters);
+
+      if (subreq)
+        {
+          if (subreq->status == HTTP_OK)
+            allowed = TRUE;
+
+          ap_destroy_sub_req(subreq);
+        }
     }
 
   return allowed;
@@ -180,3 +198,195 @@
   return allow_read(resource->info->r, resource->info->repos,
                     resource->info->repos_path, rev, pool);
 }
+
+
+/* Native path-based authorization */
+
+static int
+check_access(const char *repos_name,
+             const char *repos_path,
+             request_rec* r,
+             svn_repos_authz_access_t required_access)
+{
+  const char *authz_file = NULL;
+  svn_authz_t *access_conf = NULL;
+  svn_error_t *svn_err;
+  const char *cache_key;
+  void *user_data;
+  svn_boolean_t access_granted;
+  char errbuf[128];
+
+  /* If native authz is off, there's nothing to do. Return DONE
+   * instead of OK to indicate that no checks have really been done.
+   */
+  if (! dav_svn__get_native_authz_file(r))
+    return DONE;
+
+  authz_file = dav_svn__get_native_authz_file(r);
+  /* If access file had not been specified, the default
+     behavior is to allow access. 
+     XXX: is this right? */
+  if (authz_file == NULL)
+    return OK;
+
+  /* Retrieve/cache authorization file */
+  cache_key = apr_pstrcat(r->pool, "mod_dav_svn:", authz_file, NULL);
+  apr_pool_userdata_get(&user_data, cache_key, r->connection->pool);
+  access_conf = user_data;
+  if (access_conf == NULL)
+    {
+      svn_err = svn_repos_authz_read(&access_conf, authz_file,
+                                     TRUE, r->connection->pool);
+      if (svn_err)
+        {
+          ap_log_rerror(APLOG_MARK, APLOG_ERR,
+                        /* If it is an error code that APR can make sense
+                           of, then show it, otherwise, pass zero to avoid
+                           putting "APR does not understand this error code"
+                           in the error log. */
+                        ((svn_err->apr_err >= APR_OS_START_USERERR &&
+                          svn_err->apr_err < APR_OS_START_CANONERR) ?
+                         0 : svn_err->apr_err),
+                        r, "Failed to load the SVNNativeAuthzFile: %s",
+                        svn_err_best_message(svn_err,
+                                             errbuf, sizeof(errbuf)));
+          svn_error_clear(svn_err);
+
+          return DECLINED;
+        }
+
+      /* Cache the open repos for the next request on this connection */
+      apr_pool_userdata_set(access_conf, cache_key,
+                            NULL, r->connection->pool);
+  }
+
+  /* Perform authz access control. */
+  svn_err = svn_repos_authz_check_access(access_conf, repos_name,
+                                         repos_path, r->user,
+                                         required_access,
+                                         &access_granted,
+                                         r->pool);
+
+  if (svn_err)
+    {
+      ap_log_rerror(APLOG_MARK, APLOG_ERR,
+                    /* If it is an error code that APR can make
+                       sense of, then show it, otherwise, pass
+                       zero to avoid putting "APR does not
+                       understand this error code" in the error
+                       log. */
+                    ((svn_err->apr_err >= APR_OS_START_USERERR &&
+                      svn_err->apr_err < APR_OS_START_CANONERR) ?
+                     0 : svn_err->apr_err),
+                    r, "Failed to perform access control: %s",
+                    svn_err_best_message(svn_err, errbuf, sizeof(errbuf)));
+      svn_error_clear(svn_err);
+
+      return DECLINED;
+    }
+
+  if (! access_granted)
+    return DECLINED;
+
+  return OK;
+}
+
+
+/* Log a message indicating the access control decision made about a
+   request.  FILE and LINE should be supplied via the APLOG_MARK macro.
+   ALLOWED is boolean.  REPOS_PATH and DEST_REPOS_PATH are information
+   about the request.  DEST_REPOS_PATH may be NULL. */
+static void
+log_access_verdict(const char *file, int line,
+                   const request_rec *r,
+                   int allowed,
+                   const char *repos_path,
+                   svn_repos_authz_access_t required_access)
+{
+  int level = allowed ? APLOG_INFO : APLOG_ERR;
+  const char *verdict = allowed ? "granted" : "denied";
+
+  char access_str[4] = { 0, 0, 0, 0 };
+  int access_idx = 0;
+
+  if (required_access & svn_authz_read)
+    access_str[access_idx++] = 'r';
+
+  if (required_access & svn_authz_write)
+    access_str[access_idx++] = 'w';
+
+  if (required_access & svn_authz_recursive)
+    access_str[access_idx++] = 'R';
+
+  if (repos_path == NULL)
+    repos_path = "<global>";
+
+  if (r->user)
+  {
+    ap_log_rerror(file, line, level, 0, r,
+                  "[native] Access %s: '%s' %s %s %s", verdict, r->user,
+                  r->method, repos_path, access_str);
+  }
+  else
+  {
+    ap_log_rerror(file, line, level, 0, r,
+                  "[native] Access %s: - %s %s %s", verdict,
+                  r->method, repos_path, access_str);
+  }
+}
+
+
+dav_error *
+dav_svn__check_access(const char *repos_name,
+                      const char *repos_path,
+                      request_rec *r,
+                      svn_repos_authz_access_t required_access)
+{
+  int status;
+
+  status = check_access(repos_name, repos_path, r, required_access);
+
+  /* If no checks had been done, native authz is off, so don't log
+   * a possibly misleading authorization verdict.
+   */
+  if (status == DONE)
+    return NULL;
+
+  if(status == DECLINED)
+  {
+    log_access_verdict(APLOG_MARK, r, 0, repos_path, required_access);
+    ap_note_auth_failure(r); // XXX: need this?
+
+    // XXX: need better error message
+    return dav_svn__new_error_tag(r->pool, HTTP_FORBIDDEN, 0,
+                                  "Insufficient rights to access resource.",
+                                  SVN_DAV_ERROR_NAMESPACE,
+                                  SVN_DAV_ERROR_TAG);
+  }
+
+  log_access_verdict(APLOG_MARK, r, 1, repos_path, required_access);
+
+  return NULL;
+}
+
+
+dav_error *
+dav_svn__check_resource_access(const dav_resource *resource,
+                               const svn_repos_authz_access_t required_access)
+{
+  return dav_svn__check_access(resource->info->repos->repo_name,
+                               resource->info->repos_path,
+                               resource->info->r,
+                               required_access);
+}
+
+
+dav_error *
+dav_svn__check_global_access(const dav_resource *resource,
+                             const svn_repos_authz_access_t required_access)
+{
+  return dav_svn__check_access(resource->info->repos->repo_name,
+                               NULL, /* global access */
+                               resource->info->r,
+                               required_access);
+}
diff --git a/subversion/mod_dav_svn/dav_svn.h b/subversion/mod_dav_svn/dav_svn.h
index 142de4c..0e17456 100644
--- a/subversion/mod_dav_svn/dav_svn.h
+++ b/subversion/mod_dav_svn/dav_svn.h
@@ -255,6 +255,9 @@
    SVNParentPath allowed? */
 svn_boolean_t dav_svn__get_list_parentpath_flag(request_rec *r);
 
+/* for the repository referred to by this request, where is the access
+   file for native authz */
+const char *dav_svn__get_native_authz_file(request_rec *r);
 
 /* SPECIAL URI
 
@@ -537,6 +540,22 @@
 svn_repos_authz_func_t
 dav_svn__authz_read_func(dav_svn__authz_read_baton *baton);
 
+/* Native path-based authorization */
+dav_error *
+dav_svn__check_access(const char *repos_name,
+                      const char *repos_path,
+                      request_rec *r,
+                      svn_repos_authz_access_t required_access);
+
+/* Helpers for path-based authorization */
+dav_error *
+dav_svn__check_resource_access(const dav_resource *resource,
+                               const svn_repos_authz_access_t required_access);
+
+dav_error *
+dav_svn__check_global_access(const dav_resource *resource,
+                             const svn_repos_authz_access_t required_access);
+
 
 /*** util.c ***/
 
diff --git a/subversion/mod_dav_svn/lock.c b/subversion/mod_dav_svn/lock.c
index 0fb12ea..d3ad943 100644
--- a/subversion/mod_dav_svn/lock.c
+++ b/subversion/mod_dav_svn/lock.c
@@ -630,12 +630,30 @@
   svn_error_t *serr;
   dav_error *derr;
 
-  /* If the resource's fs path is unreadable, we don't allow a lock to
-     be created on it. */
-  if (! dav_svn__allow_read(resource, SVN_INVALID_REVNUM, resource->pool))
-    return dav_new_error(resource->pool, HTTP_FORBIDDEN,
-                         DAV_ERR_LOCK_SAVE_LOCK,
-                         "Path is not accessible.");
+  /* This whole if statement is a hack until we get rid of mod_authz_svn
+   * completely.  During the times of mod_dav_svn, there was no
+   * equivalent of dav_svn__allow_read() for writing.
+   *
+   * LOCK command needs write access to resource. If native authz
+   * is turned off, we resort to the old way of requiring read access
+   * on the resource.
+   */
+  if (dav_svn__get_native_authz_file(resource->info->r))
+    {
+      /* Path-based authorization: LOCK needs write access to resource */
+      derr = dav_svn__check_resource_access(resource, svn_authz_write);
+      if (derr)
+        return derr;
+    }
+  else
+    {
+      /* If the resource's fs path is unreadable, we don't allow a lock to
+         be created on it. */
+      if (! dav_svn__allow_read(resource, SVN_INVALID_REVNUM, resource->pool))
+        return dav_new_error(resource->pool, HTTP_FORBIDDEN,
+                             DAV_ERR_LOCK_SAVE_LOCK,
+                             "Path is not accessible.");
+    }
 
   if (lock->next)
     return dav_new_error(resource->pool, HTTP_BAD_REQUEST,
@@ -795,12 +813,24 @@
   if (info->keep_locks)
     return 0;
 
-  /* If the resource's fs path is unreadable, we don't allow a lock to
-     be removed from it. */
-  if (! dav_svn__allow_read(resource, SVN_INVALID_REVNUM, resource->pool))
-    return dav_new_error(resource->pool, HTTP_FORBIDDEN,
-                         DAV_ERR_LOCK_SAVE_LOCK,
-                         "Path is not accessible.");
+  if (dav_svn__get_native_authz_file(resource->info->r))
+    {
+      /* Path-based authorization: UNLOCK needs write access to resource */
+      dav_error *derr;
+
+      derr = dav_svn__check_resource_access(resource, svn_authz_write);
+      if (derr)
+        return derr;
+    }
+  else
+    {
+      /* If the resource's fs path is unreadable, we don't allow a lock to
+         be removed from it. */
+      if (! dav_svn__allow_read(resource, SVN_INVALID_REVNUM, resource->pool))
+        return dav_new_error(resource->pool, HTTP_FORBIDDEN,
+                             DAV_ERR_LOCK_SAVE_LOCK,
+                             "Path is not accessible.");
+    }
 
   if (locktoken == NULL)
     {
diff --git a/subversion/mod_dav_svn/mod_dav_svn.c b/subversion/mod_dav_svn/mod_dav_svn.c
index da72967..622607d 100644
--- a/subversion/mod_dav_svn/mod_dav_svn.c
+++ b/subversion/mod_dav_svn/mod_dav_svn.c
@@ -67,6 +67,7 @@
   enum conf_flag list_parentpath; /* whether to allow GET of parentpath */
   const char *root_dir;              /* our top-level directory */
   const char *master_uri;            /* URI to the master SVN repos */
+  const char *native_authz_file;     /* rule file for native authz */
 } dir_conf_t;
 
 
@@ -164,6 +165,7 @@
   newconf->list_parentpath = INHERIT_VALUE(parent, child, list_parentpath);
   /* Prefer our parent's value over our new one - hence the swap. */
   newconf->root_dir = INHERIT_VALUE(child, parent, root_dir);
+  newconf->native_authz_file = INHERIT_VALUE(parent, child, native_authz_file);
 
   return newconf;
 }
@@ -305,6 +307,17 @@
   return NULL;
 }
 
+static const char *
+SVNNativeAuthzFile_cmd(cmd_parms *cmd, void *config, const char *arg1)
+{
+  dir_conf_t *conf = config;
+
+  conf->native_authz_file
+      = svn_path_canonicalize(apr_pstrdup(cmd->pool, arg1), cmd->pool);
+
+  return NULL;
+}
+
 
 /** Accessor functions for the module's configuration state **/
 
@@ -454,6 +467,16 @@
 }
 
 
+const char *
+dav_svn__get_native_authz_file(request_rec *r)
+{
+    dir_conf_t *conf;
+
+    conf = ap_get_module_config(r->per_dir_config, &dav_svn_module);
+    return conf->native_authz_file;
+}
+
+
 static void
 merge_xml_filter_insert(request_rec *r)
 {
@@ -619,6 +642,12 @@
   AP_INIT_TAKE1("SVNMasterURI", SVNMasterURI_cmd, NULL, ACCESS_CONF,
                 "specifies a URI to access a master Subversion repository"),
 
+  /* per directory/location */
+  AP_INIT_TAKE1("SVNNativeAuthzFile", SVNNativeAuthzFile_cmd, NULL,
+                ACCESS_CONF|RSRC_CONF,
+                "Text file containing permissions of repository paths "
+                "for mod_dav_svn native path-based authorization"),
+
   { NULL }
 };
 
diff --git a/subversion/mod_dav_svn/repos.c b/subversion/mod_dav_svn/repos.c
index 832f183..c3b096e 100644
--- a/subversion/mod_dav_svn/repos.c
+++ b/subversion/mod_dav_svn/repos.c
@@ -1485,6 +1485,45 @@
   if (err)
     return err;
 
+#ifdef SVN_DEBUG
+  ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+                "dav_svn_get_resource(): %s %s %s (%s)",
+                (r->user ? r->user : "-"), r->method, repos_path, r->uri);
+#endif
+
+  /* A special case of path-based authorization for methods
+   * that don't have any saner place to insert authorization to.
+   * XXX: Think of how to do it differently!
+   *
+   * OPTIONS:
+   *   A general check, if access is allowed to this resouce,
+   *   then OPTIONS will return a valid response. Otherwise
+   *   an "Insufficient rights ..." will be returned.
+   *
+   * PROPFIND, PROPPATCH:
+   *   An initial check. If the user is not allowed to access
+   *   the resouce, no information about it should be revealed
+   *   (even "resource does not exist"). Depending on the "Depth"
+   *   header, there will be separate authz checks for every
+   *   child of this resource.
+   */
+  if (r->method_number == M_OPTIONS
+      || r->method_number == M_PROPFIND
+      || r->method_number == M_PROPPATCH)
+    {
+      /* NOTE: We cannot use "repos_path" or "relative" straight away,
+       * need to add a slash at the beginning...
+       */ 
+      char *path = NULL;
+
+      if (repos_path)
+        path = svn_path_join("/", repos_path, r->pool);
+
+      err = dav_svn__check_access(repos_name, path, r, svn_authz_read);
+      if (err)
+        return err;
+    }
+
   /* The path that we will eventually try to open as an svn
      repository.  Normally defined by the SVNPath directive. */
   fs_path = dav_svn__get_fs_path(r);
@@ -1778,10 +1817,11 @@
 {
   dav_resource *parent;
   dav_resource_private *parentinfo;
-  svn_stringbuf_t *path = resource->info->uri_path;
+
+  svn_stringbuf_t *uri_path = resource->info->uri_path;
 
   /* the root of the repository has no parent */
-  if (path->len == 1 && *path->data == '/')
+  if (uri_path->len == 1 && *uri_path->data == '/')
     {
       *parent_resource = NULL;
       return NULL;
@@ -2066,6 +2106,11 @@
                                "Resource body changes may only be made to "
                                "working resources [at this time].");
         }
+
+      /* Path-based authorization: PUT requires write access to resource. */
+      derr = dav_svn__check_resource_access(resource, svn_authz_write);
+      if (derr)
+        return derr;
     }
 
 #if 1
@@ -2371,12 +2416,23 @@
 set_headers(request_rec *r, const dav_resource *resource)
 {
   svn_error_t *serr;
+  dav_error *derr;
   svn_filesize_t length;
   const char *mimetype = NULL;
   apr_time_t last_modified;
   
   if (!resource->exists)
     return NULL;
+  
+  /* Path-based authorization: if the user doesn't have access
+   * to this resource, no information about it should be revealed. 
+   *
+   * Here we check for read access, as dav_svn_set_headers() is a
+   * first step of processing a GET request.
+   */
+  derr = dav_svn__check_resource_access(resource, svn_authz_read);
+  if (derr)
+    return derr;
 
   last_modified = get_last_modified(resource);
   if (last_modified != -1)
@@ -2722,6 +2778,35 @@
           const char *href = name;
           svn_boolean_t is_dir = (entry->kind == svn_node_dir);
 
+          /* Path-based authorization: check if the user has read access
+           * on the entry - if not, hide it.
+           */
+            {
+              dav_error *derr;
+              const char *path;
+              const char *repos_path = resource->info->repos_path;
+
+              svn_pool_clear(entry_pool);
+
+              /* Make a repos_path for an entry we are checking -
+               * If repos_path is "/", we only need to add an entry name.
+               * If repos_path is "/...", we need to add a slash and
+               * then the entry name.
+               */
+              path = apr_psprintf(entry_pool, "%s%s%s",
+                                  repos_path,
+                                  (repos_path[0] == '/'
+                                   && repos_path[1] == 0 ? "" : "/"), 
+                                  name);
+
+              derr = dav_svn__check_access(resource->info->repos->repo_name,
+                                           path,
+                                           resource->info->r,
+                                           svn_authz_read);
+              if (derr)
+                continue;
+            }
+
           svn_pool_clear(entry_pool);
 
           /* append a trailing slash onto the name for directories. we NEED
@@ -2955,6 +3040,11 @@
                          "MKCOL called on regular resource, but "
                          "autoversioning is not active.");
 
+  /* Path-based authorization: MKCOL requires write access to the resource */
+  err = dav_svn__check_resource_access(resource, svn_authz_write);
+  if (err)
+    return err;
+
   /* ### note that the parent was checked out at some point, and this
      ### is being preformed relative to the working rsrc for that parent */
 
@@ -3032,6 +3122,20 @@
                          "COPY called on regular resource, but "
                          "autoversioning is not active.");
 
+  /* Path-based authorization: COPY requires recursive read access
+   * to the source resource and recursive write access to the
+   * destination resource.
+   */
+  err = dav_svn__check_resource_access(src,
+                                       svn_authz_read | svn_authz_recursive);
+  if (err)
+    return err;
+
+  err = dav_svn__check_resource_access(dst,
+                                       svn_authz_write | svn_authz_recursive);
+  if (err)
+    return err;
+
   /* Auto-versioning copy of regular resource: */
   if (dst->type == DAV_RESOURCE_TYPE_REGULAR)
     {
@@ -3109,10 +3213,25 @@
   /* Handle activity deletions (early exit). */
   if (resource->type == DAV_RESOURCE_TYPE_ACTIVITY)
     {
+      /* Path-based authorization: DELETE of an activity requires
+       * global write access to the repository.
+       */
+      err = dav_svn__check_global_access(resource, svn_authz_write);
+      if (err)
+        return err;
+
       return dav_svn__delete_activity(resource->info->repos,
                                       resource->info->root.activity_id);
     }
 
+  /* Path-based authorization: DELETE requires recursive write access
+   * to the resource.
+   */
+  err = dav_svn__check_resource_access(resource,
+                                       svn_authz_write | svn_authz_recursive);
+  if (err)
+    return err;
+
   /* ### note that the parent was checked out at some point, and this
      ### is being preformed relative to the working rsrc for that parent */
 
@@ -3230,6 +3349,20 @@
                          "MOVE only allowed on two public URIs, and "
                          "autoversioning must be active.");
 
+  /* Path-based authorization: MOVE requires recursive write access
+   * to the source resource and recursive write access to the
+   * destinaton resource.
+   */
+  err = dav_svn__check_resource_access(src,
+                                       svn_authz_write | svn_authz_recursive);
+  if (err)
+    return err;
+
+  err = dav_svn__check_resource_access(dst,
+                                       svn_authz_write | svn_authz_recursive);
+  if (err)
+    return err;
+
   /* Change the dst VCR into a WR, in place.  This creates a txn and
      changes dst->info->root from a rev-root into a txn-root. */
   err = dav_svn__checkout(dst,
@@ -3298,6 +3431,23 @@
   /* Clear the temporary pool. */
   svn_pool_clear(ctx->info.pool);
 
+  /* Path-based authorization: initial file resource or
+   * collection resource. Require read access. */
+  if (params->walk_type & DAV_WALKTYPE_AUTH)
+    {
+      err = dav_svn__check_resource_access(&ctx->res, svn_authz_read);
+      if (err)
+        {
+          /* Apache's mod_dav doesn't have any mechanism to handle
+           * access rights violation and returning "403 Forbidden"
+           * status. For now, we just silently skip the entries
+           * that are not accessible.
+           * XXX: better way?
+           */
+          return NULL;
+        }
+    }
+
   /* The current resource is a collection (possibly here thru recursion)
      and this is the invocation for the collection. Alternatively, this is
      the first [and only] entry to do_walk() for a member resource, so
@@ -3381,12 +3531,6 @@
       apr_hash_this(hi, &key, &klen, &val);
       dirent = val;
 
-      /* authorize access to this resource, if applicable */
-      if (params->walk_type & DAV_WALKTYPE_AUTH)
-        {
-          /* ### how/what to do? */
-        }
-
       /* append this child to our buffers */
       svn_stringbuf_appendbytes(ctx->info.uri_path, key, klen);
       svn_stringbuf_appendbytes(ctx->uri, key, klen);
@@ -3398,6 +3542,22 @@
 
       if (dirent->kind == svn_node_file)
         {
+          /* Path-based authorization: file resource. Require read access. */
+          if (params->walk_type & DAV_WALKTYPE_AUTH)
+            {
+              err = dav_svn__check_resource_access(&ctx->res, svn_authz_read);
+              if (err)
+                {
+                  /* Apache's mod_dav doesn't have any mechanism to handle
+                   * access rights violation and returning "403 Forbidden"
+                   * status. For now, we just silently skip the entries
+                   * that are not accessible.
+                   * XXX: better way?
+                   */
+                  return NULL;
+                }
+            }
+
           err = (*params->func)(&ctx->wres, DAV_CALLTYPE_MEMBER);
           if (err != NULL)
             return err;
diff --git a/subversion/mod_dav_svn/version.c b/subversion/mod_dav_svn/version.c
index 94a7fe1..266ed17 100644
--- a/subversion/mod_dav_svn/version.c
+++ b/subversion/mod_dav_svn/version.c
@@ -261,6 +261,13 @@
   dav_error *derr;
   dav_svn__uri_info parse;
 
+  /* Path-based authorization: CHECKOUT requires write access
+   * to the resource.
+   */
+  derr = dav_svn__check_resource_access(resource, svn_authz_write);
+  if (derr)
+    return derr;
+
   /* Auto-Versioning Stuff */
   if (auto_checkout)
     {
@@ -958,7 +965,15 @@
                const apr_xml_doc *doc,
                ap_filter_t *output)
 {
-  int ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
+  int ns;
+  dav_error *err;
+
+  /* Path-based authorization: REPORT requires read access to the resource */
+  err = dav_svn__check_resource_access(resource, svn_authz_read);
+  if (err)
+    return err;
+
+  ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
 
   if (doc->root->ns == ns)
     {
@@ -1037,7 +1052,14 @@
                                   "DAV:activity-collection-set property.",
                                   SVN_DAV_ERROR_NAMESPACE,
                                   SVN_DAV_ERROR_TAG);
-   
+
+  /* Path-based authorization: MKACTIVITY needs global write access
+   * to the repository.
+   */
+  err = dav_svn__check_global_access(resource, svn_authz_write);
+  if (err)
+    return err;
+
   err = dav_svn__create_activity(resource->info->repos, &txn_name,
                                  resource->pool);
   if (err != NULL)