subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1776832 [4/4] - in /subversion/trunk: ./ subversion/include/ subversion/include/private/ subversion/libsvn_fs_x/ subversion/libsvn_repos/ subversion/libsvn_subr/ subversion/mod_authz_svn/ subversion/mod_dav_svn/ subversion/svnserve/ subver...
Date Sun, 01 Jan 2017 10:43:41 GMT
Modified: subversion/trunk/subversion/tests/libsvn_repos/repos-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_repos/repos-test.c?rev=1776832&r1=1776831&r2=1776832&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_repos/repos-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_repos/repos-test.c Sun Jan  1 10:43:40 2017
@@ -22,7 +22,9 @@
 
 #include <stdlib.h>
 #include <string.h>
+
 #include <apr_pools.h>
+#include <apr_time.h>
 
 #include "../svn_test.h"
 
@@ -1282,7 +1284,7 @@ authz(apr_pool_t *pool)
   contents =
     "[greek:/A]"                                                             NL
     "* = r"                                                                  NL
-    "plato = w"                                                              NL
+    "plato = rw"                                                             NL
     ""                                                                       NL
     "[greek:/iota]"                                                          NL
     "* ="                                                                    NL
@@ -1381,11 +1383,536 @@ authz(apr_pool_t *pool)
   SVN_TEST_ASSERT_ERROR(authz_get_handle(&authz_cfg, contents, FALSE, subpool),
                         SVN_ERR_AUTHZ_INVALID_CONFIG);
 
+  /* Verify that the rule on /dir2/secret doesn't affect this
+     request */
+  SVN_ERR(svn_repos_authz_check_access(authz_cfg, "greek",
+                                       "/dir", NULL,
+                                       (svn_authz_read
+                                        | svn_authz_recursive),
+                                       &access_granted, subpool));
+  if (!access_granted)
+    return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
+                            "Regression: incomplete ancestry test "
+                            "for recursive access lookup.");
+
   /* That's a wrap! */
   svn_pool_destroy(subpool);
   return SVN_NO_ERROR;
 }
 
+/* Test the supported authz wildcard variants. */
+static svn_error_t *
+test_authz_wildcards(apr_pool_t *pool)
+{
+  svn_authz_t *authz_cfg;
+
+  /* Some non-trivially overlapping wildcard rules, convering all types
+   * of wildcards: "any", "any-var", "prefix", "postfix" and "complex".
+   *
+   * Note that the rules are not in 1:1 correspondence to that enumeration.
+   */
+  const char *contents =
+    "[:glob:/**/G]"                                                          NL
+    "* = r"                                                                  NL
+    ""                                                                       NL
+    "[:glob:/A/*/G]"                                                         NL
+    "* ="                                                                    NL
+    ""                                                                       NL
+    "[:glob:/A/**/*a*]"                                                      NL
+    "* = r"                                                                  NL
+    ""                                                                       NL
+    "[:glob:/**/*a]"                                                         NL
+    "* = rw"                                                                 NL
+    ""                                                                       NL
+    "[:glob:/A/**/g*]"                                                       NL
+    "* ="                                                                    NL
+    ""                                                                       NL
+    "[:glob:/**/lambda]"                                                     NL
+    "* = rw"                                                                 NL;
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set[] = {
+    /* Test that read rules are correctly used. */
+    { "/", NULL, NULL, svn_authz_read, FALSE },              /* default */
+    { "/iota", NULL, NULL, svn_authz_write, TRUE },          /* rule 4 */
+    { "/A", NULL, NULL, svn_authz_read, FALSE },             /* inherited */
+    { "/A/mu", NULL, NULL, svn_authz_read, FALSE },          /* inherited */
+    { "/A/B", NULL, NULL, svn_authz_read, FALSE },           /* inherited */
+    { "/A/B/lambda", NULL, NULL, svn_authz_write, TRUE },    /* rule 6 */
+    { "/A/B/E", NULL, NULL, svn_authz_read, FALSE },         /* inherited */
+    { "/A/B/E/alpha", NULL, NULL, svn_authz_write, TRUE },   /* rule 4 */
+    { "/A/B/E/beta", NULL, NULL, svn_authz_write, TRUE },    /* rule 4 */
+    { "/A/B/F", NULL, NULL, svn_authz_read, FALSE },         /* inherited */
+    { "/A/C", NULL, NULL, svn_authz_read, FALSE },           /* inherited */
+    { "/A/D", NULL, NULL, svn_authz_read, FALSE },           /* inherited */
+    { "/A/D/gamma", NULL, NULL, svn_authz_read, FALSE },     /* rule 5 */
+    { "/A/D/G", NULL, NULL, svn_authz_read, FALSE },         /* rule 2 */
+    { "/A/D/G/pi", NULL, NULL, svn_authz_read, FALSE },      /* inherited */
+    { "/A/D/G/rho", NULL, NULL, svn_authz_read, FALSE },     /* inherited */
+    { "/A/D/G/tau", NULL, NULL, svn_authz_read, TRUE },      /* rule 3 */
+    { "/A/D/G/tau", NULL, NULL, svn_authz_write, FALSE },    /* rule 3 */
+    { "/A/D/H", NULL, NULL, svn_authz_read, FALSE },         /* inherited */
+    { "/A/D/H/chi", NULL, NULL, svn_authz_read, FALSE },     /* inherited */
+    { "/A/D/H/psi", NULL, NULL, svn_authz_read, FALSE },     /* inherited */
+    { "/A/D/H/omega", NULL, NULL, svn_authz_write, TRUE },   /* rule 4 */
+    /* Non-greek tree paths: */
+    { "/A/G", NULL, NULL, svn_authz_read, TRUE },            /* rule 1 */
+    { "/A/G", NULL, NULL, svn_authz_write, FALSE },          /* rule 1 */
+    { "/A/G/G", NULL, NULL, svn_authz_read, FALSE },         /* rule 2 */
+    { "/G", NULL, NULL, svn_authz_read, TRUE },              /* rule 1 */
+    { "/G", NULL, NULL, svn_authz_write, FALSE },            /* rule 1 */
+    { "/Y/G", NULL, NULL, svn_authz_read, TRUE },            /* rule 1 */
+    { "/Y/G", NULL, NULL, svn_authz_write, FALSE },          /* rule 1 */
+    { "/X/Z/G", NULL, NULL, svn_authz_read, TRUE },          /* rule 1 */
+    { "/X/Z/G", NULL, NULL, svn_authz_write, FALSE },        /* rule 1 */
+    /* Rule 5 prevents recursive access anywhere below /A. */
+    { "/", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/iota", NULL, NULL, svn_authz_read | svn_authz_recursive, TRUE },
+    { "/iota", NULL, NULL, svn_authz_write | svn_authz_recursive, FALSE },
+    { "/A", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/mu", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/B", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/B/lambda", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/B/E", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/B/E/alpha", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/B/E/beta", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/B/F", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/C", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/gamma", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/G", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/G/pi", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/G/rho", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/G/tau", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/H", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/H/chi", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/H/psi", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/H/omega", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Load the test authz rules. */
+  SVN_ERR(authz_get_handle(&authz_cfg, contents, FALSE, pool));
+
+  /* Loop over the test array and test each case. */
+  SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Test the authz performance with wildcard rules. */
+static svn_error_t *
+test_authz_wildcard_performance(apr_pool_t *pool)
+{
+  svn_authz_t *authz_cfg;
+  svn_boolean_t access_granted;
+  int i, k;
+  apr_time_t start, end;
+
+  /* Some non-trivially overlapping wildcard rules, convering all types
+   * of wildcards: "any", "any-var", "prefix", "postfix" and "complex".
+   */
+  const char *contents =
+    "[:glob:greek:/A/*/G]"                                                   NL
+    "* ="                                                                    NL
+    ""                                                                       NL
+    "[:glob:greek:/A/**/*a*]"                                                NL
+    "* = r"                                                                  NL
+    ""                                                                       NL
+    "[:glob:greek:/**/*a]"                                                   NL
+    "* = rw"                                                                 NL
+    ""                                                                       NL
+    "[:glob:greek:/A/**/g*]"                                                 NL
+    "* ="                                                                    NL
+    ""                                                                       NL
+    "[:glob:greek:/**/lambda]"                                               NL
+    "* = rw"                                                                 NL;
+
+  /* Load the test authz rules. */
+  SVN_ERR(authz_get_handle(&authz_cfg, contents, FALSE, pool));
+
+  start = apr_time_now();
+  for (k = 0; k < 100000; ++k)
+    for (i = 1; i < 4; ++i)
+      {
+        const char **path;
+        const char *paths[] =
+        { "/iota",
+          "/A",
+          "/A/mu",
+          "/A/B",
+          "/A/B/lambda",
+          "/A/B/E",
+          "/A/B/E/alpha",
+          "/A/B/E/beta",
+          "/A/B/F",
+          "/A/C",
+          "/A/D",
+          "/A/D/gamma",
+          "/A/D/G",
+          "/A/D/G/pi",
+          "/A/D/G/rho",
+          "/A/D/G/tau",
+          "/A/D/H",
+          "/A/D/H/chi",
+          "/A/D/H/psi",
+          "/A/D/H/omega",
+          NULL
+        };
+
+        for (path = paths; *path; ++path)
+          SVN_ERR(svn_repos_authz_check_access(authz_cfg, "greek",
+                                               *path, NULL, i,
+                                               &access_granted, pool));
+      }
+
+  end = apr_time_now();
+  printf("%"APR_TIME_T_FMT" musecs\n", end - start);
+  printf("%"APR_TIME_T_FMT" checks / sec\n",
+           (k * (i - 1) * 20 * 1000000l) / (end - start));
+
+  return SVN_NO_ERROR;
+}
+
+/* Test that the latest definition wins, regardless of whether the ":glob:"
+ * prefix has been given. */
+static svn_error_t *
+test_authz_prefixes(apr_pool_t *pool)
+{
+  svn_authz_t *authz_cfg;
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  int i, combi;
+
+  /* Set all rights at some folder and replace them again.  Make sure to
+   * cover the "/" b/c that already has an implicit rule, so we* overwrite
+   * it twice.  The first 2 string placeholders in the rules are for the
+   * repository name and the optional glob support marker. */
+  const char *contents_format =
+    "[%s%s%s]"                                                              NL
+    "* = r"                                                                 NL
+    "plato = rw"                                                            NL
+    ""                                                                      NL
+    "[%s%s%s]"                                                              NL
+    "* ="                                                                   NL
+    "plato = r"                                                             NL;
+
+  /* The paths on which to apply this test. */
+  enum { PATH_COUNT = 2 };
+  const char *test_paths[PATH_COUNT] = { "/", "/A" };
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set1[] = {
+    /* Test that read rules are correctly used. */
+    { "", "greek", NULL, svn_authz_read, FALSE },
+    /* Test that write rules are correctly used. */
+    { "", "greek", "plato", svn_authz_read, TRUE },
+    { "", "greek", "plato", svn_authz_write, FALSE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* To be used when global rules are specified after per-repos rules.
+   * In that case, the global rules still win. */
+  struct check_access_tests test_set2[] = {
+    /* Test that read rules are correctly used. */
+    { "", "greek", NULL, svn_authz_read, TRUE },
+    { "", "greek", NULL, svn_authz_write, FALSE },
+    /* Test that write rules are correctly used. */
+    { "", "greek", "plato", svn_authz_read, TRUE },
+    { "", "greek", "plato", svn_authz_write, TRUE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* There is a total of 16 combinations of authz content. */
+  for (combi = 0; combi < 16; ++combi)
+    {
+      const char *contents;
+      const char *glob1 = (combi & 1) ? ":glob:" : "";
+      const char *glob2 = (combi & 2) ? ":glob:" : "";
+      const char *repo1 = (combi & 4) ? "greek:" : "";
+      const char *repo2 = (combi & 4) ? "" : "greek:";
+      const char *test_path = test_paths[combi / 8];
+      struct check_access_tests *test_set = (combi & 4) ? test_set2 : test_set1;
+
+      /* Create and parse the authz rules. */
+      svn_pool_clear(iterpool);
+      contents = apr_psprintf(iterpool, contents_format,
+                              glob1, repo1, test_path,
+                              glob2, repo2, test_path);
+      SVN_ERR(authz_get_handle(&authz_cfg, contents, FALSE, iterpool));
+
+      /* iterate over all test paths */
+      for (i = combi / 8; i < PATH_COUNT; ++i)
+        {
+          /* Set the path for all test cases to the current test path. */
+          struct check_access_tests *test;
+          for (test = test_set; test->path != NULL; ++test)
+            test->path = test_paths[i];
+
+          /* Loop over the test array and test each case. */
+          SVN_ERR(authz_check_access(authz_cfg, test_set, iterpool));
+        }
+    }
+
+  /* That's a wrap! */
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_authz_recursive_override(apr_pool_t *pool)
+{
+  svn_authz_t *authz_cfg;
+
+  /* Set all rights at some folder and replace them again.  Make sure to
+   * cover the "/" b/c that already has an implicit rule, so we* overwrite
+   * it twice.  The first 2 string placeholders in the rules are for the
+   * repository name and the optional glob support marker. */
+  const char *contents =
+    "[:glob:/A/B]"                                                          NL
+    "plato = rw"                                                            NL
+    ""                                                                      NL
+    "[:glob:/A/**]"                                                         NL
+    "plato = r"                                                             NL
+    ""                                                                      NL
+    "[:glob:/B/C]"                                                          NL
+    "plato ="                                                               NL
+    ""                                                                      NL
+    "[:glob:/B/**]"                                                         NL
+    "plato = rw"                                                            NL
+    ""                                                                      NL
+    "[:glob:/C/D]"                                                          NL
+    "plato = rw"                                                            NL
+    ""                                                                      NL
+    "[:glob:/C/**/E]"                                                       NL
+    "plato = r"                                                             NL
+    ""                                                                      NL
+    "[:glob:/D/E]"                                                          NL
+    "plato = r"                                                             NL
+    ""                                                                      NL
+    "[:glob:/D/**/F]"                                                       NL
+    "plato = rw"                                                            NL;
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set[] = {
+    /* The root shall not be affected -> defaults to "no access". */
+    { "/", NULL, "plato", svn_authz_read, FALSE },
+    /* Recursive restriction of rights shall work. */
+    { "/A", NULL, "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/A", NULL, "plato", svn_authz_write | svn_authz_recursive, FALSE },
+    /* Recursive extension of rights shall work. */
+    { "/B", NULL, "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/B", NULL, "plato", svn_authz_write | svn_authz_recursive, TRUE },
+    /* Partial replacements shall not result in recursive rights. */
+    { "/C", NULL, "plato", svn_authz_read | svn_authz_recursive, FALSE },
+    { "/C/D", NULL, "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/C/D", NULL, "plato", svn_authz_write | svn_authz_recursive, FALSE },
+    { "/D", NULL, "plato", svn_authz_read | svn_authz_recursive, FALSE },
+    { "/D/E", NULL, "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/D/E", NULL, "plato", svn_authz_write | svn_authz_recursive, FALSE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  SVN_ERR(authz_get_handle(&authz_cfg, contents, FALSE, pool));
+
+  /* Loop over the test array and test each case. */
+  SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
+
+  /* That's a wrap! */
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_authz_pattern_tests(apr_pool_t *pool)
+{
+  svn_authz_t *authz_cfg;
+
+  /* Rules will be considered for recursive access checks irrespective of
+   * whether the respective paths actually do exist. */
+  const char *contents =
+    "[:glob:/**/Yeti]"                                                      NL
+    "plato = r"                                                             NL
+    ""                                                                      NL
+    "[/]"                                                                   NL
+    "plato = r"                                                             NL
+    ""                                                                      NL
+    "[/trunk]"                                                              NL
+    "plato = rw"                                                            NL;
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set[] = {
+    /* We have no recursive write access anywhere. */
+    { "/", NULL, "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/", NULL, "plato", svn_authz_write | svn_authz_recursive, FALSE },
+    { "/trunk", NULL, "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/trunk", NULL, "plato", svn_authz_write | svn_authz_recursive, FALSE },
+
+    /* We do have ordinary write access to anything under /trunk that is
+     * not a Yeti. */
+    { "/trunk", NULL, "plato", svn_authz_write, TRUE },
+    { "/trunk/A/B/C", NULL, "plato", svn_authz_write, TRUE },
+
+    /* We don't have write access to Yetis. */
+    { "/trunk/A/B/C/Yeti", NULL, "plato", svn_authz_write, FALSE },
+    { "/trunk/Yeti", NULL, "plato", svn_authz_write, FALSE },
+    { "/Yeti", NULL, "plato", svn_authz_write, FALSE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Global override via "**" and selective override for a specific path. */
+  const char *contents2 =
+    "[:glob:/X]"                                                            NL
+    "user1 ="                                                               NL
+    ""                                                                      NL
+    "[:glob:/X/**]"                                                         NL
+    "user1 = rw"                                                            NL
+    "user2 = rw"                                                            NL
+    ""                                                                      NL
+    "[:glob:/X/Y/Z]"                                                        NL
+    "user2 ="                                                               NL;
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set2[] = {
+    /* No access at the root*/
+    { "/", NULL, "user1", svn_authz_read, FALSE },
+    { "/", NULL, "user2", svn_authz_read, FALSE },
+
+    /* User 1 has recursive write access anywhere. */
+    { "/X", NULL, "user1", svn_authz_write | svn_authz_recursive, TRUE },
+    { "/X/Y", NULL, "user1", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/X/Y/Z", NULL, "user1", svn_authz_read | svn_authz_recursive, TRUE },
+
+    /* User 2 only has recursive read access to X/Y/Z. */
+    { "/X", NULL, "user1", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/X", NULL, "user2", svn_authz_write | svn_authz_recursive, FALSE },
+    { "/X/Y", NULL, "user2", svn_authz_write | svn_authz_recursive, FALSE },
+    { "/X/Y/Z", NULL, "user2", svn_authz_write | svn_authz_recursive, FALSE },
+
+    /* However, user2 has ordinary write access X and recursive write access
+     * to anything not in X/Y/Z. */
+    { "/X", NULL, "user2", svn_authz_write, TRUE },
+    { "/X/A", NULL, "user2", svn_authz_write | svn_authz_recursive, TRUE },
+    { "/X/Y/A", NULL, "user2", svn_authz_write | svn_authz_recursive, TRUE },
+
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Global patterns vs. global path rules. */
+  const char *contents3 =
+    "[groups]"                                                              NL
+    "Team1 = user1"                                                         NL
+    "Team2 = user1, user2"                                                  NL
+    ""                                                                      NL
+    "[/]"                                                                   NL
+    "* ="                                                                   NL
+    ""                                                                      NL
+    "[:glob:Repo1:/**/folder*]"                                             NL
+    "@Team1 = rw"                                                           NL
+    ""                                                                      NL
+    "[Repo2:/]"                                                             NL
+    "@Team2 = r"                                                            NL;
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set3[] = {
+    /* No access at the root of Repo1 (inherited from global settings) */
+    { "/", "Repo1", "user1", svn_authz_read, FALSE },
+    { "/", "Repo1", "user2", svn_authz_read, FALSE },
+
+    /* r/o access for both users at the root of Repo2 */
+    { "/", "Repo2", "user1", svn_authz_read, TRUE },
+    { "/", "Repo2", "user2", svn_authz_read, TRUE },
+    { "/", "Repo2", "user1", svn_authz_write, FALSE },
+    { "/", "Repo2", "user2", svn_authz_write, FALSE },
+
+    /* user1 has recursive write access (b/c there are no further rules
+     * restricting the access once granted at the parent) wherever there is
+     * a "folder..." in the  path, while user2 has no access at all. */
+    { "/folder_1", "Repo1", "user1",
+      svn_authz_write | svn_authz_recursive, TRUE },
+    { "/folder_1", "Repo1", "user2", svn_authz_read, FALSE },
+    { "/1_folder", "Repo1", "user1", svn_authz_read, FALSE },
+    { "/foo/bar/folder_2/random", "Repo1", "user1",
+      svn_authz_write | svn_authz_recursive, TRUE },
+    { "/foo/bar/folder_2/random", "Repo1", "user2", svn_authz_read, FALSE },
+    { "/foo/bar/2_folder/random", "Repo1", "user1", svn_authz_read, FALSE },
+    { "/foo/bar/folder", "Repo1", "user1",
+      svn_authz_write | svn_authz_recursive, TRUE },
+    { "/foo/bar/folder", "Repo1", "user2", svn_authz_read, FALSE },
+
+    /* Doesn't quite match the pattern: */
+    { "/foo/bar/folde", "Repo1", "user1", svn_authz_read, FALSE },
+    { "/foo/bar/folde", "Repo1", "user2", svn_authz_read, FALSE },
+
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Illustrate the difference between "matching" rule and "applying" rule.
+   * "*" only _matches_ a single level and will _apply_ to sub-paths only
+   * if no other rule _applies_.  The "**" rule applies to all paths in
+   * trunk and will only be eclipsed for members of team1 and then only for
+   * the first sub-level. */
+  const char *contents4 =
+    "[groups]"                                                              NL
+    "team1 = user1, user3"                                                  NL
+    "team2 = user2, user3"                                                  NL
+    ""                                                                      NL
+    "[:glob:Repo1:/trunk/**]"                                               NL
+    "@team2 = rw"                                                           NL
+    ""                                                                      NL
+    "[:glob:Repo1:/trunk/*]"                                                NL
+    "@team1 = r"                                                            NL;
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set4[] = {
+    /* Team2 has r/w access to /trunk */
+    { "/trunk", "Repo1", "user1", svn_authz_read, FALSE },
+    { "/trunk", "Repo1", "user2", svn_authz_write, TRUE },
+    { "/trunk", "Repo1", "user3", svn_authz_write, TRUE },
+
+    /* At the first sub-level, team1 has only read access;
+     * the remainder of team2 has write access. */
+    { "/trunk/A", "Repo1", "user1", svn_authz_read, TRUE },
+    { "/trunk/A", "Repo1", "user3", svn_authz_read, TRUE },
+    { "/trunk/A", "Repo1", "user1", svn_authz_write, FALSE },
+    { "/trunk/A", "Repo1", "user2", svn_authz_write, TRUE },
+    { "/trunk/A", "Repo1", "user3", svn_authz_write, FALSE },
+
+    /* At the second sub-level, team2 has full write access;
+     * the remainder of team1 has still r/o access. */
+    { "/trunk/A/B", "Repo1", "user2",
+      svn_authz_write | svn_authz_recursive, TRUE },
+    { "/trunk/A/B", "Repo1", "user3",
+      svn_authz_write | svn_authz_recursive, TRUE },
+    { "/trunk/A/B", "Repo1", "user1", svn_authz_read, TRUE },
+    { "/trunk/A/B", "Repo1", "user1", svn_authz_write, FALSE },
+
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Verify that the rules are applies as expected. */
+  SVN_ERR(authz_get_handle(&authz_cfg, contents, FALSE, pool));
+  SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
+
+  SVN_ERR(authz_get_handle(&authz_cfg, contents2, FALSE, pool));
+  SVN_ERR(authz_check_access(authz_cfg, test_set2, pool));
+
+  SVN_ERR(authz_get_handle(&authz_cfg, contents3, FALSE, pool));
+  SVN_ERR(authz_check_access(authz_cfg, test_set3, pool));
+
+  SVN_ERR(authz_get_handle(&authz_cfg, contents4, FALSE, pool));
+  SVN_ERR(authz_check_access(authz_cfg, test_set4, pool));
+
+  /* That's a wrap! */
+  return SVN_NO_ERROR;
+}
+
 
 /* Test in-repo authz paths */
 static svn_error_t *
@@ -1798,7 +2325,7 @@ groups_authz(const svn_test_opts_t *opts
 
   SVN_ERR(authz_check_access(authz_cfg, test_set1, pool));
 
-  /* Access rights in the global groups file are discarded. */
+  /* Access rights in the global groups file are forbidden. */
   groups_contents =
     "[groups]"                                                               NL
     "philosophers = socrates"                                                NL
@@ -1812,6 +2339,19 @@ groups_authz(const svn_test_opts_t *opts
     "@philosophers = rw"                                                     NL
     ""                                                                       NL;
 
+  SVN_TEST_ASSERT_ERROR(
+      authz_groups_get_handle(&authz_cfg, authz_contents,
+                              groups_contents, TRUE, pool),
+      SVN_ERR_AUTHZ_INVALID_CONFIG);
+  SVN_TEST_ASSERT_ERROR(
+      authz_groups_get_handle(&authz_cfg, authz_contents,
+                              groups_contents, FALSE, pool),
+      SVN_ERR_AUTHZ_INVALID_CONFIG);
+
+  groups_contents =
+    "[groups]"                                                               NL
+    "philosophers = socrates"                                                NL
+    ""                                                                       NL;
   SVN_ERR(authz_groups_get_handle(&authz_cfg, authz_contents,
                                   groups_contents, TRUE, pool));
 
@@ -3350,18 +3890,14 @@ test_config_pool(const svn_test_opts_t *
   svn_error_t *err;
 
   svn_repos__config_pool_t *config_pool;
-  apr_pool_t *config_pool_pool;
   apr_pool_t *subpool = svn_pool_create(pool);
 
   const char *wrk_dir = svn_test_data_path("config_pool", pool);
 
   SVN_ERR(svn_io_make_dir_recursively(wrk_dir, pool));
 
-  /* read all config info through a single config pool and we want to be
-     able to control its lifetime.  The latter requires a separate pool. */
-  config_pool_pool = svn_pool_create(pool);
-  SVN_ERR(svn_repos__config_pool_create(&config_pool, TRUE,
-                                        config_pool_pool));
+  /* read all config info through a single config pool. */
+  SVN_ERR(svn_repos__config_pool_create(&config_pool, TRUE, pool));
 
   /* have two different configurations  */
   SVN_ERR(svn_test_get_srcdir(&srcdir, opts, pool));
@@ -3402,11 +3938,11 @@ test_config_pool(const svn_test_opts_t *
   for (i = 0; i < 4; ++i)
     {
       SVN_ERR(svn_repos__config_pool_get(
-                                    &cfg, NULL, config_pool,
+                                    &cfg, config_pool,
                                     svn_dirent_join(wrk_dir,
                                                     "config-pool-test1.cfg",
                                                     pool),
-                                    TRUE, TRUE, NULL, subpool));
+                                    TRUE, NULL, subpool));
 
       if (sections1 == NULL)
         sections1 = cfg->sections;
@@ -3421,11 +3957,11 @@ test_config_pool(const svn_test_opts_t *
   for (i = 0; i < 4; ++i)
     {
       SVN_ERR(svn_repos__config_pool_get(
-                                    &cfg, NULL, config_pool,
+                                    &cfg, config_pool,
                                     svn_dirent_join(wrk_dir,
                                                     "config-pool-test2.cfg",
                                                     pool),
-                                    TRUE, TRUE, NULL, subpool));
+                                    TRUE, NULL, subpool));
 
       SVN_TEST_ASSERT(cfg->sections == sections1);
 
@@ -3437,11 +3973,11 @@ test_config_pool(const svn_test_opts_t *
   for (i = 0; i < 2; ++i)
     {
       SVN_ERR(svn_repos__config_pool_get(
-                                    &cfg, NULL, config_pool,
+                                    &cfg, config_pool,
                                     svn_dirent_join(wrk_dir,
                                                     "config-pool-test3.cfg",
                                                     pool),
-                                    TRUE, TRUE, NULL, subpool));
+                                    TRUE, NULL, subpool));
 
       if (sections2 == NULL)
         sections2 = cfg->sections;
@@ -3467,11 +4003,11 @@ test_config_pool(const svn_test_opts_t *
   SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
 
   /* reading the config from the repo should still give cfg1 */
-  SVN_ERR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+  SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "dir/config", pool),
-                                     TRUE, TRUE, NULL, subpool));
+                                     TRUE, NULL, subpool));
   SVN_TEST_ASSERT(cfg->sections == sections1);
   svn_pool_clear(subpool);
 
@@ -3485,48 +4021,48 @@ test_config_pool(const svn_test_opts_t *
   SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
 
   /* reading the config from the repo should give cfg2 now */
-  SVN_ERR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+  SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "dir/config", pool),
-                                     TRUE, TRUE, NULL, subpool));
+                                     TRUE, NULL, subpool));
   SVN_TEST_ASSERT(cfg->sections == sections2);
   svn_pool_clear(subpool);
 
   /* reading the copied config should still give cfg1 */
-  SVN_ERR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+  SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "another-dir/config",
                                                     pool),
-                                     TRUE, TRUE, NULL, subpool));
+                                     TRUE, NULL, subpool));
   SVN_TEST_ASSERT(cfg->sections == sections1);
   svn_pool_clear(subpool);
 
   /* once again: repeated reads.  This triggers a different code path. */
-  SVN_ERR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+  SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "dir/config", pool),
-                                     TRUE, TRUE, NULL, subpool));
+                                     TRUE, NULL, subpool));
   SVN_TEST_ASSERT(cfg->sections == sections2);
-  SVN_ERR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+  SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "another-dir/config",
                                                     pool),
-                                     TRUE, TRUE, NULL, subpool));
+                                     TRUE, NULL, subpool));
   SVN_TEST_ASSERT(cfg->sections == sections1);
   svn_pool_clear(subpool);
 
   /* access paths that don't exist */
-  SVN_TEST_ASSERT_ERROR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+  SVN_TEST_ASSERT_ERROR(svn_repos__config_pool_get(&cfg, config_pool,
                           svn_path_url_add_component2(repo_root_url, "X",
                                                       pool),
-                          TRUE, TRUE, NULL, subpool),
+                          TRUE, NULL, subpool),
                         SVN_ERR_ILLEGAL_TARGET);
-  err = svn_repos__config_pool_get(&cfg, NULL, config_pool, "X.cfg",
-                                   TRUE, TRUE, NULL, subpool);
+  err = svn_repos__config_pool_get(&cfg, config_pool, "X.cfg", TRUE, NULL,
+                                   subpool);
   SVN_TEST_ASSERT(err && APR_STATUS_IS_ENOENT(err->apr_err));
   svn_error_clear(err);
   svn_pool_clear(subpool);
@@ -3989,6 +4525,16 @@ static struct svn_test_descriptor_t test
                        "authz for svn_repos_trace_node_locations"),
     SVN_TEST_OPTS_PASS(commit_aborted_txn,
                        "test committing a previously aborted txn"),
+    SVN_TEST_PASS2(test_authz_prefixes,
+                   "test authz prefixes"),
+    SVN_TEST_PASS2(test_authz_recursive_override,
+                   "test recursively authz rule override"),
+    SVN_TEST_PASS2(test_authz_pattern_tests,
+                   "test various basic authz pattern combinations"),
+    SVN_TEST_PASS2(test_authz_wildcards,
+                   "test the different types of authz wildcards"),
+    SVN_TEST_SKIP2(test_authz_wildcard_performance, TRUE,
+                   "optional authz wildcard performance test"),
     SVN_TEST_OPTS_PASS(test_list,
                        "test svn_repos_list"),
     SVN_TEST_NULL

Modified: subversion/trunk/subversion/tests/libsvn_subr/config-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/config-test.c?rev=1776832&r1=1776831&r2=1776832&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/config-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/config-test.c Sun Jan  1 10:43:40 2017
@@ -37,6 +37,7 @@
 #include "svn_error.h"
 #include "svn_config.h"
 #include "private/svn_subr_private.h"
+#include "private/svn_config_private.h"
 
 #include "../svn_test.h"
 
@@ -403,6 +404,60 @@ test_invalid_bom(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_serialization(apr_pool_t *pool)
+{
+  svn_stringbuf_t *original_content;
+  svn_stringbuf_t *written_content;
+  svn_config_t *cfg;
+
+  const struct
+    {
+      const char *section;
+      const char *option;
+      const char *value;
+    } test_data[] =
+    {
+      { "my section", "value1", "some" },
+      { "my section", "value2", "something" },
+      { "another Section", "value1", "one" },
+      { "another Section", "value2", "two" },
+      { "another Section", "value 3", "more" },
+    };
+  int i;
+
+  /* Format the original with the same formatting that the writer will use. */
+  original_content = svn_stringbuf_create("\n[my section]\n"
+                                          "value1=some\n"
+                                          "value2=%(value1)sthing\n"
+                                          "\n[another Section]\n"
+                                          "value1=one\n"
+                                          "value2=two\n"
+                                          "value 3=more\n",
+                                          pool);
+  written_content = svn_stringbuf_create_empty(pool);
+
+  SVN_ERR(svn_config_parse(&cfg,
+                           svn_stream_from_stringbuf(original_content, pool),
+                           TRUE, TRUE, pool));
+  SVN_ERR(svn_config__write(svn_stream_from_stringbuf(written_content, pool),
+                            cfg, pool));
+  SVN_ERR(svn_config_parse(&cfg,
+                           svn_stream_from_stringbuf(written_content, pool),
+                           TRUE, TRUE, pool));
+
+  /* The serialized and re-parsed config must have the expected contents. */
+  for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
+    {
+      const char *val;
+      svn_config_get(cfg, &val, test_data[i].section, test_data[i].option,
+                     NULL);
+      SVN_TEST_STRING_ASSERT(val, test_data[i].value);
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /*
    ====================================================================
    If you add a new test to this file, update this array.
@@ -437,6 +492,8 @@ static struct svn_test_descriptor_t test
                        "test variable expansion"),
     SVN_TEST_PASS2(test_invalid_bom,
                    "test parsing config file with invalid BOM"),
+    SVN_TEST_PASS2(test_serialization,
+                   "test writing a config"),
     SVN_TEST_NULL
   };
 

Modified: subversion/trunk/subversion/tests/libsvn_subr/string-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/string-test.c?rev=1776832&r1=1776831&r2=1776832&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/string-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/string-test.c Sun Jan  1 10:43:40 2017
@@ -894,6 +894,99 @@ test_cstring_skip_prefix(apr_pool_t *poo
 }
 
 static svn_error_t *
+test_stringbuf_replace_all(apr_pool_t *pool)
+{
+  svn_stringbuf_t *s = svn_stringbuf_create("abccabcdabc", pool);
+
+  /* no replacement */
+  SVN_TEST_ASSERT(0 == svn_stringbuf_replace_all(s, "xyz", "k"));
+  SVN_TEST_STRING_ASSERT(s->data, "abccabcdabc");
+  SVN_TEST_ASSERT(s->len == 11);
+
+  /* replace at string head: grow */
+  SVN_TEST_ASSERT(1 == svn_stringbuf_replace_all(s, "abcc", "xyabcz"));
+  SVN_TEST_STRING_ASSERT(s->data, "xyabczabcdabc");
+  SVN_TEST_ASSERT(s->len == 13);
+
+  /* replace at string head: shrink */
+  SVN_TEST_ASSERT(1 == svn_stringbuf_replace_all(s, "xyabcz", "abcc"));
+  SVN_TEST_STRING_ASSERT(s->data, "abccabcdabc");
+  SVN_TEST_ASSERT(s->len == 11);
+
+  /* replace at string tail: grow */
+  SVN_TEST_ASSERT(1 == svn_stringbuf_replace_all(s, "dabc", "xyabcz"));
+  SVN_TEST_STRING_ASSERT(s->data, "abccabcxyabcz");
+  SVN_TEST_ASSERT(s->len == 13);
+
+  /* replace at string tail: shrink */
+  SVN_TEST_ASSERT(1 == svn_stringbuf_replace_all(s, "xyabcz", "dabc"));
+  SVN_TEST_STRING_ASSERT(s->data, "abccabcdabc");
+  SVN_TEST_ASSERT(s->len == 11);
+
+  /* replace at multiple locations: grow */
+  SVN_TEST_ASSERT(3 == svn_stringbuf_replace_all(s, "ab", "xyabz"));
+  SVN_TEST_STRING_ASSERT(s->data, "xyabzccxyabzcdxyabzc");
+  SVN_TEST_ASSERT(s->len == 20);
+
+  /* replace at multiple locations: shrink */
+  SVN_TEST_ASSERT(3 == svn_stringbuf_replace_all(s, "xyabz", "ab"));
+  SVN_TEST_STRING_ASSERT(s->data, "abccabcdabc");
+  SVN_TEST_ASSERT(s->len == 11);
+
+  /* replace at multiple locations: same length */
+  SVN_TEST_ASSERT(3 == svn_stringbuf_replace_all(s, "abc", "xyz"));
+  SVN_TEST_STRING_ASSERT(s->data, "xyzcxyzdxyz");
+  SVN_TEST_ASSERT(s->len == 11);
+
+  /* replace at multiple locations: overlapping */
+  s = svn_stringbuf_create("aaaaaaaaaaa", pool);
+  SVN_TEST_ASSERT(5 == svn_stringbuf_replace_all(s, "aa", "aaa"));
+  SVN_TEST_STRING_ASSERT(s->data, "aaaaaaaaaaaaaaaa");
+  SVN_TEST_ASSERT(s->len == 16);
+
+  SVN_TEST_ASSERT(5 == svn_stringbuf_replace_all(s, "aaa", "aa"));
+  SVN_TEST_STRING_ASSERT(s->data, "aaaaaaaaaaa");
+  SVN_TEST_ASSERT(s->len == 11);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_stringbuf_leftchop(apr_pool_t *pool)
+{
+  svn_stringbuf_t *s;
+
+  s = svn_stringbuf_create("abcd", pool);
+  svn_stringbuf_leftchop(s, 0);
+  SVN_TEST_ASSERT(s->len == 4);
+  SVN_TEST_STRING_ASSERT(s->data, "abcd");
+
+  svn_stringbuf_leftchop(s, 2);
+  SVN_TEST_ASSERT(s->len == 2);
+  SVN_TEST_STRING_ASSERT(s->data, "cd");
+
+  svn_stringbuf_leftchop(s, 4);
+  SVN_TEST_ASSERT(s->len == 0);
+  SVN_TEST_STRING_ASSERT(s->data, "");
+
+  s = svn_stringbuf_create("abcd", pool);
+  svn_stringbuf_leftchop(s, 4);
+  SVN_TEST_ASSERT(s->len == 0);
+  SVN_TEST_STRING_ASSERT(s->data, "");
+
+  s = svn_stringbuf_create_empty(pool);
+  svn_stringbuf_leftchop(s, 0);
+  SVN_TEST_ASSERT(s->len == 0);
+  SVN_TEST_STRING_ASSERT(s->data, "");
+
+  svn_stringbuf_leftchop(s, 2);
+  SVN_TEST_ASSERT(s->len == 0);
+  SVN_TEST_STRING_ASSERT(s->data, "");
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
 test_stringbuf_set(apr_pool_t *pool)
 {
   svn_stringbuf_t *str = svn_stringbuf_create_empty(pool);
@@ -996,6 +1089,10 @@ static struct svn_test_descriptor_t test
                    "test string matching"),
     SVN_TEST_PASS2(test_cstring_skip_prefix,
                    "test svn_cstring_skip_prefix()"),
+    SVN_TEST_PASS2(test_stringbuf_replace_all,
+                   "test svn_stringbuf_replace_all"),
+    SVN_TEST_PASS2(test_stringbuf_leftchop,
+                   "test svn_stringbuf_leftchop"),
     SVN_TEST_PASS2(test_stringbuf_set,
                    "test svn_stringbuf_set()"),
     SVN_TEST_NULL

Modified: subversion/trunk/tools/server-side/svnauthz.c
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/server-side/svnauthz.c?rev=1776832&r1=1776831&r2=1776832&view=diff
==============================================================================
--- subversion/trunk/tools/server-side/svnauthz.c (original)
+++ subversion/trunk/tools/server-side/svnauthz.c Sun Jan  1 10:43:40 2017
@@ -275,9 +275,9 @@ get_authz(svn_authz_t **authz, struct sv
                               opt_state->txn, pool);
 
   /* Else */
-  return svn_repos_authz_read2(authz, opt_state->authz_file,
+  return svn_repos_authz_read3(authz, opt_state->authz_file,
                                opt_state->groups_file,
-                               TRUE, pool);
+                               TRUE, NULL, pool, pool);
 }
 
 static svn_error_t *



Mime
View raw message