1.10.x fix for issue #4762 "authz doesn't combine global and repository rules"
These changes do not merge cleanly to 1.10.x because of a whitespace change.
* subversion/libsvn_repos/authz.c
(create_user_authz): Resolve a trivial text conflict due to trailing
whitespace which was removed on trunk in r1875617.
git-svn-id: https://svn.apache.org/repos/asf/subversion/branches/1.10.x-issue4762@1885788 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/subversion/libsvn_repos/authz.c b/subversion/libsvn_repos/authz.c
index 668d78d..41f44fb 100644
--- a/subversion/libsvn_repos/authz.c
+++ b/subversion/libsvn_repos/authz.c
@@ -889,9 +889,7 @@
/* Use a separate sub-pool to keep memory usage tight. */
apr_pool_t *subpool = svn_pool_create(scratch_pool);
- /* Find all ACLs for REPOSITORY.
- * Note that repo-specific rules replace global rules,
- * even if they don't apply to the current user. */
+ /* Find all ACLs for REPOSITORY. */
apr_array_header_t *acls = apr_array_make(subpool, authz->acls->nelts,
sizeof(authz_acl_t *));
for (i = 0; i < authz->acls->nelts; ++i)
@@ -908,15 +906,36 @@
= APR_ARRAY_IDX(acls, acls->nelts - 1, const authz_acl_t *);
if (svn_authz__compare_paths(&prev_acl->rule, &acl->rule) == 0)
{
+ svn_boolean_t global_acl_applies;
+ svn_boolean_t repos_acl_applies;
+
+ /* Previous ACL is a global rule. */
SVN_ERR_ASSERT_NO_RETURN(!strcmp(prev_acl->rule.repos,
AUTHZ_ANY_REPOSITORY));
+ /* Current ACL is a per-repository rule. */
SVN_ERR_ASSERT_NO_RETURN(strcmp(acl->rule.repos,
AUTHZ_ANY_REPOSITORY));
- apr_array_pop(acls);
- }
- }
- APR_ARRAY_PUSH(acls, const authz_acl_t *) = acl;
+ global_acl_applies =
+ svn_authz__get_acl_access(NULL, prev_acl, user, repository);
+ repos_acl_applies =
+ svn_authz__get_acl_access(NULL, acl, user, repository);
+
+ /* Prefer rules which apply to both this user and this path
+ * over rules which apply only to the path. In cases where
+ * both rules apply to user and path, always prefer the
+ * repository-specific rule. */
+ if (!global_acl_applies || repos_acl_applies)
+ {
+ apr_array_pop(acls);
+ APR_ARRAY_PUSH(acls, const authz_acl_t *) = acl;
+ }
+ }
+ else
+ APR_ARRAY_PUSH(acls, const authz_acl_t *) = acl;
+ }
+ else
+ APR_ARRAY_PUSH(acls, const authz_acl_t *) = acl;
}
}
diff --git a/subversion/tests/libsvn_repos/authz-test.c b/subversion/tests/libsvn_repos/authz-test.c
index 6ee2448..3ebaff7 100644
--- a/subversion/tests/libsvn_repos/authz-test.c
+++ b/subversion/tests/libsvn_repos/authz-test.c
@@ -478,6 +478,39 @@
return SVN_NO_ERROR;
}
+static svn_error_t *
+reposful_reposless_stanzas_inherit(apr_pool_t *pool)
+{
+ const char rules[] =
+ "[groups]" NL
+ "company = user1, user2, user3" NL
+ "customer = customer1, customer2" NL
+ "" NL
+ "# company can read-write on everything" NL
+ "[/]" NL
+ "@company = rw" NL
+ "" NL
+ "[project1:/]" NL
+ "@customer = r" NL
+ "" NL
+ "[project2:/]" NL;
+
+ svn_stringbuf_t *buf = svn_stringbuf_create(rules, pool);
+ svn_stream_t *stream = svn_stream_from_stringbuf(buf, pool);
+ svn_authz_t *authz;
+ svn_boolean_t access_granted;
+
+ SVN_ERR(svn_repos_authz_parse(&authz, stream, NULL, pool));
+
+ SVN_ERR(svn_repos_authz_check_access(authz, "project1", "/foo", "user1",
+ svn_authz_write | svn_authz_recursive,
+ &access_granted,
+ pool));
+ SVN_TEST_ASSERT(access_granted == TRUE);
+
+ return SVN_NO_ERROR;
+}
+
static int max_threads = 4;
static struct svn_test_descriptor_t test_funcs[] =
@@ -489,6 +522,8 @@
"test svn_authz__get_global_rights"),
SVN_TEST_PASS2(issue_4741_groups,
"issue 4741 groups"),
+ SVN_TEST_PASS2(reposful_reposless_stanzas_inherit,
+ "[foo:/] inherits [/]"),
SVN_TEST_NULL
};