Merge "Make project state check in READ explicit"
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
package com.google.gerrit.httpd.raw;
|
||||
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.extensions.restapi.Url;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.Patch;
|
||||
@@ -29,6 +30,7 @@ import com.google.gerrit.server.permissions.ChangePermission;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
@@ -57,6 +59,7 @@ public class CatServlet extends HttpServlet {
|
||||
private final PatchSetUtil psUtil;
|
||||
private final ChangeNotes.Factory changeNotesFactory;
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final ProjectCache projectCache;
|
||||
|
||||
@Inject
|
||||
CatServlet(
|
||||
@@ -65,13 +68,15 @@ public class CatServlet extends HttpServlet {
|
||||
ChangeEditUtil ceu,
|
||||
PatchSetUtil psu,
|
||||
ChangeNotes.Factory cnf,
|
||||
PermissionBackend pb) {
|
||||
PermissionBackend pb,
|
||||
ProjectCache pc) {
|
||||
requestDb = sf;
|
||||
userProvider = usrprv;
|
||||
changeEditUtil = ceu;
|
||||
psUtil = psu;
|
||||
changeNotesFactory = cnf;
|
||||
permissionBackend = pb;
|
||||
projectCache = pc;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -131,6 +136,7 @@ public class CatServlet extends HttpServlet {
|
||||
.change(notes)
|
||||
.database(requestDb)
|
||||
.check(ChangePermission.READ);
|
||||
projectCache.checkedGet(notes.getProjectName()).checkStatePermitsRead();
|
||||
if (patchKey.getParentKey().get() == 0) {
|
||||
// change edit
|
||||
Optional<ChangeEdit> edit = changeEditUtil.byChange(notes);
|
||||
@@ -148,10 +154,10 @@ public class CatServlet extends HttpServlet {
|
||||
}
|
||||
revision = patchSet.getRevision().get();
|
||||
}
|
||||
} catch (NoSuchChangeException | AuthException e) {
|
||||
} catch (ResourceConflictException | NoSuchChangeException | AuthException e) {
|
||||
rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
} catch (OrmException | PermissionBackendException e) {
|
||||
} catch (OrmException | PermissionBackendException | IOException e) {
|
||||
getServletContext().log("Cannot query database", e);
|
||||
rsp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
return;
|
||||
|
||||
@@ -49,10 +49,12 @@ import com.google.gerrit.server.permissions.ChangePermission;
|
||||
import com.google.gerrit.server.permissions.LabelPermission;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.util.LabelVote;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -109,6 +111,7 @@ public class ApprovalsUtil {
|
||||
private final IdentifiedUser.GenericFactory userFactory;
|
||||
private final ApprovalCopier copier;
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final ProjectCache projectCache;
|
||||
|
||||
@VisibleForTesting
|
||||
@Inject
|
||||
@@ -116,11 +119,13 @@ public class ApprovalsUtil {
|
||||
NotesMigration migration,
|
||||
IdentifiedUser.GenericFactory userFactory,
|
||||
ApprovalCopier copier,
|
||||
PermissionBackend permissionBackend) {
|
||||
PermissionBackend permissionBackend,
|
||||
ProjectCache projectCache) {
|
||||
this.migration = migration;
|
||||
this.userFactory = userFactory;
|
||||
this.copier = copier;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.projectCache = projectCache;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,8 +268,9 @@ public class ApprovalsUtil {
|
||||
private boolean canSee(ReviewDb db, ChangeNotes notes, Account.Id accountId) {
|
||||
try {
|
||||
IdentifiedUser user = userFactory.create(accountId);
|
||||
return permissionBackend.user(user).change(notes).database(db).test(ChangePermission.READ);
|
||||
} catch (PermissionBackendException e) {
|
||||
return projectCache.checkedGet(notes.getProjectName()).statePermitsRead()
|
||||
&& permissionBackend.user(user).change(notes).database(db).test(ChangePermission.READ);
|
||||
} catch (IOException | PermissionBackendException e) {
|
||||
log.warn(
|
||||
String.format(
|
||||
"Failed to check if account %d can see change %d",
|
||||
|
||||
@@ -467,10 +467,11 @@ public class ChangeInserter implements InsertChangeOp {
|
||||
try {
|
||||
IdentifiedUser user = userFactory.create(accountId);
|
||||
return permissionBackend
|
||||
.user(user)
|
||||
.change(notes)
|
||||
.database(db)
|
||||
.test(ChangePermission.READ);
|
||||
.user(user)
|
||||
.change(notes)
|
||||
.database(db)
|
||||
.test(ChangePermission.READ)
|
||||
&& projectState.statePermitsRead();
|
||||
} catch (PermissionBackendException e) {
|
||||
log.warn(
|
||||
String.format(
|
||||
|
||||
@@ -124,6 +124,7 @@ import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.project.RemoveReviewerControl;
|
||||
import com.google.gerrit.server.project.SubmitRuleOptions;
|
||||
import com.google.gerrit.server.query.change.ChangeData;
|
||||
@@ -1469,13 +1470,19 @@ public class ChangeJson {
|
||||
: withUser.indexedChange(cd, notesFactory.createFromIndexedChange(cd.change()));
|
||||
}
|
||||
|
||||
private boolean isWorldReadable(ChangeData cd) throws OrmException, PermissionBackendException {
|
||||
private boolean isWorldReadable(ChangeData cd)
|
||||
throws OrmException, PermissionBackendException, IOException {
|
||||
try {
|
||||
permissionBackendForChange(anonymous, cd).check(ChangePermission.READ);
|
||||
return true;
|
||||
} catch (AuthException ae) {
|
||||
return false;
|
||||
}
|
||||
ProjectState projectState = projectCache.checkedGet(cd.project());
|
||||
if (projectState == null) {
|
||||
log.error("project state for project " + cd.project() + " is null");
|
||||
return false;
|
||||
}
|
||||
return projectState.statePermitsRead();
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
|
||||
@@ -163,7 +163,7 @@ public class EventBroker implements EventDispatcher {
|
||||
return false;
|
||||
}
|
||||
ProjectState pe = projectCache.get(change.getProject());
|
||||
if (pe == null) {
|
||||
if (pe == null || !pe.statePermitsRead()) {
|
||||
return false;
|
||||
}
|
||||
ReviewDb db = dbProvider.get();
|
||||
|
||||
@@ -33,6 +33,8 @@ import com.google.gerrit.server.permissions.ChangePermission;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.query.change.ChangeData;
|
||||
import com.google.gerrit.server.query.change.InternalChangeQuery;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
@@ -87,10 +89,14 @@ public class LocalMergeSuperSetComputation implements MergeSuperSetComputation {
|
||||
private final Provider<InternalChangeQuery> queryProvider;
|
||||
private final Map<QueryKey, List<ChangeData>> queryCache;
|
||||
private final Map<Branch.NameKey, Optional<RevCommit>> heads;
|
||||
private final ProjectCache projectCache;
|
||||
|
||||
@Inject
|
||||
LocalMergeSuperSetComputation(
|
||||
PermissionBackend permissionBackend, Provider<InternalChangeQuery> queryProvider) {
|
||||
PermissionBackend permissionBackend,
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
ProjectCache projectCache) {
|
||||
this.projectCache = projectCache;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.queryProvider = queryProvider;
|
||||
this.queryCache = new HashMap<>();
|
||||
@@ -171,8 +177,12 @@ public class LocalMergeSuperSetComputation implements MergeSuperSetComputation {
|
||||
}
|
||||
|
||||
private boolean isVisible(ReviewDb db, ChangeSet changeSet, ChangeData cd, CurrentUser user)
|
||||
throws PermissionBackendException {
|
||||
boolean visible = changeSet.ids().contains(cd.getId());
|
||||
throws PermissionBackendException, IOException {
|
||||
ProjectState projectState = projectCache.checkedGet(cd.project());
|
||||
boolean visible =
|
||||
changeSet.ids().contains(cd.getId())
|
||||
&& (projectState != null)
|
||||
&& projectState.statePermitsRead();
|
||||
if (visible
|
||||
&& !permissionBackend.user(user).change(cd).database(db).test(ChangePermission.READ)) {
|
||||
// We thought the change was visible, but it isn't.
|
||||
|
||||
@@ -27,6 +27,8 @@ import com.google.gerrit.server.index.change.ChangeField;
|
||||
import com.google.gerrit.server.permissions.ChangePermission;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.query.change.ChangeData;
|
||||
import com.google.gerrit.server.query.change.InternalChangeQuery;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
@@ -75,6 +77,7 @@ public class MergeSuperSet {
|
||||
private final DynamicItem<MergeSuperSetComputation> mergeSuperSetComputation;
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final Config cfg;
|
||||
private final ProjectCache projectCache;
|
||||
|
||||
private MergeOpRepoManager orm;
|
||||
private boolean closeOrm;
|
||||
@@ -86,13 +89,15 @@ public class MergeSuperSet {
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
Provider<MergeOpRepoManager> repoManagerProvider,
|
||||
DynamicItem<MergeSuperSetComputation> mergeSuperSetComputation,
|
||||
PermissionBackend permissionBackend) {
|
||||
PermissionBackend permissionBackend,
|
||||
ProjectCache projectCache) {
|
||||
this.cfg = cfg;
|
||||
this.changeDataFactory = changeDataFactory;
|
||||
this.queryProvider = queryProvider;
|
||||
this.repoManagerProvider = repoManagerProvider;
|
||||
this.mergeSuperSetComputation = mergeSuperSetComputation;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.projectCache = projectCache;
|
||||
}
|
||||
|
||||
public static boolean wholeTopicEnabled(Config config) {
|
||||
@@ -115,9 +120,17 @@ public class MergeSuperSet {
|
||||
}
|
||||
|
||||
ChangeData cd = changeDataFactory.create(db, change.getProject(), change.getId());
|
||||
ProjectState projectState = projectCache.checkedGet(cd.project());
|
||||
ChangeSet changeSet =
|
||||
new ChangeSet(
|
||||
cd, permissionBackend.user(user).change(cd).database(db).test(ChangePermission.READ));
|
||||
cd,
|
||||
projectState != null
|
||||
&& projectState.statePermitsRead()
|
||||
&& permissionBackend
|
||||
.user(user)
|
||||
.change(cd)
|
||||
.database(db)
|
||||
.test(ChangePermission.READ));
|
||||
if (wholeTopicEnabled(cfg)) {
|
||||
return completeChangeSetIncludingTopics(db, changeSet, user);
|
||||
}
|
||||
@@ -149,7 +162,7 @@ public class MergeSuperSet {
|
||||
CurrentUser user,
|
||||
Set<String> topicsSeen,
|
||||
Set<String> visibleTopicsSeen)
|
||||
throws OrmException, PermissionBackendException {
|
||||
throws OrmException, PermissionBackendException, IOException {
|
||||
List<ChangeData> visibleChanges = new ArrayList<>();
|
||||
List<ChangeData> nonVisibleChanges = new ArrayList<>();
|
||||
|
||||
@@ -208,7 +221,10 @@ public class MergeSuperSet {
|
||||
}
|
||||
|
||||
private boolean canRead(ReviewDb db, CurrentUser user, ChangeData cd)
|
||||
throws PermissionBackendException {
|
||||
return permissionBackend.user(user).change(cd).database(db).test(ChangePermission.READ);
|
||||
throws PermissionBackendException, IOException {
|
||||
ProjectState projectState = projectCache.checkedGet(cd.project());
|
||||
return projectState != null
|
||||
&& projectState.statePermitsRead()
|
||||
&& permissionBackend.user(user).change(cd).database(db).test(ChangePermission.READ);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +316,8 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
|
||||
Map<Change.Id, Branch.NameKey> visibleChanges = new HashMap<>();
|
||||
for (ChangeData cd : changeCache.getChangeData(db.get(), project)) {
|
||||
ChangeNotes notes = changeNotesFactory.createFromIndexedChange(cd.change());
|
||||
if (perm.indexedChange(cd, notes).test(ChangePermission.READ)) {
|
||||
if (projectState.statePermitsRead()
|
||||
&& perm.indexedChange(cd, notes).test(ChangePermission.READ)) {
|
||||
visibleChanges.put(cd.getId(), cd.change().getDest());
|
||||
}
|
||||
}
|
||||
@@ -349,7 +350,7 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if (perm.change(r.notes()).test(ChangePermission.READ)) {
|
||||
if (projectState.statePermitsRead() && perm.change(r.notes()).test(ChangePermission.READ)) {
|
||||
return r.notes();
|
||||
}
|
||||
} catch (PermissionBackendException e) {
|
||||
|
||||
@@ -408,11 +408,12 @@ public abstract class ChangeEmail extends NotificationEmail {
|
||||
|
||||
@Override
|
||||
protected boolean isVisibleTo(Account.Id to) throws OrmException, PermissionBackendException {
|
||||
return args.permissionBackend
|
||||
.user(args.identifiedUserFactory.create(to))
|
||||
.change(changeData)
|
||||
.database(args.db.get())
|
||||
.test(ChangePermission.READ);
|
||||
return projectState.statePermitsRead()
|
||||
&& args.permissionBackend
|
||||
.user(args.identifiedUserFactory.create(to))
|
||||
.change(changeData)
|
||||
.database(args.db.get())
|
||||
.test(ChangePermission.READ);
|
||||
}
|
||||
|
||||
/** Find all users who are authors of any part of this change. */
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.InvalidChangeOperationException;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
@@ -93,6 +94,7 @@ public class PatchScriptFactory implements Callable<PatchScript> {
|
||||
private final ChangeEditUtil editReader;
|
||||
private final Provider<CurrentUser> userProvider;
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final ProjectCache projectCache;
|
||||
private Optional<ChangeEdit> edit;
|
||||
|
||||
private final Change.Id changeId;
|
||||
@@ -116,6 +118,7 @@ public class PatchScriptFactory implements Callable<PatchScript> {
|
||||
ChangeEditUtil editReader,
|
||||
Provider<CurrentUser> userProvider,
|
||||
PermissionBackend permissionBackend,
|
||||
ProjectCache projectCache,
|
||||
@Assisted ChangeNotes notes,
|
||||
@Assisted String fileName,
|
||||
@Assisted("patchSetA") @Nullable PatchSet.Id patchSetA,
|
||||
@@ -131,6 +134,7 @@ public class PatchScriptFactory implements Callable<PatchScript> {
|
||||
this.editReader = editReader;
|
||||
this.userProvider = userProvider;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.projectCache = projectCache;
|
||||
|
||||
this.fileName = fileName;
|
||||
this.psa = patchSetA;
|
||||
@@ -152,6 +156,7 @@ public class PatchScriptFactory implements Callable<PatchScript> {
|
||||
ChangeEditUtil editReader,
|
||||
Provider<CurrentUser> userProvider,
|
||||
PermissionBackend permissionBackend,
|
||||
ProjectCache projectCache,
|
||||
@Assisted ChangeNotes notes,
|
||||
@Assisted String fileName,
|
||||
@Assisted int parentNum,
|
||||
@@ -167,6 +172,7 @@ public class PatchScriptFactory implements Callable<PatchScript> {
|
||||
this.editReader = editReader;
|
||||
this.userProvider = userProvider;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.projectCache = projectCache;
|
||||
|
||||
this.fileName = fileName;
|
||||
this.psa = null;
|
||||
@@ -209,6 +215,10 @@ public class PatchScriptFactory implements Callable<PatchScript> {
|
||||
}
|
||||
}
|
||||
|
||||
if (!projectCache.checkedGet(notes.getProjectName()).statePermitsRead()) {
|
||||
throw new NoSuchChangeException(changeId);
|
||||
}
|
||||
|
||||
try (Repository git = repoManager.openRepository(notes.getProjectName())) {
|
||||
bId = toObjectId(psEntityB);
|
||||
if (parentNum < 0) {
|
||||
|
||||
@@ -130,7 +130,7 @@ class ChangeControl {
|
||||
if (getChange().isPrivate() && !isPrivateVisible(db, cd)) {
|
||||
return false;
|
||||
}
|
||||
return refControl.isVisible() && getProjectControl().getProject().getState().permitsRead();
|
||||
return refControl.isVisible();
|
||||
}
|
||||
|
||||
/** Can this user abandon this change? */
|
||||
|
||||
@@ -24,8 +24,11 @@ import com.google.gerrit.server.permissions.ChangePermission;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Provider;
|
||||
import java.io.IOException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -36,17 +39,20 @@ public class ChangeIsVisibleToPredicate extends IsVisibleToPredicate<ChangeData>
|
||||
protected final ChangeNotes.Factory notesFactory;
|
||||
protected final CurrentUser user;
|
||||
protected final PermissionBackend permissionBackend;
|
||||
protected final ProjectCache projectCache;
|
||||
|
||||
public ChangeIsVisibleToPredicate(
|
||||
Provider<ReviewDb> db,
|
||||
ChangeNotes.Factory notesFactory,
|
||||
CurrentUser user,
|
||||
PermissionBackend permissionBackend) {
|
||||
PermissionBackend permissionBackend,
|
||||
ProjectCache projectCache) {
|
||||
super(ChangeQueryBuilder.FIELD_VISIBLETO, IndexUtils.describe(user));
|
||||
this.db = db;
|
||||
this.notesFactory = notesFactory;
|
||||
this.user = user;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.projectCache = projectCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,6 +66,20 @@ public class ChangeIsVisibleToPredicate extends IsVisibleToPredicate<ChangeData>
|
||||
}
|
||||
|
||||
ChangeNotes notes = notesFactory.createFromIndexedChange(change);
|
||||
|
||||
try {
|
||||
ProjectState projectState = projectCache.checkedGet(cd.project());
|
||||
if (projectState == null) {
|
||||
logger.info("No such project: {}", cd.project());
|
||||
return false;
|
||||
}
|
||||
if (!projectState.statePermitsRead()) {
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new OrmException("unable to read project state", e);
|
||||
}
|
||||
|
||||
boolean visible;
|
||||
try {
|
||||
visible =
|
||||
|
||||
@@ -915,7 +915,8 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
}
|
||||
|
||||
public Predicate<ChangeData> visibleto(CurrentUser user) {
|
||||
return new ChangeIsVisibleToPredicate(args.db, args.notesFactory, user, args.permissionBackend);
|
||||
return new ChangeIsVisibleToPredicate(
|
||||
args.db, args.notesFactory, user, args.permissionBackend, args.projectCache);
|
||||
}
|
||||
|
||||
public Predicate<ChangeData> is_visible() throws QueryParseException {
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.google.gerrit.server.index.change.ChangeSchemaDefinitions;
|
||||
import com.google.gerrit.server.index.change.IndexedChangeQuery;
|
||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.ArrayList;
|
||||
@@ -63,6 +64,7 @@ public class ChangeQueryProcessor extends QueryProcessor<ChangeData>
|
||||
private final ChangeNotes.Factory notesFactory;
|
||||
private final DynamicMap<ChangeAttributeFactory> attributeFactories;
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final ProjectCache projectCache;
|
||||
|
||||
static {
|
||||
// It is assumed that basic rewrites do not touch visibleto predicates.
|
||||
@@ -82,7 +84,8 @@ public class ChangeQueryProcessor extends QueryProcessor<ChangeData>
|
||||
Provider<ReviewDb> db,
|
||||
ChangeNotes.Factory notesFactory,
|
||||
DynamicMap<ChangeAttributeFactory> attributeFactories,
|
||||
PermissionBackend permissionBackend) {
|
||||
PermissionBackend permissionBackend,
|
||||
ProjectCache projectCache) {
|
||||
super(
|
||||
metricMaker,
|
||||
ChangeSchemaDefinitions.INSTANCE,
|
||||
@@ -96,6 +99,7 @@ public class ChangeQueryProcessor extends QueryProcessor<ChangeData>
|
||||
this.notesFactory = notesFactory;
|
||||
this.attributeFactories = attributeFactories;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.projectCache = projectCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,7 +142,8 @@ public class ChangeQueryProcessor extends QueryProcessor<ChangeData>
|
||||
protected Predicate<ChangeData> enforceVisibility(Predicate<ChangeData> pred) {
|
||||
return new AndChangeSource(
|
||||
pred,
|
||||
new ChangeIsVisibleToPredicate(db, notesFactory, userProvider.get(), permissionBackend),
|
||||
new ChangeIsVisibleToPredicate(
|
||||
db, notesFactory, userProvider.get(), permissionBackend, projectCache),
|
||||
start);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Provider;
|
||||
import java.io.IOException;
|
||||
|
||||
public class EqualsLabelPredicate extends ChangeIndexPredicate {
|
||||
protected final ProjectCache projectCache;
|
||||
@@ -123,8 +124,11 @@ public class EqualsLabelPredicate extends ChangeIndexPredicate {
|
||||
try {
|
||||
PermissionBackend.ForChange perm =
|
||||
permissionBackend.user(reviewer).database(dbProvider).change(cd);
|
||||
return perm.test(ChangePermission.READ);
|
||||
} catch (PermissionBackendException e) {
|
||||
ProjectState projectState = projectCache.checkedGet(cd.project());
|
||||
return projectState != null
|
||||
&& projectState.statePermitsRead()
|
||||
&& perm.test(ChangePermission.READ);
|
||||
} catch (PermissionBackendException | IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,13 +135,17 @@ public class ChangesCollection
|
||||
return createChange;
|
||||
}
|
||||
|
||||
private boolean canRead(ChangeNotes notes) throws PermissionBackendException {
|
||||
private boolean canRead(ChangeNotes notes) throws PermissionBackendException, IOException {
|
||||
try {
|
||||
permissionBackend.user(user).change(notes).database(db).check(ChangePermission.READ);
|
||||
return true;
|
||||
} catch (AuthException e) {
|
||||
return false;
|
||||
}
|
||||
ProjectState projectState = projectCache.checkedGet(notes.getProjectName());
|
||||
if (projectState == null) {
|
||||
return false;
|
||||
}
|
||||
return projectState.statePermitsRead();
|
||||
}
|
||||
|
||||
private void checkProjectStatePermitsRead(Project.NameKey project)
|
||||
|
||||
@@ -101,7 +101,7 @@ public class GetRelated implements RestReadView<RevisionResource> {
|
||||
|
||||
reloadChangeIfStale(cds, basePs);
|
||||
|
||||
for (RelatedChangesSorter.PatchSetData d : sorter.sort(cds, basePs, rsrc.getUser())) {
|
||||
for (RelatedChangesSorter.PatchSetData d : sorter.sort(cds, basePs)) {
|
||||
PatchSet ps = d.patchSet();
|
||||
RevCommit commit;
|
||||
if (isEdit && ps.getId().equals(basePs.getId())) {
|
||||
|
||||
@@ -34,6 +34,8 @@ import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.permissions.ChangePermission;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.query.change.ChangeData;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
@@ -61,25 +63,30 @@ class RelatedChangesSorter {
|
||||
private final GitRepositoryManager repoManager;
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final Provider<ReviewDb> dbProvider;
|
||||
private final ProjectCache projectCache;
|
||||
private final Provider<CurrentUser> currentUserProvider;
|
||||
|
||||
@Inject
|
||||
RelatedChangesSorter(
|
||||
GitRepositoryManager repoManager,
|
||||
PermissionBackend permissionBackend,
|
||||
Provider<ReviewDb> dbProvider) {
|
||||
Provider<ReviewDb> dbProvider,
|
||||
ProjectCache projectCache,
|
||||
Provider<CurrentUser> currentUserProvider) {
|
||||
this.repoManager = repoManager;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.dbProvider = dbProvider;
|
||||
this.projectCache = projectCache;
|
||||
this.currentUserProvider = currentUserProvider;
|
||||
}
|
||||
|
||||
public List<PatchSetData> sort(List<ChangeData> in, PatchSet startPs, CurrentUser user)
|
||||
public List<PatchSetData> sort(List<ChangeData> in, PatchSet startPs)
|
||||
throws OrmException, IOException, PermissionBackendException {
|
||||
checkArgument(!in.isEmpty(), "Input may not be empty");
|
||||
// Map of all patch sets, keyed by commit SHA-1.
|
||||
Map<String, PatchSetData> byId = collectById(in);
|
||||
PatchSetData start = byId.get(startPs.getRevision().get());
|
||||
checkArgument(start != null, "%s not found in %s", startPs, in);
|
||||
PermissionBackend.WithUser perm = permissionBackend.user(user).database(dbProvider);
|
||||
|
||||
// Map of patch set -> immediate parent.
|
||||
ListMultimap<PatchSetData, PatchSetData> parents =
|
||||
@@ -106,9 +113,9 @@ class RelatedChangesSorter {
|
||||
}
|
||||
}
|
||||
|
||||
Collection<PatchSetData> ancestors = walkAncestors(perm, parents, start);
|
||||
Collection<PatchSetData> ancestors = walkAncestors(parents, start);
|
||||
List<PatchSetData> descendants =
|
||||
walkDescendants(perm, children, start, otherPatchSetsOfStart, ancestors);
|
||||
walkDescendants(children, start, otherPatchSetsOfStart, ancestors);
|
||||
List<PatchSetData> result = new ArrayList<>(ancestors.size() + descendants.size() - 1);
|
||||
result.addAll(Lists.reverse(descendants));
|
||||
result.addAll(ancestors);
|
||||
@@ -140,17 +147,15 @@ class RelatedChangesSorter {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Collection<PatchSetData> walkAncestors(
|
||||
PermissionBackend.WithUser perm,
|
||||
ListMultimap<PatchSetData, PatchSetData> parents,
|
||||
PatchSetData start)
|
||||
throws PermissionBackendException {
|
||||
private Collection<PatchSetData> walkAncestors(
|
||||
ListMultimap<PatchSetData, PatchSetData> parents, PatchSetData start)
|
||||
throws PermissionBackendException, IOException {
|
||||
LinkedHashSet<PatchSetData> result = new LinkedHashSet<>();
|
||||
Deque<PatchSetData> pending = new ArrayDeque<>();
|
||||
pending.add(start);
|
||||
while (!pending.isEmpty()) {
|
||||
PatchSetData psd = pending.remove();
|
||||
if (result.contains(psd) || !isVisible(psd, perm)) {
|
||||
if (result.contains(psd) || !isVisible(psd)) {
|
||||
continue;
|
||||
}
|
||||
result.add(psd);
|
||||
@@ -159,26 +164,24 @@ class RelatedChangesSorter {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<PatchSetData> walkDescendants(
|
||||
PermissionBackend.WithUser perm,
|
||||
private List<PatchSetData> walkDescendants(
|
||||
ListMultimap<PatchSetData, PatchSetData> children,
|
||||
PatchSetData start,
|
||||
List<PatchSetData> otherPatchSetsOfStart,
|
||||
Iterable<PatchSetData> ancestors)
|
||||
throws PermissionBackendException {
|
||||
throws PermissionBackendException, IOException {
|
||||
Set<Change.Id> alreadyEmittedChanges = new HashSet<>();
|
||||
addAllChangeIds(alreadyEmittedChanges, ancestors);
|
||||
|
||||
// Prefer descendants found by following the original patch set passed in.
|
||||
List<PatchSetData> result =
|
||||
walkDescendentsImpl(perm, alreadyEmittedChanges, children, ImmutableList.of(start));
|
||||
walkDescendentsImpl(alreadyEmittedChanges, children, ImmutableList.of(start));
|
||||
addAllChangeIds(alreadyEmittedChanges, result);
|
||||
|
||||
// Then, go back and add new indirect descendants found by following any
|
||||
// other patch sets of start. These show up after all direct descendants,
|
||||
// because we wouldn't know where in the walk to insert them.
|
||||
result.addAll(
|
||||
walkDescendentsImpl(perm, alreadyEmittedChanges, children, otherPatchSetsOfStart));
|
||||
result.addAll(walkDescendentsImpl(alreadyEmittedChanges, children, otherPatchSetsOfStart));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -189,12 +192,11 @@ class RelatedChangesSorter {
|
||||
}
|
||||
}
|
||||
|
||||
private static List<PatchSetData> walkDescendentsImpl(
|
||||
PermissionBackend.WithUser perm,
|
||||
private List<PatchSetData> walkDescendentsImpl(
|
||||
Set<Change.Id> alreadyEmittedChanges,
|
||||
ListMultimap<PatchSetData, PatchSetData> children,
|
||||
List<PatchSetData> start)
|
||||
throws PermissionBackendException {
|
||||
throws PermissionBackendException, IOException {
|
||||
if (start.isEmpty()) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
@@ -205,7 +207,7 @@ class RelatedChangesSorter {
|
||||
pending.addAll(start);
|
||||
while (!pending.isEmpty()) {
|
||||
PatchSetData psd = pending.remove();
|
||||
if (seen.contains(psd) || !isVisible(psd, perm)) {
|
||||
if (seen.contains(psd) || !isVisible(psd)) {
|
||||
continue;
|
||||
}
|
||||
seen.add(psd);
|
||||
@@ -236,14 +238,16 @@ class RelatedChangesSorter {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isVisible(PatchSetData psd, PermissionBackend.WithUser perm)
|
||||
throws PermissionBackendException {
|
||||
private boolean isVisible(PatchSetData psd) throws PermissionBackendException, IOException {
|
||||
PermissionBackend.WithUser perm =
|
||||
permissionBackend.user(currentUserProvider).database(dbProvider);
|
||||
try {
|
||||
perm.change(psd.data()).check(ChangePermission.READ);
|
||||
return true;
|
||||
} catch (AuthException e) {
|
||||
return false;
|
||||
}
|
||||
ProjectState state = projectCache.checkedGet(psd.data().project());
|
||||
return state != null && state.statePermitsRead();
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.google.gerrit.server.edit.ChangeEditUtil;
|
||||
import com.google.gerrit.server.permissions.ChangePermission;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
@@ -51,6 +52,7 @@ public class Revisions implements ChildCollection<ChangeResource, RevisionResour
|
||||
private final ChangeEditUtil editUtil;
|
||||
private final PatchSetUtil psUtil;
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final ProjectCache projectCache;
|
||||
|
||||
@Inject
|
||||
Revisions(
|
||||
@@ -58,12 +60,14 @@ public class Revisions implements ChildCollection<ChangeResource, RevisionResour
|
||||
Provider<ReviewDb> dbProvider,
|
||||
ChangeEditUtil editUtil,
|
||||
PatchSetUtil psUtil,
|
||||
PermissionBackend permissionBackend) {
|
||||
PermissionBackend permissionBackend,
|
||||
ProjectCache projectCache) {
|
||||
this.views = views;
|
||||
this.dbProvider = dbProvider;
|
||||
this.editUtil = editUtil;
|
||||
this.psUtil = psUtil;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.projectCache = projectCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,14 +109,14 @@ public class Revisions implements ChildCollection<ChangeResource, RevisionResour
|
||||
}
|
||||
}
|
||||
|
||||
private boolean visible(ChangeResource change) throws PermissionBackendException {
|
||||
private boolean visible(ChangeResource change) throws PermissionBackendException, IOException {
|
||||
try {
|
||||
permissionBackend
|
||||
.user(change.getUser())
|
||||
.change(change.getNotes())
|
||||
.database(dbProvider)
|
||||
.check(ChangePermission.READ);
|
||||
return true;
|
||||
return projectCache.checkedGet(change.getProject()).statePermitsRead();
|
||||
} catch (AuthException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -92,11 +92,12 @@ public class ChangeArgumentParser {
|
||||
if (!changes.containsKey(notes.getChangeId())
|
||||
&& inProject(projectState, notes.getProjectName())
|
||||
&& (canMaintainServer
|
||||
|| permissionBackend
|
||||
.user(currentUser)
|
||||
.change(notes)
|
||||
.database(db)
|
||||
.test(ChangePermission.READ))) {
|
||||
|| (permissionBackend
|
||||
.user(currentUser)
|
||||
.change(notes)
|
||||
.database(db)
|
||||
.test(ChangePermission.READ)
|
||||
&& projectState.statePermitsRead()))) {
|
||||
toAdd.add(notes);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user