Convert update and forceUpdate to PermissionBackend
Change-Id: Ic2d4d879f73541585f80be40cbcc8b670f23d151
This commit is contained in:
@@ -107,6 +107,9 @@ import com.google.gerrit.server.notedb.NotesMigration;
|
||||
import com.google.gerrit.server.patch.PatchSetInfoFactory;
|
||||
import com.google.gerrit.server.permissions.GlobalPermission;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.permissions.ProjectPermission;
|
||||
import com.google.gerrit.server.permissions.RefPermission;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
@@ -295,6 +298,7 @@ public class ReceiveCommits {
|
||||
private final ChangeNotes.Factory notesFactory;
|
||||
private final AccountResolver accountResolver;
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final PermissionBackend.ForProject permissions;
|
||||
private final CmdLineParser.Factory optionParserFactory;
|
||||
private final GitReferenceUpdated gitRefUpdated;
|
||||
private final PatchSetInfoFactory patchSetInfoFactory;
|
||||
@@ -393,7 +397,7 @@ public class ReceiveCommits {
|
||||
SetHashtagsOp.Factory hashtagsFactory,
|
||||
ReplaceOp.Factory replaceOpFactory,
|
||||
MergedByPushOp.Factory mergedByPushOpFactory)
|
||||
throws IOException {
|
||||
throws IOException, PermissionBackendException {
|
||||
this.user = projectControl.getUser().asIdentifiedUser();
|
||||
this.db = db;
|
||||
this.seq = seq;
|
||||
@@ -468,9 +472,15 @@ public class ReceiveCommits {
|
||||
}
|
||||
});
|
||||
|
||||
if (!projectControl.allRefsAreVisible()) {
|
||||
permissions = permissionBackend.user(user).project(project.getNameKey());
|
||||
// If the user lacks READ permission, some references may be filtered and hidden from view.
|
||||
// Check objects mentioned inside the incoming pack file are reachable from visible refs.
|
||||
try {
|
||||
permissions.check(ProjectPermission.READ);
|
||||
} catch (AuthException e) {
|
||||
rp.setCheckReferencedObjectsAreReachable(receiveConfig.checkReferencedObjectsAreReachable);
|
||||
}
|
||||
|
||||
rp.setAdvertiseRefsHook(
|
||||
new VisibleRefFilter(tagCache, notesFactory, changeCache, repo, projectControl, db, false));
|
||||
List<AdvertiseRefsHook> advHooks = new ArrayList<>(3);
|
||||
@@ -584,7 +594,16 @@ public class ReceiveCommits {
|
||||
batch.setRefLogIdent(rp.getRefLogIdent());
|
||||
batch.setRefLogMessage("push", true);
|
||||
|
||||
parseCommands(commands);
|
||||
try {
|
||||
parseCommands(commands);
|
||||
} catch (PermissionBackendException err) {
|
||||
for (ReceiveCommand cmd : batch.getCommands()) {
|
||||
if (cmd.getResult() == NOT_ATTEMPTED) {
|
||||
cmd.setResult(REJECTED_OTHER_REASON, "internal server error");
|
||||
}
|
||||
}
|
||||
logError(String.format("Failed to process refs in %s", project.getName()), err);
|
||||
}
|
||||
if (magicBranch != null && magicBranch.cmd.getResult() == NOT_ATTEMPTED) {
|
||||
selectNewAndReplacedChangesFromMagicBranch();
|
||||
}
|
||||
@@ -928,7 +947,8 @@ public class ReceiveCommits {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
private void parseCommands(Collection<ReceiveCommand> commands) {
|
||||
private void parseCommands(Collection<ReceiveCommand> commands)
|
||||
throws PermissionBackendException {
|
||||
List<String> optionList = rp.getPushOptions();
|
||||
if (optionList != null) {
|
||||
for (String option : optionList) {
|
||||
@@ -1162,24 +1182,29 @@ public class ReceiveCommits {
|
||||
}
|
||||
}
|
||||
|
||||
private void parseUpdate(ReceiveCommand cmd) {
|
||||
private void parseUpdate(ReceiveCommand cmd) throws PermissionBackendException {
|
||||
logDebug("Updating {}", cmd);
|
||||
RefControl ctl = projectControl.controlForRef(cmd.getRefName());
|
||||
if (ctl.canUpdate()) {
|
||||
boolean ok;
|
||||
try {
|
||||
permissions.ref(cmd.getRefName()).check(RefPermission.UPDATE);
|
||||
ok = true;
|
||||
} catch (AuthException err) {
|
||||
ok = false;
|
||||
}
|
||||
if (ok) {
|
||||
if (isHead(cmd) && !isCommit(cmd)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validRefOperation(cmd)) {
|
||||
return;
|
||||
}
|
||||
validateNewCommits(ctl, cmd);
|
||||
validateNewCommits(projectControl.controlForRef(cmd.getRefName()), cmd);
|
||||
batch.addCommand(cmd);
|
||||
} else {
|
||||
if (RefNames.REFS_CONFIG.equals(ctl.getRefName())) {
|
||||
if (RefNames.REFS_CONFIG.equals(cmd.getRefName())) {
|
||||
errors.put(Error.CONFIG_UPDATE, RefNames.REFS_CONFIG);
|
||||
} else {
|
||||
errors.put(Error.UPDATE, ctl.getRefName());
|
||||
errors.put(Error.UPDATE, cmd.getRefName());
|
||||
}
|
||||
reject(cmd, "prohibited by Gerrit: ref update access denied");
|
||||
}
|
||||
@@ -1223,7 +1248,7 @@ public class ReceiveCommits {
|
||||
}
|
||||
}
|
||||
|
||||
private void parseRewind(ReceiveCommand cmd) {
|
||||
private void parseRewind(ReceiveCommand cmd) throws PermissionBackendException {
|
||||
RevCommit newObject;
|
||||
try {
|
||||
newObject = rp.getRevWalk().parseCommit(cmd.getNewId());
|
||||
@@ -1246,7 +1271,14 @@ public class ReceiveCommits {
|
||||
}
|
||||
}
|
||||
|
||||
if (ctl.canForceUpdate()) {
|
||||
boolean ok;
|
||||
try {
|
||||
permissions.ref(cmd.getRefName()).check(RefPermission.FORCE_UPDATE);
|
||||
ok = true;
|
||||
} catch (AuthException err) {
|
||||
ok = false;
|
||||
}
|
||||
if (ok) {
|
||||
if (!validRefOperation(cmd)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -261,6 +261,25 @@ public abstract class PermissionBackend {
|
||||
public boolean test(RefPermission perm) throws PermissionBackendException {
|
||||
return test(EnumSet.of(perm)).contains(perm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if user may be able to perform the permission.
|
||||
*
|
||||
* <p>Similar to {@link #test(RefPermission)} except this method returns {@code false} instead
|
||||
* of throwing an exception.
|
||||
*
|
||||
* @param perm the permission to test.
|
||||
* @return true if the user might be able to perform the permission; false if the user may be
|
||||
* missing the necessary grants or state, or if the backend threw an exception.
|
||||
*/
|
||||
public boolean testOrFalse(RefPermission perm) {
|
||||
try {
|
||||
return test(perm);
|
||||
} catch (PermissionBackendException e) {
|
||||
logger.warn("Cannot test " + perm + "; assuming false", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** PermissionBackend scoped to a user, project, reference and change. */
|
||||
|
||||
@@ -188,7 +188,7 @@ public class RefControl {
|
||||
}
|
||||
|
||||
/** @return true if the user can update the reference as a fast-forward. */
|
||||
public boolean canUpdate() {
|
||||
private boolean canUpdate() {
|
||||
if (RefNames.REFS_CONFIG.equals(refName) && !projectControl.isOwner()) {
|
||||
// Pushing requires being at least project owner, in addition to push.
|
||||
// Pushing configuration changes modifies the access control
|
||||
@@ -208,7 +208,7 @@ public class RefControl {
|
||||
}
|
||||
|
||||
/** @return true if the user can rewind (force push) the reference. */
|
||||
public boolean canForceUpdate() {
|
||||
private boolean canForceUpdate() {
|
||||
if (!canWrite()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user