Added sameGroupVisibility to All-Projects project.config.
The sameGroupVisiblity is needed to restrict visibility of accounts
when accountVisibility is SAME_GROUP. Namely, this is a way to make
sure the autoVerify group in a contributor-agreements section is
never suggested.
Change-Id: I0d5d55793ca55fc5929ca093637a27c309ca38d9
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountControl.java
index b297ed8..e297ad7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountControl.java
@@ -14,11 +14,14 @@
package com.google.gerrit.server.account;
+import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.git.AccountsSection;
+import com.google.gerrit.server.project.ProjectCache;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -27,16 +30,19 @@
/** Access control management for one account's access to other accounts. */
public class AccountControl {
public static class Factory {
+ private final ProjectCache projectCache;
private final GroupControl.Factory groupControlFactory;
private final Provider<CurrentUser> user;
private final IdentifiedUser.GenericFactory userFactory;
private final AccountVisibility accountVisibility;
@Inject
- Factory(final GroupControl.Factory groupControlFactory,
+ Factory(final ProjectCache projectCache,
+ final GroupControl.Factory groupControlFactory,
final Provider<CurrentUser> user,
final IdentifiedUser.GenericFactory userFactory,
final AccountVisibility accountVisibility) {
+ this.projectCache = projectCache;
this.groupControlFactory = groupControlFactory;
this.user = user;
this.userFactory = userFactory;
@@ -44,20 +50,24 @@
}
public AccountControl get() {
- return new AccountControl(groupControlFactory, user.get(), userFactory,
- accountVisibility);
+ return new AccountControl(projectCache, groupControlFactory, user.get(),
+ userFactory, accountVisibility);
}
}
+ private final AccountsSection accountsSection;
private final GroupControl.Factory groupControlFactory;
private final CurrentUser currentUser;
private final IdentifiedUser.GenericFactory userFactory;
private final AccountVisibility accountVisibility;
- AccountControl(final GroupControl.Factory groupControlFactory,
+ AccountControl(final ProjectCache projectCache,
+ final GroupControl.Factory groupControlFactory,
final CurrentUser currentUser,
final IdentifiedUser.GenericFactory userFactory,
final AccountVisibility accountVisibility) {
+ this.accountsSection =
+ projectCache.getAllProjects().getConfig().getAccountsSection();
this.groupControlFactory = groupControlFactory;
this.currentUser = currentUser;
this.userFactory = userFactory;
@@ -87,6 +97,12 @@
Set<AccountGroup.UUID> usersGroups = groupsOf(otherUser);
usersGroups.remove(AccountGroup.ANONYMOUS_USERS);
usersGroups.remove(AccountGroup.REGISTERED_USERS);
+ for (PermissionRule rule : accountsSection.getSameGroupVisibility()) {
+ if (rule.isBlock() || rule.isDeny()) {
+ usersGroups.remove(rule.getGroup().getUUID());
+ }
+ }
+
if (currentUser.getEffectiveGroups().containsAnyOf(usersGroups)) {
return true;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/ListGroupMembership.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/ListGroupMembership.java
index 237d381..346f406 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/ListGroupMembership.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/ListGroupMembership.java
@@ -15,6 +15,7 @@
package com.google.gerrit.server.account;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
import com.google.gerrit.reviewdb.client.AccountGroup;
import java.util.Set;
@@ -47,6 +48,6 @@
@Override
public Set<AccountGroup.UUID> getKnownGroups() {
- return ImmutableSet.copyOf(groups);
+ return Sets.newHashSet(groups);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/AccountsSection.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/AccountsSection.java
new file mode 100644
index 0000000..7d868bf
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/AccountsSection.java
@@ -0,0 +1,35 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.git;
+
+import com.google.gerrit.common.data.PermissionRule;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AccountsSection {
+ protected List<PermissionRule> sameGroupVisibility;
+
+ public List<PermissionRule> getSameGroupVisibility() {
+ if (sameGroupVisibility == null) {
+ sameGroupVisibility = new ArrayList<PermissionRule>();
+ }
+ return sameGroupVisibility;
+ }
+
+ public void setSameGroupVisibility(List<PermissionRule> sameGroupVisibility) {
+ this.sameGroupVisibility = sameGroupVisibility;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
index b380276..2b36259 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
@@ -58,6 +58,9 @@
private static final String KEY_INHERIT_FROM = "inheritFrom";
private static final String KEY_GROUP_PERMISSIONS = "exclusiveGroupPermissions";
+ private static final String ACCOUNTS = "accounts";
+ private static final String KEY_SAME_GROUP_VISIBILITY = "sameGroupVisibility";
+
private static final String CONTRIBUTOR_AGREEMENT = "contributor-agreement";
private static final String KEY_ACCEPTED = "accepted";
private static final String KEY_REQUIRE_CONTACT_INFORMATION = "requireContactInformation";
@@ -84,6 +87,7 @@
private Project.NameKey projectName;
private Project project;
+ private AccountsSection accountsSection;
private Map<AccountGroup.UUID, GroupReference> groupsByUUID;
private Map<String, AccessSection> accessSections;
private Map<String, ContributorAgreement> contributorAgreements;
@@ -112,6 +116,10 @@
return project;
}
+ public AccountsSection getAccountsSection() {
+ return accountsSection;
+ }
+
public AccessSection getAccessSection(String name) {
return getAccessSection(name, false);
}
@@ -266,6 +274,20 @@
p.setUseContentMerge(getBoolean(rc, SUBMIT, KEY_MERGE_CONTENT, false));
p.setState(getEnum(rc, PROJECT, null, KEY_STATE, defaultStateValue));
+ loadAccountsSection(rc, groupsByName);
+ loadContributorAgreements(rc, groupsByName);
+ loadAccessSections(rc, groupsByName);
+ }
+
+ private void loadAccountsSection(
+ Config rc, Map<String, GroupReference> groupsByName) {
+ accountsSection = new AccountsSection();
+ accountsSection.setSameGroupVisibility(loadPermissionRules(
+ rc, ACCOUNTS, null, KEY_SAME_GROUP_VISIBILITY, groupsByName, false));
+ }
+
+ private void loadContributorAgreements(
+ Config rc, Map<String, GroupReference> groupsByName) {
contributorAgreements = new HashMap<String, ContributorAgreement>();
for (String name : rc.getSubsections(CONTRIBUTOR_AGREEMENT)) {
ContributorAgreement ca = getContributorAgreement(name, true);
@@ -273,32 +295,33 @@
ca.setRequireContactInformation(
rc.getBoolean(CONTRIBUTOR_AGREEMENT, name, KEY_REQUIRE_CONTACT_INFORMATION, false));
ca.setAgreementUrl(rc.getString(CONTRIBUTOR_AGREEMENT, name, KEY_AGREEMENT_URL));
+ ca.setAccepted(loadPermissionRules(
+ rc, CONTRIBUTOR_AGREEMENT, name, KEY_ACCEPTED, groupsByName, false));
- Permission perm = new Permission(KEY_ACCEPTED);
- loadPermissionRules(rc, CONTRIBUTOR_AGREEMENT, name, KEY_ACCEPTED, groupsByName, perm, false);
- ca.setAccepted(perm.getRules());
-
- perm = new Permission(KEY_AUTO_VERIFY);
- loadPermissionRules(rc, CONTRIBUTOR_AGREEMENT, name, KEY_AUTO_VERIFY, groupsByName, perm, false);
- if (perm.getRules().isEmpty()) {
+ List<PermissionRule> rules = loadPermissionRules(
+ rc, CONTRIBUTOR_AGREEMENT, name, KEY_AUTO_VERIFY, groupsByName, false);
+ if (rules.isEmpty()) {
ca.setAutoVerify(null);
- } else if (perm.getRules().size() > 1) {
+ } else if (rules.size() > 1) {
error(new ValidationError(PROJECT_CONFIG, "Invalid rule in "
+ CONTRIBUTOR_AGREEMENT
+ "." + name
+ "." + KEY_AUTO_VERIFY
+ ": at most one group may be set"));
- } else if (perm.getRules().get(0).getAction() != Action.ALLOW) {
+ } else if (rules.get(0).getAction() != Action.ALLOW) {
error(new ValidationError(PROJECT_CONFIG, "Invalid rule in "
+ CONTRIBUTOR_AGREEMENT
+ "." + name
+ "." + KEY_AUTO_VERIFY
+ ": the group must be allowed"));
} else {
- ca.setAutoVerify(perm.getRules().get(0).getGroup());
+ ca.setAutoVerify(rules.get(0).getGroup());
}
}
+ }
+ private void loadAccessSections(
+ Config rc, Map<String, GroupReference> groupsByName) {
accessSections = new HashMap<String, AccessSection>();
for (String refName : rc.getSubsections(ACCESS)) {
if (RefConfigSection.isValid(refName)) {
@@ -336,6 +359,15 @@
}
}
+ private List<PermissionRule> loadPermissionRules(Config rc, String section,
+ String subsection, String varName,
+ Map<String, GroupReference> groupsByName,
+ boolean useRange) {
+ Permission perm = new Permission(varName);
+ loadPermissionRules(rc, section, subsection, varName, groupsByName, perm, useRange);
+ return perm.getRules();
+ }
+
private void loadPermissionRules(Config rc, String section,
String subsection, String varName,
Map<String, GroupReference> groupsByName, Permission perm,
@@ -425,6 +457,24 @@
set(rc, PROJECT, null, KEY_STATE, p.getState(), null);
Set<AccountGroup.UUID> keepGroups = new HashSet<AccountGroup.UUID>();
+ saveAccountsSection(rc, keepGroups);
+ saveContributorAgreements(rc, keepGroups);
+ saveAccessSections(rc, keepGroups);
+ groupsByUUID.keySet().retainAll(keepGroups);
+
+ saveConfig(PROJECT_CONFIG, rc);
+ saveGroupList();
+ }
+
+ private void saveAccountsSection(Config rc, Set<AccountGroup.UUID> keepGroups) {
+ if (accountsSection != null) {
+ rc.setStringList(ACCOUNTS, null, KEY_SAME_GROUP_VISIBILITY,
+ ruleToStringList(accountsSection.getSameGroupVisibility(), keepGroups));
+ }
+ }
+
+ private void saveContributorAgreements(
+ Config rc, Set<AccountGroup.UUID> keepGroups) {
for (ContributorAgreement ca : sort(contributorAgreements.values())) {
set(rc, CONTRIBUTOR_AGREEMENT, ca.getName(), KEY_DESCRIPTION, ca.getDescription());
set(rc, CONTRIBUTOR_AGREEMENT, ca.getName(), KEY_REQUIRE_CONTACT_INFORMATION, ca.isRequireContactInformation());
@@ -440,16 +490,25 @@
rc.unset(CONTRIBUTOR_AGREEMENT, ca.getName(), KEY_AUTO_VERIFY);
}
- List<String> rules = new ArrayList<String>();
- for (PermissionRule rule : sort(ca.getAccepted())) {
- if (rule.getGroup().getUUID() != null) {
- keepGroups.add(rule.getGroup().getUUID());
- }
- rules.add(rule.asString(false));
- }
- rc.setStringList(CONTRIBUTOR_AGREEMENT, ca.getName(), KEY_ACCEPTED, rules);
+ rc.setStringList(CONTRIBUTOR_AGREEMENT, ca.getName(), KEY_ACCEPTED,
+ ruleToStringList(ca.getAccepted(), keepGroups));
}
+ }
+ private List<String> ruleToStringList(
+ List<PermissionRule> list, Set<AccountGroup.UUID> keepGroups) {
+ List<String> rules = new ArrayList<String>();
+ for (PermissionRule rule : sort(list)) {
+ if (rule.getGroup().getUUID() != null) {
+ keepGroups.add(rule.getGroup().getUUID());
+ }
+ rules.add(rule.asString(false));
+ }
+ return rules;
+ }
+
+ private void saveAccessSections(
+ Config rc, Set<AccountGroup.UUID> keepGroups) {
AccessSection capability = accessSections.get(AccessSection.GLOBAL_CAPABILITIES);
if (capability != null) {
Set<String> have = new HashSet<String>();
@@ -526,10 +585,6 @@
rc.unsetSection(ACCESS, name);
}
}
- groupsByUUID.keySet().retainAll(keepGroups);
-
- saveConfig(PROJECT_CONFIG, rc);
- saveGroupList();
}
private void saveGroupList() throws IOException {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/ProjectConfigTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/ProjectConfigTest.java
index e8f9b1a..2bc5d9f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/git/ProjectConfigTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/ProjectConfigTest.java
@@ -73,6 +73,9 @@
+ " submit = group Developers\n" //
+ " push = group Developers\n" //
+ " read = group Developers\n" //
+ + "[accounts]\n" //
+ + " sameGroupVisibility = deny group Developers\n" //
+ + " sameGroupVisibility = block group Staff\n" //
+ "[contributor-agreement \"Individual\"]\n" //
+ " description = A simple description\n" //
+ " accepted = group Developers\n" //
@@ -83,6 +86,7 @@
));
ProjectConfig cfg = read(rev);
+ assertEquals(2, cfg.getAccountsSection().getSameGroupVisibility().size());
ContributorAgreement ca = cfg.getContributorAgreement("Individual");
assertEquals("Individual", ca.getName());
assertEquals("A simple description", ca.getDescription());
@@ -118,6 +122,9 @@
+ " submit = group Developers\n" //
+ " upload = group Developers\n" //
+ " read = group Developers\n" //
+ + "[accounts]\n" //
+ + " sameGroupVisibility = deny group Developers\n" //
+ + " sameGroupVisibility = block group Staff\n" //
+ "[contributor-agreement \"Individual\"]\n" //
+ " description = A simple description\n" //
+ " accepted = group Developers\n" //
@@ -129,6 +136,8 @@
ProjectConfig cfg = read(rev);
AccessSection section = cfg.getAccessSection("refs/heads/*");
+ cfg.getAccountsSection().setSameGroupVisibility(
+ Collections.singletonList(new PermissionRule(cfg.resolve(staff))));
Permission submit = section.getPermission(Permission.SUBMIT);
submit.add(new PermissionRule(cfg.resolve(staff)));
ContributorAgreement ca = cfg.getContributorAgreement("Individual");
@@ -144,6 +153,8 @@
+ "\tsubmit = group Staff\n" //
+ " upload = group Developers\n" //
+ " read = group Developers\n"//
+ + "[accounts]\n" //
+ + " sameGroupVisibility = group Staff\n" //
+ "[contributor-agreement \"Individual\"]\n" //
+ " description = A new description\n" //
+ " accepted = group Staff\n" //