summaryrefslogtreecommitdiffstats
path: root/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java')
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java177
1 files changed, 145 insertions, 32 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
index a6182d159e..59b7670f65 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
@@ -14,12 +14,15 @@
package com.google.gerrit.server.project;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRange;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.common.data.RefConfigSection;
import com.google.gerrit.common.errors.InvalidNameException;
+import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
@@ -41,6 +44,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/** Manages access control for Git references (aka branches, tags). */
@@ -57,6 +61,7 @@ public class RefControl {
private Boolean owner;
private Boolean canForgeAuthor;
private Boolean canForgeCommitter;
+ private Boolean isVisible;
RefControl(ProjectControl projectControl, String ref,
PermissionCollection relevant) {
@@ -102,8 +107,31 @@ public class RefControl {
/** Can this user see this reference exists? */
public boolean isVisible() {
- return (getCurrentUser() instanceof InternalUser || canPerform(Permission.READ))
- && canRead();
+ if (isVisible == null) {
+ isVisible =
+ (getCurrentUser() instanceof InternalUser || canPerform(Permission.READ))
+ && canRead();
+ }
+ return isVisible;
+ }
+
+ /**
+ * True if this reference is visible by all REGISTERED_USERS
+ */
+ public boolean isVisibleByRegisteredUsers() {
+ List<PermissionRule> access = relevant.getPermission(Permission.READ);
+ Set<ProjectRef> allows = Sets.newHashSet();
+ Set<ProjectRef> blocks = Sets.newHashSet();
+ for (PermissionRule rule : access) {
+ if (rule.isBlock()) {
+ blocks.add(relevant.getRuleProps(rule));
+ } else if (rule.getGroup().getUUID().equals(AccountGroup.ANONYMOUS_USERS)
+ || rule.getGroup().getUUID().equals(AccountGroup.REGISTERED_USERS)) {
+ allows.add(relevant.getRuleProps(rule));
+ }
+ }
+ blocks.removeAll(allows);
+ return blocks.isEmpty() && !allows.isEmpty();
}
/**
@@ -193,16 +221,7 @@ public class RefControl {
// granting of powers beyond pushing to the configuration.
return false;
}
- boolean result = false;
- for (PermissionRule rule : access(Permission.PUSH)) {
- if (rule.isBlock()) {
- return false;
- }
- if (rule.getForce()) {
- result = true;
- }
- }
- return result;
+ return canForcePerform(Permission.PUSH);
}
/**
@@ -218,7 +237,8 @@ public class RefControl {
}
boolean owner;
switch (getCurrentUser().getAccessPath()) {
- case WEB_UI:
+ case REST_API:
+ case JSON_RPC:
owner = isOwner();
break;
@@ -258,11 +278,10 @@ public class RefControl {
// than if it doesn't have a PGP signature.
//
if (tag.getFullMessage().contains("-----BEGIN PGP SIGNATURE-----\n")) {
- return owner || canPerform(Permission.PUSH_TAG);
+ return owner || canPerform(Permission.PUSH_SIGNED_TAG);
} else {
return owner || canPerform(Permission.PUSH_TAG);
}
-
} else {
return false;
}
@@ -285,7 +304,8 @@ public class RefControl {
}
switch (getCurrentUser().getAccessPath()) {
- case WEB_UI:
+ case REST_API:
+ case JSON_RPC:
return isOwner() || canPushWithForce();
case GIT:
@@ -322,6 +342,36 @@ public class RefControl {
return canPerform(Permission.ABANDON);
}
+ /** @return true if this user can remove a reviewer for a change. */
+ public boolean canRemoveReviewer() {
+ return canPerform(Permission.REMOVE_REVIEWER);
+ }
+
+ /** @return true if this user can view draft changes. */
+ public boolean canViewDrafts() {
+ return canPerform(Permission.VIEW_DRAFTS);
+ }
+
+ /** @return true if this user can publish draft changes. */
+ public boolean canPublishDrafts() {
+ return canPerform(Permission.PUBLISH_DRAFTS);
+ }
+
+ /** @return true if this user can delete draft changes. */
+ public boolean canDeleteDrafts() {
+ return canPerform(Permission.DELETE_DRAFTS);
+ }
+
+ /** @return true if this user can edit topic names. */
+ public boolean canEditTopicName() {
+ return canPerform(Permission.EDIT_TOPIC_NAME);
+ }
+
+ /** @return true if this user can force edit topic names. */
+ public boolean canForceEditTopicName() {
+ return canForcePerform(Permission.EDIT_TOPIC_NAME);
+ }
+
/** All value ranges of any allowed label permission. */
public List<PermissionRange> getLabelRanges() {
List<PermissionRange> r = new ArrayList<PermissionRange>();
@@ -351,39 +401,97 @@ public class RefControl {
return null;
}
- private static PermissionRange toRange(String permissionName,
- List<PermissionRule> ruleList) {
- int min = 0;
- int max = 0;
- int blockMin = Integer.MIN_VALUE;
- int blockMax = Integer.MAX_VALUE;
- for (PermissionRule rule : ruleList) {
+ private static class AllowedRange {
+ private int allowMin = 0;
+ private int allowMax = 0;
+ private int blockMin = Integer.MIN_VALUE;
+ private int blockMax = Integer.MAX_VALUE;
+
+ void update(PermissionRule rule) {
if (rule.isBlock()) {
blockMin = Math.max(blockMin, rule.getMin());
blockMax = Math.min(blockMax, rule.getMax());
} else {
- min = Math.min(min, rule.getMin());
- max = Math.max(max, rule.getMax());
+ allowMin = Math.min(allowMin, rule.getMin());
+ allowMax = Math.max(allowMax, rule.getMax());
}
}
- if (blockMin > Integer.MIN_VALUE) {
- min = Math.max(min, blockMin + 1);
+
+ int getAllowMin() {
+ return allowMin;
+ }
+ int getAllowMax() {
+ return allowMax;
}
- if (blockMax < Integer.MAX_VALUE) {
- max = Math.min(max, blockMax - 1);
+ int getBlockMin() {
+ // ALLOW wins over BLOCK on the same project
+ return Math.min(blockMin, allowMin - 1);
+ }
+ int getBlockMax() {
+ // ALLOW wins over BLOCK on the same project
+ return Math.max(blockMax, allowMax + 1);
+ }
+ }
+
+ private PermissionRange toRange(String permissionName,
+ List<PermissionRule> ruleList) {
+ Map<ProjectRef, AllowedRange> ranges = Maps.newHashMap();
+ for (PermissionRule rule : ruleList) {
+ ProjectRef p = relevant.getRuleProps(rule);
+ AllowedRange r = ranges.get(p);
+ if (r == null) {
+ r = new AllowedRange();
+ ranges.put(p, r);
+ }
+ r.update(rule);
}
+ int allowMin = 0;
+ int allowMax = 0;
+ int blockMin = Integer.MIN_VALUE;
+ int blockMax = Integer.MAX_VALUE;
+ for (AllowedRange r : ranges.values()) {
+ allowMin = Math.min(allowMin, r.getAllowMin());
+ allowMax = Math.max(allowMax, r.getAllowMax());
+ blockMin = Math.max(blockMin, r.getBlockMin());
+ blockMax = Math.min(blockMax, r.getBlockMax());
+ }
+
+ // BLOCK wins over ALLOW across projects
+ int min = Math.max(allowMin, blockMin + 1);
+ int max = Math.min(allowMax, blockMax - 1);
return new PermissionRange(permissionName, min, max);
}
/** True if the user has this permission. Works only for non labels. */
boolean canPerform(String permissionName) {
List<PermissionRule> access = access(permissionName);
+ Set<ProjectRef> allows = Sets.newHashSet();
+ Set<ProjectRef> blocks = Sets.newHashSet();
for (PermissionRule rule : access) {
if (rule.isBlock() && !rule.getForce()) {
- return false;
+ blocks.add(relevant.getRuleProps(rule));
+ } else {
+ allows.add(relevant.getRuleProps(rule));
+ }
+ }
+ blocks.removeAll(allows);
+ return blocks.isEmpty() && !allows.isEmpty();
+ }
+
+ /** True if the user has force this permission. Works only for non labels. */
+ private boolean canForcePerform(String permissionName) {
+ List<PermissionRule> access = access(permissionName);
+ Set<ProjectRef> allows = Sets.newHashSet();
+ Set<ProjectRef> blocks = Sets.newHashSet();
+ for (PermissionRule rule : access) {
+ if (rule.isBlock()) {
+ blocks.add(relevant.getRuleProps(rule));
+ } else if (rule.getForce()) {
+ allows.add(relevant.getRuleProps(rule));
}
}
- return !access.isEmpty();
+ blocks.removeAll(allows);
+ return blocks.isEmpty() && !allows.isEmpty();
}
/** Rules for the given permission, or the empty list. */
@@ -428,7 +536,12 @@ public class RefControl {
public static String shortestExample(String pattern) {
if (isRE(pattern)) {
- return toRegExp(pattern).toAutomaton().getShortestExample(true);
+ // Since Brics will substitute dot [.] with \0 when generating
+ // shortest example, any usage of dot will fail in
+ // Repository.isValidRefName() if not combined with star [*].
+ // To get around this, we substitute the \0 with an arbitrary
+ // accepted character.
+ return toRegExp(pattern).toAutomaton().getShortestExample(true).replace('\0', '-');
} else if (pattern.endsWith("/*")) {
return pattern.substring(0, pattern.length() - 1) + '1';
} else {