You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2017/01/01 10:43:41 UTC
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...
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 *