Merge changes Ib3f0849f,I9d12ed46,I38520cff
* changes: Factor out Contributor Agreements from ProjectControl Add ProjectPermissions for upload and receive pack, migrate callers Add ProjectPermission.READ_NO_CONFIG
This commit is contained in:
commit
b7d274f03c
@ -19,6 +19,7 @@ import com.google.common.collect.Lists;
|
||||
import com.google.gerrit.acceptance.InProcessProtocol.Context;
|
||||
import com.google.gerrit.common.data.Capable;
|
||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
@ -34,8 +35,13 @@ import com.google.gerrit.server.git.TransferConfig;
|
||||
import com.google.gerrit.server.git.VisibleRefFilter;
|
||||
import com.google.gerrit.server.git.receive.AsyncReceiveCommits;
|
||||
import com.google.gerrit.server.git.validators.UploadValidators;
|
||||
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.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.util.RequestContext;
|
||||
import com.google.gerrit.server.util.RequestScopePropagator;
|
||||
import com.google.gerrit.server.util.ThreadLocalRequestContext;
|
||||
@ -203,29 +209,32 @@ class InProcessProtocol extends TestProtocol<Context> {
|
||||
|
||||
private static class Upload implements UploadPackFactory<Context> {
|
||||
private final Provider<CurrentUser> userProvider;
|
||||
private final ProjectControl.GenericFactory projectControlFactory;
|
||||
private final VisibleRefFilter.Factory refFilterFactory;
|
||||
private final TransferConfig transferConfig;
|
||||
private final DynamicSet<PreUploadHook> preUploadHooks;
|
||||
private final UploadValidators.Factory uploadValidatorsFactory;
|
||||
private final ThreadLocalRequestContext threadContext;
|
||||
private final ProjectCache projectCache;
|
||||
private final PermissionBackend permissionBackend;
|
||||
|
||||
@Inject
|
||||
Upload(
|
||||
Provider<CurrentUser> userProvider,
|
||||
ProjectControl.GenericFactory projectControlFactory,
|
||||
VisibleRefFilter.Factory refFilterFactory,
|
||||
TransferConfig transferConfig,
|
||||
DynamicSet<PreUploadHook> preUploadHooks,
|
||||
UploadValidators.Factory uploadValidatorsFactory,
|
||||
ThreadLocalRequestContext threadContext) {
|
||||
ThreadLocalRequestContext threadContext,
|
||||
ProjectCache projectCache,
|
||||
PermissionBackend permissionBackend) {
|
||||
this.userProvider = userProvider;
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.refFilterFactory = refFilterFactory;
|
||||
this.transferConfig = transferConfig;
|
||||
this.preUploadHooks = preUploadHooks;
|
||||
this.uploadValidatorsFactory = uploadValidatorsFactory;
|
||||
this.threadContext = threadContext;
|
||||
this.projectCache = projectCache;
|
||||
this.permissionBackend = permissionBackend;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -236,23 +245,35 @@ class InProcessProtocol extends TestProtocol<Context> {
|
||||
// its original context anyway.
|
||||
threadContext.setContext(req);
|
||||
current.set(req);
|
||||
try {
|
||||
ProjectControl ctl = projectControlFactory.controlFor(req.project, userProvider.get());
|
||||
if (!ctl.canRunUploadPack()) {
|
||||
throw new ServiceNotAuthorizedException();
|
||||
}
|
||||
|
||||
UploadPack up = new UploadPack(repo);
|
||||
up.setPackConfig(transferConfig.getPackConfig());
|
||||
up.setTimeout(transferConfig.getTimeout());
|
||||
up.setAdvertiseRefsHook(refFilterFactory.create(ctl.getProjectState(), repo));
|
||||
List<PreUploadHook> hooks = Lists.newArrayList(preUploadHooks);
|
||||
hooks.add(uploadValidatorsFactory.create(ctl.getProject(), repo, "localhost-test"));
|
||||
up.setPreUploadHook(PreUploadHookChain.newChain(hooks));
|
||||
return up;
|
||||
} catch (NoSuchProjectException | IOException e) {
|
||||
try {
|
||||
permissionBackend
|
||||
.user(userProvider)
|
||||
.project(req.project)
|
||||
.check(ProjectPermission.RUN_UPLOAD_PACK);
|
||||
} catch (AuthException e) {
|
||||
throw new ServiceNotAuthorizedException();
|
||||
} catch (PermissionBackendException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
ProjectState projectState;
|
||||
try {
|
||||
projectState = projectCache.checkedGet(req.project);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (projectState == null) {
|
||||
throw new RuntimeException("can't load project state for " + req.project.get());
|
||||
}
|
||||
UploadPack up = new UploadPack(repo);
|
||||
up.setPackConfig(transferConfig.getPackConfig());
|
||||
up.setTimeout(transferConfig.getTimeout());
|
||||
up.setAdvertiseRefsHook(refFilterFactory.create(projectState, repo));
|
||||
List<PreUploadHook> hooks = Lists.newArrayList(preUploadHooks);
|
||||
hooks.add(uploadValidatorsFactory.create(projectState.getProject(), repo, "localhost-test"));
|
||||
up.setPreUploadHook(PreUploadHookChain.newChain(hooks));
|
||||
return up;
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,6 +285,7 @@ class InProcessProtocol extends TestProtocol<Context> {
|
||||
private final DynamicSet<ReceivePackInitializer> receivePackInitializers;
|
||||
private final DynamicSet<PostReceiveHook> postReceiveHooks;
|
||||
private final ThreadLocalRequestContext threadContext;
|
||||
private final PermissionBackend permissionBackend;
|
||||
|
||||
@Inject
|
||||
Receive(
|
||||
@ -273,7 +295,8 @@ class InProcessProtocol extends TestProtocol<Context> {
|
||||
TransferConfig config,
|
||||
DynamicSet<ReceivePackInitializer> receivePackInitializers,
|
||||
DynamicSet<PostReceiveHook> postReceiveHooks,
|
||||
ThreadLocalRequestContext threadContext) {
|
||||
ThreadLocalRequestContext threadContext,
|
||||
PermissionBackend permissionBackend) {
|
||||
this.userProvider = userProvider;
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.factory = factory;
|
||||
@ -281,6 +304,7 @@ class InProcessProtocol extends TestProtocol<Context> {
|
||||
this.receivePackInitializers = receivePackInitializers;
|
||||
this.postReceiveHooks = postReceiveHooks;
|
||||
this.threadContext = threadContext;
|
||||
this.permissionBackend = permissionBackend;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -291,12 +315,18 @@ class InProcessProtocol extends TestProtocol<Context> {
|
||||
// its original context anyway.
|
||||
threadContext.setContext(req);
|
||||
current.set(req);
|
||||
try {
|
||||
permissionBackend
|
||||
.user(userProvider)
|
||||
.project(req.project)
|
||||
.check(ProjectPermission.RUN_RECEIVE_PACK);
|
||||
} catch (AuthException e) {
|
||||
throw new ServiceNotAuthorizedException();
|
||||
} catch (PermissionBackendException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
try {
|
||||
ProjectControl ctl = projectControlFactory.controlFor(req.project, userProvider.get());
|
||||
if (!ctl.canRunReceivePack()) {
|
||||
throw new ServiceNotAuthorizedException();
|
||||
}
|
||||
|
||||
AsyncReceiveCommits arc = factory.create(ctl, db, null, ImmutableSetMultimap.of());
|
||||
ReceivePack rp = arc.getReceivePack();
|
||||
|
||||
|
@ -234,13 +234,16 @@ public class GitOverHttpServlet extends GitServlet {
|
||||
static class UploadFilter implements Filter {
|
||||
private final VisibleRefFilter.Factory refFilterFactory;
|
||||
private final UploadValidators.Factory uploadValidatorsFactory;
|
||||
private final PermissionBackend permissionBackend;
|
||||
|
||||
@Inject
|
||||
UploadFilter(
|
||||
VisibleRefFilter.Factory refFilterFactory,
|
||||
UploadValidators.Factory uploadValidatorsFactory) {
|
||||
UploadValidators.Factory uploadValidatorsFactory,
|
||||
PermissionBackend permissionBackend) {
|
||||
this.refFilterFactory = refFilterFactory;
|
||||
this.uploadValidatorsFactory = uploadValidatorsFactory;
|
||||
this.permissionBackend = permissionBackend;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -251,13 +254,20 @@ public class GitOverHttpServlet extends GitServlet {
|
||||
ProjectControl pc = (ProjectControl) request.getAttribute(ATT_CONTROL);
|
||||
UploadPack up = (UploadPack) request.getAttribute(ServletUtils.ATTRIBUTE_HANDLER);
|
||||
|
||||
if (!pc.canRunUploadPack()) {
|
||||
try {
|
||||
permissionBackend
|
||||
.user(pc.getUser())
|
||||
.project(pc.getProject().getNameKey())
|
||||
.check(ProjectPermission.RUN_UPLOAD_PACK);
|
||||
} catch (AuthException e) {
|
||||
GitSmartHttpTools.sendError(
|
||||
(HttpServletRequest) request,
|
||||
(HttpServletResponse) response,
|
||||
HttpServletResponse.SC_FORBIDDEN,
|
||||
"upload-pack not permitted on this server");
|
||||
return;
|
||||
} catch (PermissionBackendException e) {
|
||||
throw new ServletException(e);
|
||||
}
|
||||
// We use getRemoteHost() here instead of getRemoteAddr() because REMOTE_ADDR
|
||||
// may have been overridden by a proxy server -- we'll try to avoid this.
|
||||
@ -312,10 +322,14 @@ public class GitOverHttpServlet extends GitServlet {
|
||||
|
||||
static class ReceiveFilter implements Filter {
|
||||
private final Cache<AdvertisedObjectsCacheKey, Set<ObjectId>> cache;
|
||||
private final PermissionBackend permissionBackend;
|
||||
|
||||
@Inject
|
||||
ReceiveFilter(@Named(ID_CACHE) Cache<AdvertisedObjectsCacheKey, Set<ObjectId>> cache) {
|
||||
ReceiveFilter(
|
||||
@Named(ID_CACHE) Cache<AdvertisedObjectsCacheKey, Set<ObjectId>> cache,
|
||||
PermissionBackend permissionBackend) {
|
||||
this.cache = cache;
|
||||
this.permissionBackend = permissionBackend;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -329,13 +343,20 @@ public class GitOverHttpServlet extends GitServlet {
|
||||
ProjectControl pc = (ProjectControl) request.getAttribute(ATT_CONTROL);
|
||||
Project.NameKey projectName = pc.getProject().getNameKey();
|
||||
|
||||
if (!pc.canRunReceivePack()) {
|
||||
try {
|
||||
permissionBackend
|
||||
.user(pc.getUser())
|
||||
.project(pc.getProject().getNameKey())
|
||||
.check(ProjectPermission.RUN_RECEIVE_PACK);
|
||||
} catch (AuthException e) {
|
||||
GitSmartHttpTools.sendError(
|
||||
(HttpServletRequest) request,
|
||||
(HttpServletResponse) response,
|
||||
HttpServletResponse.SC_FORBIDDEN,
|
||||
"receive-pack not permitted on this server");
|
||||
return;
|
||||
} catch (PermissionBackendException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Capable s = arc.canUpload();
|
||||
|
@ -25,6 +25,7 @@ import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.ContributorAgreementsChecker;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
@ -62,6 +63,7 @@ class ChangeProjectAccess extends ProjectAccessHandler<ProjectAccess> {
|
||||
AllProjectsName allProjects,
|
||||
Provider<SetParent> setParent,
|
||||
GitReferenceUpdated gitRefUpdated,
|
||||
ContributorAgreementsChecker contributorAgreements,
|
||||
@Assisted("projectName") Project.NameKey projectName,
|
||||
@Nullable @Assisted ObjectId base,
|
||||
@Assisted List<AccessSection> sectionList,
|
||||
@ -78,6 +80,7 @@ class ChangeProjectAccess extends ProjectAccessHandler<ProjectAccess> {
|
||||
sectionList,
|
||||
parentProjectName,
|
||||
message,
|
||||
contributorAgreements,
|
||||
true);
|
||||
this.projectAccessFactory = projectAccessFactory;
|
||||
this.projectCache = projectCache;
|
||||
|
@ -18,7 +18,6 @@ import static com.google.gerrit.common.ProjectAccessUtil.mergeSections;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.Capable;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
@ -37,6 +36,7 @@ import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.ContributorAgreementsChecker;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
import com.google.gerrit.server.project.RefPattern;
|
||||
@ -58,6 +58,7 @@ public abstract class ProjectAccessHandler<T> extends Handler<T> {
|
||||
private final MetaDataUpdate.User metaDataUpdateFactory;
|
||||
private final AllProjectsName allProjects;
|
||||
private final Provider<SetParent> setParent;
|
||||
private final ContributorAgreementsChecker contributorAgreements;
|
||||
|
||||
protected final Project.NameKey projectName;
|
||||
protected final ObjectId base;
|
||||
@ -77,6 +78,7 @@ public abstract class ProjectAccessHandler<T> extends Handler<T> {
|
||||
List<AccessSection> sectionList,
|
||||
Project.NameKey parentProjectName,
|
||||
String message,
|
||||
ContributorAgreementsChecker contributorAgreements,
|
||||
boolean checkIfOwner) {
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.groupBackend = groupBackend;
|
||||
@ -89,6 +91,7 @@ public abstract class ProjectAccessHandler<T> extends Handler<T> {
|
||||
this.sectionList = sectionList;
|
||||
this.parentProjectName = parentProjectName;
|
||||
this.message = message;
|
||||
this.contributorAgreements = contributorAgreements;
|
||||
this.checkIfOwner = checkIfOwner;
|
||||
}
|
||||
|
||||
@ -99,9 +102,10 @@ public abstract class ProjectAccessHandler<T> extends Handler<T> {
|
||||
PermissionDeniedException, PermissionBackendException {
|
||||
final ProjectControl projectControl = projectControlFactory.controlFor(projectName);
|
||||
|
||||
Capable r = projectControl.canPushToAtLeastOneRef();
|
||||
if (r != Capable.OK) {
|
||||
throw new PermissionDeniedException(r.getMessage());
|
||||
try {
|
||||
contributorAgreements.check(projectName, projectControl.getUser());
|
||||
} catch (AuthException e) {
|
||||
throw new PermissionDeniedException(e.getMessage());
|
||||
}
|
||||
|
||||
try (MetaDataUpdate md = metaDataUpdateFactory.create(projectName)) {
|
||||
|
@ -43,6 +43,7 @@ import com.google.gerrit.server.group.SystemGroupBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.permissions.RefPermission;
|
||||
import com.google.gerrit.server.project.ContributorAgreementsChecker;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
import com.google.gerrit.server.project.SetParent;
|
||||
@ -94,6 +95,7 @@ public class ReviewProjectAccess extends ProjectAccessHandler<Change.Id> {
|
||||
BatchUpdate.Factory updateFactory,
|
||||
Provider<SetParent> setParent,
|
||||
Sequences seq,
|
||||
ContributorAgreementsChecker contributorAgreements,
|
||||
@Assisted("projectName") Project.NameKey projectName,
|
||||
@Nullable @Assisted ObjectId base,
|
||||
@Assisted List<AccessSection> sectionList,
|
||||
@ -110,6 +112,7 @@ public class ReviewProjectAccess extends ProjectAccessHandler<Change.Id> {
|
||||
sectionList,
|
||||
parentProjectName,
|
||||
message,
|
||||
contributorAgreements,
|
||||
false);
|
||||
this.db = db;
|
||||
this.permissionBackend = permissionBackend;
|
||||
|
@ -31,10 +31,10 @@ 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.ContributorAgreementsChecker;
|
||||
import com.google.gerrit.server.project.InvalidChangeOperationException;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
import com.google.gerrit.server.update.BatchUpdate;
|
||||
import com.google.gerrit.server.update.RetryHelper;
|
||||
import com.google.gerrit.server.update.RetryingRestModifyView;
|
||||
@ -54,7 +54,7 @@ public class CherryPick
|
||||
private final Provider<CurrentUser> user;
|
||||
private final CherryPickChange cherryPickChange;
|
||||
private final ChangeJson.Factory json;
|
||||
private final ProjectControl.GenericFactory projectControlFactory;
|
||||
private final ContributorAgreementsChecker contributorAgreements;
|
||||
|
||||
@Inject
|
||||
CherryPick(
|
||||
@ -63,13 +63,13 @@ public class CherryPick
|
||||
RetryHelper retryHelper,
|
||||
CherryPickChange cherryPickChange,
|
||||
ChangeJson.Factory json,
|
||||
ProjectControl.GenericFactory projectControlFactory) {
|
||||
ContributorAgreementsChecker contributorAgreements) {
|
||||
super(retryHelper);
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.user = user;
|
||||
this.cherryPickChange = cherryPickChange;
|
||||
this.json = json;
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.contributorAgreements = contributorAgreements;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -85,7 +85,8 @@ public class CherryPick
|
||||
}
|
||||
|
||||
String refName = RefNames.fullName(input.destination);
|
||||
CreateChange.checkValidCLA(projectControlFactory.controlFor(rsrc.getProject(), rsrc.getUser()));
|
||||
contributorAgreements.check(rsrc.getProject(), rsrc.getUser());
|
||||
|
||||
permissionBackend
|
||||
.user(user)
|
||||
.project(rsrc.getChange().getProject())
|
||||
|
@ -30,6 +30,7 @@ import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.permissions.RefPermission;
|
||||
import com.google.gerrit.server.project.CommitResource;
|
||||
import com.google.gerrit.server.project.ContributorAgreementsChecker;
|
||||
import com.google.gerrit.server.project.InvalidChangeOperationException;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.update.BatchUpdate;
|
||||
@ -51,6 +52,7 @@ public class CherryPickCommit
|
||||
private final Provider<CurrentUser> user;
|
||||
private final CherryPickChange cherryPickChange;
|
||||
private final ChangeJson.Factory json;
|
||||
private final ContributorAgreementsChecker contributorAgreements;
|
||||
|
||||
@Inject
|
||||
CherryPickCommit(
|
||||
@ -58,12 +60,14 @@ public class CherryPickCommit
|
||||
Provider<CurrentUser> user,
|
||||
CherryPickChange cherryPickChange,
|
||||
ChangeJson.Factory json,
|
||||
PermissionBackend permissionBackend) {
|
||||
PermissionBackend permissionBackend,
|
||||
ContributorAgreementsChecker contributorAgreements) {
|
||||
super(retryHelper);
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.user = user;
|
||||
this.cherryPickChange = cherryPickChange;
|
||||
this.json = json;
|
||||
this.contributorAgreements = contributorAgreements;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -83,7 +87,7 @@ public class CherryPickCommit
|
||||
}
|
||||
|
||||
String refName = RefNames.fullName(destination);
|
||||
CreateChange.checkValidCLA(rsrc.getProjectState().controlFor(user.get()));
|
||||
contributorAgreements.check(projectName, user.get());
|
||||
permissionBackend
|
||||
.user(user)
|
||||
.project(projectName)
|
||||
|
@ -20,14 +20,12 @@ import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.gerrit.common.TimeUtil;
|
||||
import com.google.gerrit.common.data.Capable;
|
||||
import com.google.gerrit.extensions.client.ChangeStatus;
|
||||
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
|
||||
import com.google.gerrit.extensions.client.SubmitType;
|
||||
import com.google.gerrit.extensions.common.ChangeInfo;
|
||||
import com.google.gerrit.extensions.common.ChangeInput;
|
||||
import com.google.gerrit.extensions.common.MergeInput;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.extensions.restapi.Response;
|
||||
@ -57,8 +55,8 @@ import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.permissions.RefPermission;
|
||||
import com.google.gerrit.server.project.CommitsCollection;
|
||||
import com.google.gerrit.server.project.ContributorAgreementsChecker;
|
||||
import com.google.gerrit.server.project.InvalidChangeOperationException;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
import com.google.gerrit.server.project.ProjectResource;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.project.ProjectsCollection;
|
||||
@ -110,6 +108,7 @@ public class CreateChange
|
||||
private final MergeUtil.Factory mergeUtilFactory;
|
||||
private final SubmitType submitType;
|
||||
private final NotifyUtil notifyUtil;
|
||||
private final ContributorAgreementsChecker contributorAgreements;
|
||||
|
||||
@Inject
|
||||
CreateChange(
|
||||
@ -130,7 +129,8 @@ public class CreateChange
|
||||
PatchSetUtil psUtil,
|
||||
@GerritServerConfig Config config,
|
||||
MergeUtil.Factory mergeUtilFactory,
|
||||
NotifyUtil notifyUtil) {
|
||||
NotifyUtil notifyUtil,
|
||||
ContributorAgreementsChecker contributorAgreements) {
|
||||
super(retryHelper);
|
||||
this.anonymousCowardName = anonymousCowardName;
|
||||
this.db = db;
|
||||
@ -149,6 +149,7 @@ public class CreateChange
|
||||
this.submitType = config.getEnum("project", null, "submitType", SubmitType.MERGE_IF_NECESSARY);
|
||||
this.mergeUtilFactory = mergeUtilFactory;
|
||||
this.notifyUtil = notifyUtil;
|
||||
this.contributorAgreements = contributorAgreements;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -175,7 +176,7 @@ public class CreateChange
|
||||
}
|
||||
|
||||
ProjectResource rsrc = projectsCollection.parse(input.project);
|
||||
checkValidCLA(rsrc.getControl());
|
||||
contributorAgreements.check(rsrc.getNameKey(), rsrc.getUser());
|
||||
|
||||
Project.NameKey project = rsrc.getNameKey();
|
||||
String refName = RefNames.fullName(input.branch);
|
||||
@ -341,11 +342,4 @@ public class CreateChange
|
||||
private static ObjectId emptyTreeId(ObjectInserter inserter) throws IOException {
|
||||
return inserter.insert(new TreeFormatter());
|
||||
}
|
||||
|
||||
static void checkValidCLA(ProjectControl ctl) throws AuthException {
|
||||
Capable capable = ctl.canPushToAtLeastOneRef();
|
||||
if (capable != Capable.OK) {
|
||||
throw new AuthException(capable.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,8 @@ import com.google.gerrit.extensions.restapi.RestApiException;
|
||||
import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.gerrit.server.edit.ChangeEdit;
|
||||
import com.google.gerrit.server.edit.ChangeEditUtil;
|
||||
import com.google.gerrit.server.project.ContributorAgreementsChecker;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
import com.google.gerrit.server.update.BatchUpdate;
|
||||
import com.google.gerrit.server.update.RetryHelper;
|
||||
import com.google.gerrit.server.update.RetryingRestModifyView;
|
||||
@ -76,18 +76,18 @@ public class PublishChangeEdit
|
||||
|
||||
private final ChangeEditUtil editUtil;
|
||||
private final NotifyUtil notifyUtil;
|
||||
private final ProjectControl.GenericFactory projectControlFactory;
|
||||
private final ContributorAgreementsChecker contributorAgreementsChecker;
|
||||
|
||||
@Inject
|
||||
Publish(
|
||||
RetryHelper retryHelper,
|
||||
ChangeEditUtil editUtil,
|
||||
NotifyUtil notifyUtil,
|
||||
ProjectControl.GenericFactory projectControlFactory) {
|
||||
ContributorAgreementsChecker contributorAgreementsChecker) {
|
||||
super(retryHelper);
|
||||
this.editUtil = editUtil;
|
||||
this.notifyUtil = notifyUtil;
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.contributorAgreementsChecker = contributorAgreementsChecker;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -95,8 +95,7 @@ public class PublishChangeEdit
|
||||
BatchUpdate.Factory updateFactory, ChangeResource rsrc, PublishChangeEditInput in)
|
||||
throws IOException, OrmException, RestApiException, UpdateException, ConfigInvalidException,
|
||||
NoSuchProjectException {
|
||||
CreateChange.checkValidCLA(
|
||||
projectControlFactory.controlFor(rsrc.getProject(), rsrc.getUser()));
|
||||
contributorAgreementsChecker.check(rsrc.getProject(), rsrc.getUser());
|
||||
Optional<ChangeEdit> edit = editUtil.byChange(rsrc.getNotes(), rsrc.getUser());
|
||||
if (!edit.isPresent()) {
|
||||
throw new ResourceConflictException(
|
||||
|
@ -46,9 +46,9 @@ import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.notedb.ReviewerStateInternal;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.ContributorAgreementsChecker;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
import com.google.gerrit.server.update.BatchUpdate;
|
||||
import com.google.gerrit.server.update.BatchUpdateOp;
|
||||
import com.google.gerrit.server.update.ChangeContext;
|
||||
@ -95,7 +95,7 @@ public class Revert extends RetryingRestModifyView<ChangeResource, RevertInput,
|
||||
private final PersonIdent serverIdent;
|
||||
private final ApprovalsUtil approvalsUtil;
|
||||
private final ChangeReverted changeReverted;
|
||||
private final ProjectControl.GenericFactory projectControlFactory;
|
||||
private final ContributorAgreementsChecker contributorAgreements;
|
||||
|
||||
@Inject
|
||||
Revert(
|
||||
@ -112,7 +112,7 @@ public class Revert extends RetryingRestModifyView<ChangeResource, RevertInput,
|
||||
@GerritPersonIdent PersonIdent serverIdent,
|
||||
ApprovalsUtil approvalsUtil,
|
||||
ChangeReverted changeReverted,
|
||||
ProjectControl.GenericFactory projectControlFactory) {
|
||||
ContributorAgreementsChecker contributorAgreements) {
|
||||
super(retryHelper);
|
||||
this.db = db;
|
||||
this.permissionBackend = permissionBackend;
|
||||
@ -126,7 +126,7 @@ public class Revert extends RetryingRestModifyView<ChangeResource, RevertInput,
|
||||
this.serverIdent = serverIdent;
|
||||
this.approvalsUtil = approvalsUtil;
|
||||
this.changeReverted = changeReverted;
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.contributorAgreements = contributorAgreements;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -139,7 +139,7 @@ public class Revert extends RetryingRestModifyView<ChangeResource, RevertInput,
|
||||
throw new ResourceConflictException("change is " + ChangeUtil.status(change));
|
||||
}
|
||||
|
||||
CreateChange.checkValidCLA(projectControlFactory.controlFor(rsrc.getProject(), rsrc.getUser()));
|
||||
contributorAgreements.check(rsrc.getProject(), rsrc.getUser());
|
||||
permissionBackend.user(rsrc.getUser()).ref(change.getDest()).check(CREATE_CHANGE);
|
||||
|
||||
Change.Id revertId =
|
||||
|
@ -20,7 +20,6 @@ import static com.google.gerrit.reviewdb.client.RefNames.REFS_CONFIG;
|
||||
import static com.google.gerrit.reviewdb.client.RefNames.REFS_USERS_SELF;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
@ -37,6 +36,7 @@ import com.google.gerrit.server.permissions.ChangePermission;
|
||||
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.ProjectControl;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
@ -118,15 +118,18 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
|
||||
refs = addUsersSelfSymref(refs);
|
||||
}
|
||||
|
||||
projectCtl = projectState.controlFor(user.get());
|
||||
if (projectCtl.allRefsAreVisible(ImmutableSet.of(REFS_CONFIG))) {
|
||||
PermissionBackend.WithUser withUser = permissionBackend.user(user);
|
||||
PermissionBackend.ForProject forProject = withUser.project(projectState.getNameKey());
|
||||
if (checkProjectPermission(forProject, ProjectPermission.READ)) {
|
||||
return refs;
|
||||
} else if (checkProjectPermission(forProject, ProjectPermission.READ_NO_CONFIG)) {
|
||||
return fastHideRefsMetaConfig(refs);
|
||||
}
|
||||
|
||||
Account.Id userId;
|
||||
boolean viewMetadata;
|
||||
if (user.get().isIdentifiedUser()) {
|
||||
viewMetadata = permissionBackend.user(user).testOrFalse(GlobalPermission.ACCESS_DATABASE);
|
||||
viewMetadata = withUser.testOrFalse(GlobalPermission.ACCESS_DATABASE);
|
||||
IdentifiedUser u = user.get().asIdentifiedUser();
|
||||
userId = u.getAccountId();
|
||||
userEditPrefix = RefNames.refsEditPrefix(userId);
|
||||
@ -138,6 +141,7 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
|
||||
Map<String, Ref> result = new HashMap<>();
|
||||
List<Ref> deferredTags = new ArrayList<>();
|
||||
|
||||
projectCtl = projectState.controlFor(user.get());
|
||||
for (Ref ref : refs.values()) {
|
||||
String name = ref.getName();
|
||||
Change.Id changeId;
|
||||
@ -336,4 +340,21 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkProjectPermission(
|
||||
PermissionBackend.ForProject forProject, ProjectPermission perm) {
|
||||
try {
|
||||
forProject.check(perm);
|
||||
} catch (AuthException e) {
|
||||
return false;
|
||||
} catch (PermissionBackendException e) {
|
||||
log.error(
|
||||
String.format(
|
||||
"Can't check permission for user %s on project %s",
|
||||
user.get(), projectState.getName()),
|
||||
e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import com.google.gerrit.server.notedb.ReviewerStateInternal;
|
||||
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.project.ContributorAgreementsChecker;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.query.change.InternalChangeQuery;
|
||||
@ -45,6 +46,7 @@ import com.google.inject.Singleton;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
||||
import com.google.inject.name.Named;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@ -167,6 +169,7 @@ public class AsyncReceiveCommits implements PreReceiveHook {
|
||||
private final ExecutorService executor;
|
||||
private final RequestScopePropagator scopePropagator;
|
||||
private final ReceiveConfig receiveConfig;
|
||||
private final ContributorAgreementsChecker contributorAgreements;
|
||||
private final long timeoutMillis;
|
||||
private final ProjectControl projectControl;
|
||||
private final Repository repo;
|
||||
@ -185,6 +188,7 @@ public class AsyncReceiveCommits implements PreReceiveHook {
|
||||
ReceiveConfig receiveConfig,
|
||||
TransferConfig transferConfig,
|
||||
Provider<LazyPostReceiveHookChain> lazyPostReceive,
|
||||
ContributorAgreementsChecker contributorAgreements,
|
||||
@Named(TIMEOUT_NAME) long timeoutMillis,
|
||||
@Assisted ProjectControl projectControl,
|
||||
@Assisted Repository repo,
|
||||
@ -195,6 +199,7 @@ public class AsyncReceiveCommits implements PreReceiveHook {
|
||||
this.executor = executor;
|
||||
this.scopePropagator = scopePropagator;
|
||||
this.receiveConfig = receiveConfig;
|
||||
this.contributorAgreements = contributorAgreements;
|
||||
this.timeoutMillis = timeoutMillis;
|
||||
this.projectControl = projectControl;
|
||||
this.repo = repo;
|
||||
@ -235,15 +240,23 @@ public class AsyncReceiveCommits implements PreReceiveHook {
|
||||
}
|
||||
|
||||
/** Determine if the user can upload commits. */
|
||||
public Capable canUpload() {
|
||||
public Capable canUpload() throws IOException {
|
||||
Capable result = projectControl.canPushToAtLeastOneRef();
|
||||
if (result != Capable.OK) {
|
||||
return result;
|
||||
}
|
||||
if (receiveConfig.checkMagicRefs) {
|
||||
result = MagicBranch.checkMagicBranchRefs(repo, projectControl.getProject());
|
||||
|
||||
try {
|
||||
contributorAgreements.check(
|
||||
projectControl.getProject().getNameKey(), projectControl.getUser());
|
||||
} catch (AuthException e) {
|
||||
return new Capable(e.getMessage());
|
||||
}
|
||||
return result;
|
||||
|
||||
if (receiveConfig.checkMagicRefs) {
|
||||
return MagicBranch.checkMagicBranchRefs(repo, projectControl.getProject());
|
||||
}
|
||||
return Capable.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -34,6 +34,14 @@ public enum ProjectPermission {
|
||||
*/
|
||||
READ(Permission.READ),
|
||||
|
||||
/**
|
||||
* Can read all non-config references in the repository.
|
||||
*
|
||||
* <p>This is the same as {@code READ} but does not check if they user can see refs/meta/config.
|
||||
* Therefore, callers should check {@code READ} before excluding config refs in a short-circuit.
|
||||
*/
|
||||
READ_NO_CONFIG,
|
||||
|
||||
/**
|
||||
* Can create at least one reference in the project.
|
||||
*
|
||||
@ -62,7 +70,13 @@ public enum ProjectPermission {
|
||||
* .check(RefPermission.CREATE_CHANGE);
|
||||
* </pre>
|
||||
*/
|
||||
CREATE_CHANGE;
|
||||
CREATE_CHANGE,
|
||||
|
||||
/** Can run receive pack. */
|
||||
RUN_RECEIVE_PACK,
|
||||
|
||||
/** Can run upload pack. */
|
||||
RUN_UPLOAD_PACK;
|
||||
|
||||
private final String name;
|
||||
|
||||
|
@ -0,0 +1,108 @@
|
||||
// Copyright (C) 2017 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.gerrit.server.project;
|
||||
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.common.PageLinks;
|
||||
import com.google.gerrit.common.data.ContributorAgreement;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.common.data.PermissionRule.Action;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup.UUID;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.config.CanonicalWebUrl;
|
||||
import com.google.gerrit.server.project.ProjectControl.Metrics;
|
||||
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.List;
|
||||
|
||||
@Singleton
|
||||
public class ContributorAgreementsChecker {
|
||||
|
||||
private final String canonicalWebUrl;
|
||||
private final ProjectCache projectCache;
|
||||
private final Metrics metrics;
|
||||
|
||||
@Inject
|
||||
ContributorAgreementsChecker(
|
||||
@CanonicalWebUrl @Nullable String canonicalWebUrl,
|
||||
ProjectCache projectCache,
|
||||
Metrics metrics) {
|
||||
this.canonicalWebUrl = canonicalWebUrl;
|
||||
this.projectCache = projectCache;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user has signed a contributor agreement for the project.
|
||||
*
|
||||
* @throws AuthException if the user has not signed a contributor agreement for the project
|
||||
* @throws IOException if project states could not be loaded
|
||||
*/
|
||||
public void check(Project.NameKey project, CurrentUser user) throws IOException, AuthException {
|
||||
metrics.claCheckCount.increment();
|
||||
|
||||
ProjectState projectState = projectCache.checkedGet(project);
|
||||
if (projectState == null) {
|
||||
throw new IOException("Can't load All-Projects");
|
||||
}
|
||||
|
||||
if (!projectState.isUseContributorAgreements()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user.isIdentifiedUser()) {
|
||||
throw new AuthException("Must be logged in to verify Contributor Agreement");
|
||||
}
|
||||
|
||||
IdentifiedUser iUser = user.asIdentifiedUser();
|
||||
Collection<ContributorAgreement> contributorAgreements =
|
||||
projectCache.getAllProjects().getConfig().getContributorAgreements();
|
||||
List<UUID> okGroupIds = new ArrayList<>();
|
||||
for (ContributorAgreement ca : contributorAgreements) {
|
||||
List<AccountGroup.UUID> groupIds;
|
||||
groupIds = okGroupIds;
|
||||
|
||||
for (PermissionRule rule : ca.getAccepted()) {
|
||||
if ((rule.getAction() == Action.ALLOW)
|
||||
&& (rule.getGroup() != null)
|
||||
&& (rule.getGroup().getUUID() != null)) {
|
||||
groupIds.add(new AccountGroup.UUID(rule.getGroup().getUUID().get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!iUser.getEffectiveGroups().containsAnyOf(okGroupIds)) {
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
msg.append("A Contributor Agreement must be completed before uploading");
|
||||
if (canonicalWebUrl != null) {
|
||||
msg.append(":\n\n ");
|
||||
msg.append(canonicalWebUrl);
|
||||
msg.append("#");
|
||||
msg.append(PageLinks.SETTINGS_AGREEMENTS);
|
||||
msg.append("\n");
|
||||
} else {
|
||||
msg.append(".");
|
||||
}
|
||||
throw new AuthException(msg.toString());
|
||||
}
|
||||
}
|
||||
}
|
@ -16,16 +16,13 @@ package com.google.gerrit.server.project;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.common.PageLinks;
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.Capable;
|
||||
import com.google.gerrit.common.data.ContributorAgreement;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.common.data.PermissionRule.Action;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.metrics.Counter0;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
@ -34,11 +31,10 @@ import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.Branch;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.RefNames;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.GroupMembership;
|
||||
import com.google.gerrit.server.config.CanonicalWebUrl;
|
||||
import com.google.gerrit.server.config.GitReceivePackGroups;
|
||||
import com.google.gerrit.server.config.GitUploadPackGroups;
|
||||
import com.google.gerrit.server.group.SystemGroupBackend;
|
||||
@ -58,7 +54,6 @@ import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
@ -129,15 +124,12 @@ public class ProjectControl {
|
||||
|
||||
private final Set<AccountGroup.UUID> uploadGroups;
|
||||
private final Set<AccountGroup.UUID> receiveGroups;
|
||||
private final String canonicalWebUrl;
|
||||
private final PermissionBackend.WithUser perm;
|
||||
private final CurrentUser user;
|
||||
private final ProjectState state;
|
||||
private final CommitsCollection commits;
|
||||
private final ChangeControl.Factory changeControlFactory;
|
||||
private final PermissionCollection.Factory permissionFilter;
|
||||
private final Collection<ContributorAgreement> contributorAgreements;
|
||||
private final Metrics metrics;
|
||||
|
||||
private List<SectionMatcher> allSections;
|
||||
private Map<String, RefControl> refControls;
|
||||
@ -151,19 +143,14 @@ public class ProjectControl {
|
||||
PermissionCollection.Factory permissionFilter,
|
||||
CommitsCollection commits,
|
||||
ChangeControl.Factory changeControlFactory,
|
||||
@CanonicalWebUrl @Nullable String canonicalWebUrl,
|
||||
PermissionBackend permissionBackend,
|
||||
@Assisted CurrentUser who,
|
||||
@Assisted ProjectState ps,
|
||||
Metrics metrics) {
|
||||
@Assisted ProjectState ps) {
|
||||
this.changeControlFactory = changeControlFactory;
|
||||
this.uploadGroups = uploadGroups;
|
||||
this.receiveGroups = receiveGroups;
|
||||
this.permissionFilter = permissionFilter;
|
||||
this.commits = commits;
|
||||
this.contributorAgreements = pc.getAllProjects().getConfig().getContributorAgreements();
|
||||
this.canonicalWebUrl = canonicalWebUrl;
|
||||
this.metrics = metrics;
|
||||
this.perm = permissionBackend.user(who);
|
||||
user = who;
|
||||
state = ps;
|
||||
@ -214,31 +201,31 @@ public class ProjectControl {
|
||||
return state.getProject();
|
||||
}
|
||||
|
||||
public boolean allRefsAreVisible(Set<String> ignore) {
|
||||
// TODO(hiesel) Hide refs/changes and replace this method by a proper READ check of all refs
|
||||
return user.isInternalUser() || canPerformOnAllRefs(Permission.READ, ignore);
|
||||
}
|
||||
|
||||
/** Is this user a project owner? */
|
||||
public boolean isOwner() {
|
||||
return (isDeclaredOwner() && !controlForRef("refs/*").isBlocked(Permission.OWNER)) || isAdmin();
|
||||
}
|
||||
|
||||
/** @return {@code Capable.OK} if the user can upload to at least one reference */
|
||||
/**
|
||||
* @return {@code Capable.OK} if the user can upload to at least one reference. Does not check
|
||||
* Contributor Agreements.
|
||||
*/
|
||||
public Capable canPushToAtLeastOneRef() {
|
||||
if (!canPerformOnAnyRef(Permission.PUSH)
|
||||
&& !canPerformOnAnyRef(Permission.CREATE_TAG)
|
||||
&& !isOwner()) {
|
||||
return new Capable("Upload denied for project '" + state.getName() + "'");
|
||||
}
|
||||
if (state.isUseContributorAgreements()) {
|
||||
return verifyActiveContributorAgreement();
|
||||
}
|
||||
return Capable.OK;
|
||||
}
|
||||
|
||||
/** Does this user have ownership on at least one reference name? */
|
||||
public boolean isOwnerAnyRef() {
|
||||
return canPerformOnAnyRef(Permission.OWNER) || isAdmin();
|
||||
}
|
||||
|
||||
/** Can the user run upload pack? */
|
||||
public boolean canRunUploadPack() {
|
||||
private boolean canRunUploadPack() {
|
||||
for (AccountGroup.UUID group : uploadGroups) {
|
||||
if (match(group)) {
|
||||
return true;
|
||||
@ -248,7 +235,7 @@ public class ProjectControl {
|
||||
}
|
||||
|
||||
/** Can the user run receive pack? */
|
||||
public boolean canRunReceivePack() {
|
||||
private boolean canRunReceivePack() {
|
||||
for (AccountGroup.UUID group : receiveGroups) {
|
||||
if (match(group)) {
|
||||
return true;
|
||||
@ -257,6 +244,10 @@ public class ProjectControl {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean allRefsAreVisible(Set<String> ignore) {
|
||||
return user.isInternalUser() || canPerformOnAllRefs(Permission.READ, ignore);
|
||||
}
|
||||
|
||||
/** Returns whether the project is hidden. */
|
||||
private boolean isHidden() {
|
||||
return getProject().getState().equals(com.google.gerrit.extensions.client.ProjectState.HIDDEN);
|
||||
@ -296,46 +287,6 @@ public class ProjectControl {
|
||||
return declaredOwner;
|
||||
}
|
||||
|
||||
private Capable verifyActiveContributorAgreement() {
|
||||
metrics.claCheckCount.increment();
|
||||
if (!(user.isIdentifiedUser())) {
|
||||
return new Capable("Must be logged in to verify Contributor Agreement");
|
||||
}
|
||||
final IdentifiedUser iUser = user.asIdentifiedUser();
|
||||
|
||||
List<AccountGroup.UUID> okGroupIds = new ArrayList<>();
|
||||
for (ContributorAgreement ca : contributorAgreements) {
|
||||
List<AccountGroup.UUID> groupIds;
|
||||
groupIds = okGroupIds;
|
||||
|
||||
for (PermissionRule rule : ca.getAccepted()) {
|
||||
if ((rule.getAction() == Action.ALLOW)
|
||||
&& (rule.getGroup() != null)
|
||||
&& (rule.getGroup().getUUID() != null)) {
|
||||
groupIds.add(new AccountGroup.UUID(rule.getGroup().getUUID().get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iUser.getEffectiveGroups().containsAnyOf(okGroupIds)) {
|
||||
return Capable.OK;
|
||||
}
|
||||
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
msg.append("A Contributor Agreement must be completed before uploading");
|
||||
if (canonicalWebUrl != null) {
|
||||
msg.append(":\n\n ");
|
||||
msg.append(canonicalWebUrl);
|
||||
msg.append("#");
|
||||
msg.append(PageLinks.SETTINGS_AGREEMENTS);
|
||||
msg.append("\n");
|
||||
} else {
|
||||
msg.append(".");
|
||||
}
|
||||
msg.append("\n");
|
||||
return new Capable(msg.toString());
|
||||
}
|
||||
|
||||
private boolean canPerformOnAnyRef(String permissionName) {
|
||||
for (SectionMatcher matcher : access()) {
|
||||
AccessSection section = matcher.section;
|
||||
@ -513,10 +464,18 @@ public class ProjectControl {
|
||||
case READ:
|
||||
return !isHidden() && allRefsAreVisible(Collections.emptySet());
|
||||
|
||||
case READ_NO_CONFIG:
|
||||
return !isHidden() && allRefsAreVisible(ImmutableSet.of(RefNames.REFS_CONFIG));
|
||||
|
||||
case CREATE_REF:
|
||||
return canAddRefs();
|
||||
case CREATE_CHANGE:
|
||||
return canCreateChanges();
|
||||
|
||||
case RUN_RECEIVE_PACK:
|
||||
return canRunReceivePack();
|
||||
case RUN_UPLOAD_PACK:
|
||||
return canRunUploadPack();
|
||||
}
|
||||
throw new PermissionBackendException(perm + " unsupported");
|
||||
}
|
||||
|
@ -207,7 +207,6 @@ public class RefControlTest {
|
||||
@Inject private SingleVersionListener singleVersionListener;
|
||||
@Inject private InMemoryDatabase schemaFactory;
|
||||
@Inject private ThreadLocalRequestContext requestContext;
|
||||
@Inject private ProjectControl.Metrics metrics;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@ -875,11 +874,9 @@ public class RefControlTest {
|
||||
sectionSorter,
|
||||
null, // commitsCollection
|
||||
changeControlFactory,
|
||||
"http://localhost", // canonicalWebUrl
|
||||
permissionBackend,
|
||||
new MockUser(name, memberOf),
|
||||
newProjectState(local),
|
||||
metrics);
|
||||
newProjectState(local));
|
||||
}
|
||||
|
||||
private ProjectState newProjectState(ProjectConfig local) {
|
||||
|
@ -17,11 +17,15 @@ package com.google.gerrit.sshd.commands;
|
||||
import com.google.common.collect.MultimapBuilder;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
import com.google.gerrit.common.data.Capable;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.git.VisibleRefFilter;
|
||||
import com.google.gerrit.server.git.receive.AsyncReceiveCommits;
|
||||
import com.google.gerrit.server.notedb.ReviewerStateInternal;
|
||||
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.sshd.AbstractGitCommand;
|
||||
import com.google.gerrit.sshd.CommandMetaData;
|
||||
import com.google.gerrit.sshd.SshSession;
|
||||
@ -51,6 +55,7 @@ final class Receive extends AbstractGitCommand {
|
||||
@Inject private AsyncReceiveCommits.Factory factory;
|
||||
@Inject private IdentifiedUser currentUser;
|
||||
@Inject private SshSession session;
|
||||
@Inject private PermissionBackend permissionBackend;
|
||||
|
||||
private final SetMultimap<ReviewerStateInternal, Account.Id> reviewers =
|
||||
MultimapBuilder.hashKeys(2).hashSetValues().build();
|
||||
@ -77,8 +82,15 @@ final class Receive extends AbstractGitCommand {
|
||||
|
||||
@Override
|
||||
protected void runImpl() throws IOException, Failure {
|
||||
if (!projectControl.canRunReceivePack()) {
|
||||
try {
|
||||
permissionBackend
|
||||
.user(currentUser)
|
||||
.project(project.getNameKey())
|
||||
.check(ProjectPermission.RUN_RECEIVE_PACK);
|
||||
} catch (AuthException e) {
|
||||
throw new Failure(1, "fatal: receive-pack not permitted on this server");
|
||||
} catch (PermissionBackendException e) {
|
||||
throw new Failure(1, "fatal: unable to check permissions " + e);
|
||||
}
|
||||
|
||||
AsyncReceiveCommits arc = factory.create(projectControl, repo, null, reviewers);
|
||||
|
@ -16,10 +16,14 @@ package com.google.gerrit.sshd.commands;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.server.git.TransferConfig;
|
||||
import com.google.gerrit.server.git.VisibleRefFilter;
|
||||
import com.google.gerrit.server.git.validators.UploadValidationException;
|
||||
import com.google.gerrit.server.git.validators.UploadValidators;
|
||||
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.sshd.AbstractGitCommand;
|
||||
import com.google.gerrit.sshd.SshSession;
|
||||
import com.google.inject.Inject;
|
||||
@ -39,11 +43,19 @@ final class Upload extends AbstractGitCommand {
|
||||
@Inject private DynamicSet<PostUploadHook> postUploadHooks;
|
||||
@Inject private UploadValidators.Factory uploadValidatorsFactory;
|
||||
@Inject private SshSession session;
|
||||
@Inject private PermissionBackend permissionBackend;
|
||||
|
||||
@Override
|
||||
protected void runImpl() throws IOException, Failure {
|
||||
if (!projectControl.canRunUploadPack()) {
|
||||
try {
|
||||
permissionBackend
|
||||
.user(projectControl.getUser())
|
||||
.project(projectControl.getProject().getNameKey())
|
||||
.check(ProjectPermission.RUN_UPLOAD_PACK);
|
||||
} catch (AuthException e) {
|
||||
throw new Failure(1, "fatal: upload-pack not permitted on this server");
|
||||
} catch (PermissionBackendException e) {
|
||||
throw new Failure(1, "fatal: unable to check permissions " + e);
|
||||
}
|
||||
|
||||
final UploadPack up = new UploadPack(repo);
|
||||
|
Loading…
Reference in New Issue
Block a user