Add #absentUser() to ForProject, ForRef and ForChange

We used to think adding this method to the top level is enough
and could avoid misuses. But it turns out we still need them in
other permission backend classes so that we only need to rescope
a user when necessary, which could provide better performance.
See I67b72b59 as an example.

Change-Id: I9ef30fb38315250fa63fb8b3d27e19e19d5e3e22
This commit is contained in:
Changcheng Xiao
2018-05-15 16:27:32 +02:00
parent 4501481b2a
commit 2b2a99e538
9 changed files with 85 additions and 11 deletions

View File

@@ -29,6 +29,7 @@ import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.notedb.ChangeNotes; import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.permissions.PermissionBackend.ForChange; import com.google.gerrit.server.permissions.PermissionBackend.ForChange;
import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.ChangeData;
@@ -47,11 +48,16 @@ class ChangeControl {
static class Factory { static class Factory {
private final ChangeData.Factory changeDataFactory; private final ChangeData.Factory changeDataFactory;
private final ChangeNotes.Factory notesFactory; private final ChangeNotes.Factory notesFactory;
private final IdentifiedUser.GenericFactory identifiedUserFactory;
@Inject @Inject
Factory(ChangeData.Factory changeDataFactory, ChangeNotes.Factory notesFactory) { Factory(
ChangeData.Factory changeDataFactory,
ChangeNotes.Factory notesFactory,
IdentifiedUser.GenericFactory identifiedUserFactory) {
this.changeDataFactory = changeDataFactory; this.changeDataFactory = changeDataFactory;
this.notesFactory = notesFactory; this.notesFactory = notesFactory;
this.identifiedUserFactory = identifiedUserFactory;
} }
ChangeControl create( ChangeControl create(
@@ -61,17 +67,22 @@ class ChangeControl {
} }
ChangeControl create(RefControl refControl, ChangeNotes notes) { ChangeControl create(RefControl refControl, ChangeNotes notes) {
return new ChangeControl(changeDataFactory, refControl, notes); return new ChangeControl(changeDataFactory, identifiedUserFactory, refControl, notes);
} }
} }
private final ChangeData.Factory changeDataFactory; private final ChangeData.Factory changeDataFactory;
private final IdentifiedUser.GenericFactory identifiedUserFactory;
private final RefControl refControl; private final RefControl refControl;
private final ChangeNotes notes; private final ChangeNotes notes;
private ChangeControl( private ChangeControl(
ChangeData.Factory changeDataFactory, RefControl refControl, ChangeNotes notes) { ChangeData.Factory changeDataFactory,
IdentifiedUser.GenericFactory identifiedUserFactory,
RefControl refControl,
ChangeNotes notes) {
this.changeDataFactory = changeDataFactory; this.changeDataFactory = changeDataFactory;
this.identifiedUserFactory = identifiedUserFactory;
this.refControl = refControl; this.refControl = refControl;
this.notes = notes; this.notes = notes;
} }
@@ -84,7 +95,8 @@ class ChangeControl {
if (getUser().equals(who)) { if (getUser().equals(who)) {
return this; return this;
} }
return new ChangeControl(changeDataFactory, refControl.forUser(who), notes); return new ChangeControl(
changeDataFactory, identifiedUserFactory, refControl.forUser(who), notes);
} }
private CurrentUser getUser() { private CurrentUser getUser() {
@@ -260,6 +272,11 @@ class ChangeControl {
return user().equals(user) ? this : forUser(user).asForChange(cd, db); return user().equals(user) ? this : forUser(user).asForChange(cd, db);
} }
@Override
public ForChange absentUser(Account.Id id) {
return user(identifiedUserFactory.create(id));
}
@Override @Override
public String resourcePath() { public String resourcePath() {
if (resourcePath == null) { if (resourcePath == null) {

View File

@@ -79,8 +79,8 @@ public class DefaultPermissionBackend extends PermissionBackend {
} }
@Override @Override
public WithUser absentUser(Account.Id user) { public WithUser absentUser(Account.Id id) {
IdentifiedUser identifiedUser = identifiedUserFactory.create(checkNotNull(user, "user")); IdentifiedUser identifiedUser = identifiedUserFactory.create(checkNotNull(id, "user"));
return new WithUserImpl(identifiedUser); return new WithUserImpl(identifiedUser);
} }

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.server.permissions; package com.google.gerrit.server.permissions;
import com.google.gerrit.extensions.api.access.GlobalOrPluginPermission; import com.google.gerrit.extensions.api.access.GlobalOrPluginPermission;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
@@ -128,6 +129,11 @@ public class FailedPermissionBackend {
return this; return this;
} }
@Override
public ForProject absentUser(Account.Id id) {
return this;
}
@Override @Override
public String resourcePath() { public String resourcePath() {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
@@ -181,6 +187,11 @@ public class FailedPermissionBackend {
return this; return this;
} }
@Override
public ForRef absentUser(Account.Id id) {
return this;
}
@Override @Override
public String resourcePath() { public String resourcePath() {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
@@ -233,6 +244,11 @@ public class FailedPermissionBackend {
return this; return this;
} }
@Override
public ForChange absentUser(Account.Id id) {
return this;
}
@Override @Override
public String resourcePath() { public String resourcePath() {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(

View File

@@ -112,7 +112,7 @@ public abstract class PermissionBackend {
* *
* <p>Usage should be very limited as this can expose a group-oracle. * <p>Usage should be very limited as this can expose a group-oracle.
*/ */
public abstract WithUser absentUser(Account.Id user); public abstract WithUser absentUser(Account.Id id);
/** /**
* Check whether this {@code PermissionBackend} respects the same global capabilities as the * Check whether this {@code PermissionBackend} respects the same global capabilities as the
@@ -305,6 +305,9 @@ public abstract class PermissionBackend {
/** Returns a new instance rescoped to same project, but different {@code user}. */ /** Returns a new instance rescoped to same project, but different {@code user}. */
public abstract ForProject user(CurrentUser user); public abstract ForProject user(CurrentUser user);
/** @see PermissionBackend#absentUser(Account.Id) */
public abstract ForProject absentUser(Account.Id id);
/** Returns an instance scoped for {@code ref} in this project. */ /** Returns an instance scoped for {@code ref} in this project. */
public abstract ForRef ref(String ref); public abstract ForRef ref(String ref);
@@ -413,6 +416,9 @@ public abstract class PermissionBackend {
/** Returns a new instance rescoped to same reference, but different {@code user}. */ /** Returns a new instance rescoped to same reference, but different {@code user}. */
public abstract ForRef user(CurrentUser user); public abstract ForRef user(CurrentUser user);
/** @see PermissionBackend#absentUser(Account.Id) */
public abstract ForRef absentUser(Account.Id id);
/** Returns an instance scoped to change. */ /** Returns an instance scoped to change. */
public abstract ForChange change(ChangeData cd); public abstract ForChange change(ChangeData cd);
@@ -471,6 +477,9 @@ public abstract class PermissionBackend {
/** Returns a new instance rescoped to same change, but different {@code user}. */ /** Returns a new instance rescoped to same change, but different {@code user}. */
public abstract ForChange user(CurrentUser user); public abstract ForChange user(CurrentUser user);
/** @see PermissionBackend#absentUser(Account.Id) */
public abstract ForChange absentUser(Account.Id id);
/** Verify scoped user can {@code perm}, throwing if denied. */ /** Verify scoped user can {@code perm}, throwing if denied. */
public abstract void check(ChangePermissionOrLabel perm) public abstract void check(ChangePermissionOrLabel perm)
throws AuthException, PermissionBackendException; throws AuthException, PermissionBackendException;

View File

@@ -20,6 +20,7 @@ import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.Permission; import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRule; import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Branch; import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
@@ -27,6 +28,7 @@ import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.GroupMembership; import com.google.gerrit.server.account.GroupMembership;
import com.google.gerrit.server.config.GitReceivePackGroups; import com.google.gerrit.server.config.GitReceivePackGroups;
import com.google.gerrit.server.config.GitUploadPackGroups; import com.google.gerrit.server.config.GitUploadPackGroups;
@@ -67,6 +69,7 @@ class ProjectControl {
private final ChangeControl.Factory changeControlFactory; private final ChangeControl.Factory changeControlFactory;
private final PermissionCollection.Factory permissionFilter; private final PermissionCollection.Factory permissionFilter;
private final DefaultRefFilter.Factory refFilterFactory; private final DefaultRefFilter.Factory refFilterFactory;
private final IdentifiedUser.GenericFactory identifiedUserFactory;
private List<SectionMatcher> allSections; private List<SectionMatcher> allSections;
private Map<String, RefControl> refControls; private Map<String, RefControl> refControls;
@@ -80,6 +83,7 @@ class ProjectControl {
ChangeControl.Factory changeControlFactory, ChangeControl.Factory changeControlFactory,
PermissionBackend permissionBackend, PermissionBackend permissionBackend,
DefaultRefFilter.Factory refFilterFactory, DefaultRefFilter.Factory refFilterFactory,
IdentifiedUser.GenericFactory identifiedUserFactory,
@Assisted CurrentUser who, @Assisted CurrentUser who,
@Assisted ProjectState ps) { @Assisted ProjectState ps) {
this.changeControlFactory = changeControlFactory; this.changeControlFactory = changeControlFactory;
@@ -88,6 +92,7 @@ class ProjectControl {
this.permissionFilter = permissionFilter; this.permissionFilter = permissionFilter;
this.permissionBackend = permissionBackend; this.permissionBackend = permissionBackend;
this.refFilterFactory = refFilterFactory; this.refFilterFactory = refFilterFactory;
this.identifiedUserFactory = identifiedUserFactory;
user = who; user = who;
state = ps; state = ps;
} }
@@ -101,6 +106,7 @@ class ProjectControl {
changeControlFactory, changeControlFactory,
permissionBackend, permissionBackend,
refFilterFactory, refFilterFactory,
identifiedUserFactory,
who, who,
state); state);
// Not per-user, and reusing saves lookup time. // Not per-user, and reusing saves lookup time.
@@ -132,7 +138,7 @@ class ProjectControl {
RefControl ctl = refControls.get(refName); RefControl ctl = refControls.get(refName);
if (ctl == null) { if (ctl == null) {
PermissionCollection relevant = permissionFilter.filter(access(), refName, user); PermissionCollection relevant = permissionFilter.filter(access(), refName, user);
ctl = new RefControl(this, refName, relevant); ctl = new RefControl(identifiedUserFactory, this, refName, relevant);
refControls.put(refName, ctl); refControls.put(refName, ctl);
} }
return ctl; return ctl;
@@ -326,6 +332,11 @@ class ProjectControl {
return forUser(user).asForProject().database(db); return forUser(user).asForProject().database(db);
} }
@Override
public ForProject absentUser(Account.Id id) {
return user(identifiedUserFactory.create(id));
}
@Override @Override
public String resourcePath() { public String resourcePath() {
if (resourcePath == null) { if (resourcePath == null) {

View File

@@ -21,10 +21,12 @@ import com.google.gerrit.common.data.PermissionRange;
import com.google.gerrit.common.data.PermissionRule; import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.common.data.PermissionRule.Action; import com.google.gerrit.common.data.PermissionRule.Action;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.notedb.ChangeNotes; import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.permissions.PermissionBackend.ForChange; import com.google.gerrit.server.permissions.PermissionBackend.ForChange;
import com.google.gerrit.server.permissions.PermissionBackend.ForRef; import com.google.gerrit.server.permissions.PermissionBackend.ForRef;
@@ -39,6 +41,7 @@ import java.util.Set;
/** Manages access control for Git references (aka branches, tags). */ /** Manages access control for Git references (aka branches, tags). */
class RefControl { class RefControl {
private final IdentifiedUser.GenericFactory identifiedUserFactory;
private final ProjectControl projectControl; private final ProjectControl projectControl;
private final String refName; private final String refName;
@@ -52,7 +55,12 @@ class RefControl {
private Boolean canForgeCommitter; private Boolean canForgeCommitter;
private Boolean isVisible; private Boolean isVisible;
RefControl(ProjectControl projectControl, String ref, PermissionCollection relevant) { RefControl(
IdentifiedUser.GenericFactory identifiedUserFactory,
ProjectControl projectControl,
String ref,
PermissionCollection relevant) {
this.identifiedUserFactory = identifiedUserFactory;
this.projectControl = projectControl; this.projectControl = projectControl;
this.refName = ref; this.refName = ref;
this.relevant = relevant; this.relevant = relevant;
@@ -71,7 +79,7 @@ class RefControl {
if (relevant.isUserSpecific()) { if (relevant.isUserSpecific()) {
return newCtl.controlForRef(refName); return newCtl.controlForRef(refName);
} }
return new RefControl(newCtl, refName, relevant); return new RefControl(identifiedUserFactory, newCtl, refName, relevant);
} }
/** Is this user a ref owner? */ /** Is this user a ref owner? */
@@ -403,6 +411,11 @@ class RefControl {
return forUser(user).asForRef().database(db); return forUser(user).asForRef().database(db);
} }
@Override
public ForRef absentUser(Account.Id id) {
return user(identifiedUserFactory.create(id));
}
@Override @Override
public String resourcePath() { public String resourcePath() {
if (resourcePath == null) { if (resourcePath == null) {

View File

@@ -87,7 +87,7 @@ public class ListCapabilitiesTest {
} }
@Override @Override
public WithUser absentUser(Id user) { public WithUser absentUser(Id id) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@@ -77,6 +77,11 @@ public class UiActionsTest {
throw new UnsupportedOperationException("not implemented"); throw new UnsupportedOperationException("not implemented");
} }
@Override
public ForProject absentUser(Account.Id id) {
throw new UnsupportedOperationException("not implemented");
}
@Override @Override
public ForRef ref(String ref) { public ForRef ref(String ref) {
throw new UnsupportedOperationException("not implemented"); throw new UnsupportedOperationException("not implemented");

View File

@@ -47,6 +47,7 @@ import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.CapabilityCollection; import com.google.gerrit.server.account.CapabilityCollection;
import com.google.gerrit.server.account.GroupMembership; import com.google.gerrit.server.account.GroupMembership;
import com.google.gerrit.server.account.ListGroupMembership; import com.google.gerrit.server.account.ListGroupMembership;
@@ -202,6 +203,7 @@ public class RefControlTest {
@Inject private InMemoryDatabase schemaFactory; @Inject private InMemoryDatabase schemaFactory;
@Inject private ThreadLocalRequestContext requestContext; @Inject private ThreadLocalRequestContext requestContext;
@Inject private DefaultRefFilter.Factory refFilterFactory; @Inject private DefaultRefFilter.Factory refFilterFactory;
@Inject private IdentifiedUser.GenericFactory identifiedUserFactory;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@@ -986,6 +988,7 @@ public class RefControlTest {
changeControlFactory, changeControlFactory,
permissionBackend, permissionBackend,
refFilterFactory, refFilterFactory,
identifiedUserFactory,
new MockUser(name, memberOf), new MockUser(name, memberOf),
newProjectState(local)); newProjectState(local));
} }