Fix: User could get around restrictions by editing commit msg

The Gerrit server may enforce several restrictions on the
commit message (change-id needed, signed-off-by, etc).

The user could get around these restrictions by pushing a
commit and then editing the commit message using the UI.

Now the "Edit commit message"-feature is using the
validation code refactored out from ReceiveCommits, and
correct validation of the commit message is done before
Gerrit accepts the new commit.

Change-Id: I2fb13ddb1ea5aacf672101b1e4c1867543bd66e3
This commit is contained in:
Gustaf Lundh
2012-11-30 16:12:16 +01:00
parent 55456d0578
commit 15d5ac0e70
4 changed files with 140 additions and 114 deletions

View File

@@ -28,18 +28,22 @@ import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.mail.CommitMessageEditedSender;
import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.ssh.NoSshInfo;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
@@ -63,6 +67,7 @@ class EditCommitMessageHandler extends Handler<ChangeDetail> {
private final String message;
private final ChangeHooks hooks;
private final CommitValidators.Factory commitValidatorsFactory;
private final GitRepositoryManager gitManager;
private final PatchSetInfoFactory patchSetInfoFactory;
@@ -76,6 +81,7 @@ class EditCommitMessageHandler extends Handler<ChangeDetail> {
final CommitMessageEditedSender.Factory commitMessageEditedSenderFactory,
@Assisted final PatchSet.Id patchSetId,
@Assisted @Nullable final String message, final ChangeHooks hooks,
final CommitValidators.Factory commitValidatorsFactory,
final GitRepositoryManager gitManager,
final PatchSetInfoFactory patchSetInfoFactory,
final GitReferenceUpdated replication,
@@ -89,6 +95,7 @@ class EditCommitMessageHandler extends Handler<ChangeDetail> {
this.patchSetId = patchSetId;
this.message = message;
this.hooks = hooks;
this.commitValidatorsFactory = commitValidatorsFactory;
this.gitManager = gitManager;
this.patchSetInfoFactory = patchSetInfoFactory;
@@ -109,10 +116,22 @@ class EditCommitMessageHandler extends Handler<ChangeDetail> {
"Not allowed to add new Patch Sets to: " + changeId.toString());
}
ChangeUtil.editCommitMessage(patchSetId, currentUser, message, db,
commitMessageEditedSenderFactory, hooks, gitManager, patchSetInfoFactory,
replication, myIdent);
final Repository git;
try {
git = gitManager.openRepository(db.changes().get(changeId).getProject());
} catch (RepositoryNotFoundException e) {
throw new NoSuchChangeException(changeId, e);
}
try {
CommitValidators commitValidators =
commitValidatorsFactory.create(control.getRefControl(), new NoSshInfo(), git);
ChangeUtil.editCommitMessage(patchSetId, control.getRefControl(), commitValidators, currentUser, message, db,
commitMessageEditedSenderFactory, hooks, git, patchSetInfoFactory, replication, myIdent);
return changeDetailFactory.create(changeId).call();
} finally {
git.close();
}
}
}

View File

@@ -27,15 +27,19 @@ import com.google.gerrit.reviewdb.client.TrackingId;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.config.TrackingFooter;
import com.google.gerrit.server.config.TrackingFooters;
import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MergeOp;
import com.google.gerrit.server.mail.CommitMessageEditedSender;
import com.google.gerrit.server.git.validators.CommitValidationException;
import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.mail.RevertedSender;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.RefControl;
import com.google.gerrit.server.util.IdGenerator;
import com.google.gwtorm.server.AtomicUpdate;
import com.google.gwtorm.server.OrmConcurrencyException;
@@ -54,6 +58,7 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.FooterLine;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.eclipse.jgit.util.Base64;
import org.eclipse.jgit.util.ChangeIdUtil;
import org.eclipse.jgit.util.NB;
@@ -305,9 +310,10 @@ public class ChangeUtil {
}
public static Change.Id editCommitMessage(final PatchSet.Id patchSetId,
final RefControl refControl, CommitValidators commitValidators,
final IdentifiedUser user, final String message, final ReviewDb db,
final CommitMessageEditedSender.Factory commitMessageEditedSenderFactory,
final ChangeHooks hooks, GitRepositoryManager gitManager,
final ChangeHooks hooks, Repository git,
final PatchSetInfoFactory patchSetInfoFactory,
final GitReferenceUpdated replication, PersonIdent myIdent)
throws NoSuchChangeException, EmailException, OrmException,
@@ -323,14 +329,6 @@ public class ChangeUtil {
throw new InvalidChangeOperationException("The commit message cannot be empty");
}
final Repository git;
try {
git = gitManager.openRepository(db.changes().get(changeId).getProject());
} catch (RepositoryNotFoundException e) {
throw new NoSuchChangeException(changeId, e);
}
try {
final RevWalk revWalk = new RevWalk(git);
try {
RevCommit commit =
@@ -372,6 +370,18 @@ public class ChangeUtil {
final PatchSetInfo info =
patchSetInfoFactory.get(newCommit, newPatchSet.getId());
CommitReceivedEvent commitReceivedEvent =
new CommitReceivedEvent(new ReceiveCommand(ObjectId.zeroId(),
newCommit.getId(), newPatchSet.getRefName()), refControl
.getProjectControl().getProject(), refControl.getRefName(),
newCommit, user);
try {
commitValidators.validateForReceiveCommits(commitReceivedEvent);
} catch (CommitValidationException e) {
throw new InvalidChangeOperationException(e.getMessage());
}
final RefUpdate ru = git.updateRef(newPatchSet.getRefName());
ru.setExpectedOldObjectId(ObjectId.zeroId());
ru.setNewObjectId(newCommit);
@@ -443,9 +453,6 @@ public class ChangeUtil {
} finally {
revWalk.release();
}
} finally {
git.close();
}
}
public static void deleteDraftChange(final PatchSet.Id patchSetId,

View File

@@ -58,7 +58,7 @@ public class CommitValidators {
private static final FooterKey CHANGE_ID = new FooterKey("Change-Id");
private static final Pattern NEW_PATCHSET = Pattern
.compile("^refs/changes/(?:[0-9][0-9]/)?([1-9][0-9]*)(?:/new)?$");
.compile("^refs/changes/(?:[0-9][0-9])?(/[1-9][0-9]*){1,2}(?:/new)?$");
public interface Factory {
CommitValidators create(RefControl refControl, SshInfo sshInfo,

View File

@@ -19,7 +19,7 @@ import com.jcraft.jsch.HostKey;
import java.util.Collections;
import java.util.List;
class NoSshInfo implements SshInfo {
public class NoSshInfo implements SshInfo {
@Override
public List<HostKey> getHostKeys() {
return Collections.emptyList();