diff options
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.java | 177 |
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 { |