diff options
Diffstat (limited to 'gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java')
-rw-r--r-- | gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java | 110 |
1 files changed, 75 insertions, 35 deletions
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java index ca23ec2500..4cd6fa0739 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java @@ -14,6 +14,10 @@ package com.google.gerrit.httpd.rpc.project; +import static com.google.gerrit.server.permissions.GlobalPermission.ADMINISTRATE_SERVER; +import static com.google.gerrit.server.permissions.RefPermission.CREATE_CHANGE; +import static com.google.gerrit.server.permissions.RefPermission.READ; + import com.google.common.collect.Maps; import com.google.gerrit.common.data.AccessSection; import com.google.gerrit.common.data.GroupDescription; @@ -24,21 +28,28 @@ import com.google.gerrit.common.data.ProjectAccess; import com.google.gerrit.common.data.RefConfigSection; import com.google.gerrit.common.data.WebLinkInfoCommon; import com.google.gerrit.common.errors.NoSuchGroupException; +import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.httpd.rpc.Handler; import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.RefNames; +import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.WebLinks; import com.google.gerrit.server.account.GroupBackend; import com.google.gerrit.server.account.GroupControl; 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.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.NoSuchProjectException; import com.google.gerrit.server.project.ProjectCache; import com.google.gerrit.server.project.ProjectControl; -import com.google.gerrit.server.project.RefControl; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.assistedinject.Assisted; import java.io.IOException; import java.util.ArrayList; @@ -56,27 +67,32 @@ class ProjectAccessFactory extends Handler<ProjectAccess> { private final GroupBackend groupBackend; private final ProjectCache projectCache; - private final ProjectControl.Factory projectControlFactory; + private final PermissionBackend permissionBackend; + private final Provider<CurrentUser> user; + private final ProjectControl.GenericFactory projectControlFactory; private final GroupControl.Factory groupControlFactory; private final MetaDataUpdate.Server metaDataUpdateFactory; private final AllProjectsName allProjectsName; private final Project.NameKey projectName; - private ProjectControl pc; private WebLinks webLinks; @Inject ProjectAccessFactory( - final GroupBackend groupBackend, - final ProjectCache projectCache, - final ProjectControl.Factory projectControlFactory, - final GroupControl.Factory groupControlFactory, - final MetaDataUpdate.Server metaDataUpdateFactory, - final AllProjectsName allProjectsName, - final WebLinks webLinks, + GroupBackend groupBackend, + ProjectCache projectCache, + PermissionBackend permissionBackend, + Provider<CurrentUser> user, + ProjectControl.GenericFactory projectControlFactory, + GroupControl.Factory groupControlFactory, + MetaDataUpdate.Server metaDataUpdateFactory, + AllProjectsName allProjectsName, + WebLinks webLinks, @Assisted final Project.NameKey name) { this.groupBackend = groupBackend; this.projectCache = projectCache; + this.permissionBackend = permissionBackend; + this.user = user; this.projectControlFactory = projectControlFactory; this.groupControlFactory = groupControlFactory; this.metaDataUpdateFactory = metaDataUpdateFactory; @@ -87,8 +103,10 @@ class ProjectAccessFactory extends Handler<ProjectAccess> { } @Override - public ProjectAccess call() throws NoSuchProjectException, IOException, ConfigInvalidException { - pc = open(); + public ProjectAccess call() + throws NoSuchProjectException, IOException, ConfigInvalidException, + PermissionBackendException { + ProjectControl pc = checkProjectControl(); // Load the current configuration from the repository, ensuring its the most // recent version available. If it differs from what was in the project @@ -97,23 +115,23 @@ class ProjectAccessFactory extends Handler<ProjectAccess> { ProjectConfig config; try (MetaDataUpdate md = metaDataUpdateFactory.create(projectName)) { config = ProjectConfig.read(md); - if (config.updateGroupNames(groupBackend)) { md.setMessage("Update group names\n"); config.commit(md); projectCache.evict(config.getProject()); - pc = open(); + pc = checkProjectControl(); } else if (config.getRevision() != null && !config.getRevision().equals(pc.getProjectState().getConfig().getRevision())) { projectCache.evict(config.getProject()); - pc = open(); + pc = checkProjectControl(); } } - final RefControl metaConfigControl = pc.controlForRef(RefNames.REFS_CONFIG); List<AccessSection> local = new ArrayList<>(); Set<String> ownerOf = new HashSet<>(); Map<AccountGroup.UUID, Boolean> visibleGroups = new HashMap<>(); + PermissionBackend.ForProject perm = permissionBackend.user(user).project(projectName); + boolean checkReadConfig = check(perm, RefNames.REFS_CONFIG, READ); for (AccessSection section : config.getAccessSections()) { String name = section.getName(); @@ -122,20 +140,19 @@ class ProjectAccessFactory extends Handler<ProjectAccess> { local.add(section); ownerOf.add(name); - } else if (metaConfigControl.isVisible()) { + } else if (checkReadConfig) { local.add(section); } } else if (RefConfigSection.isValid(name)) { - RefControl rc = pc.controlForRef(name); - if (rc.isOwner()) { + if (pc.controlForRef(name).isOwner()) { local.add(section); ownerOf.add(name); - } else if (metaConfigControl.isVisible()) { + } else if (checkReadConfig) { local.add(section); - } else if (rc.isVisible()) { + } else if (check(perm, name, READ)) { // Filter the section to only add rules describing groups that // are visible to the current-user. This includes any group the // user is a member of, as well as groups they own or that @@ -177,10 +194,9 @@ class ProjectAccessFactory extends Handler<ProjectAccess> { } } - if (ownerOf.isEmpty() && pc.isOwnerAnyRef()) { + if (ownerOf.isEmpty() && isAdmin()) { // Special case: If the section list is empty, this project has no current - // access control information. Rely on what ProjectControl determines - // is ownership, which probably means falling back to site administrators. + // access control information. Fall back to site administrators. ownerOf.add(AccessSection.ALL); } @@ -193,19 +209,19 @@ class ProjectAccessFactory extends Handler<ProjectAccess> { detail.setInheritsFrom(config.getProject().getParent(allProjectsName)); - if (projectName.equals(allProjectsName)) { - if (pc.isOwner()) { - ownerOf.add(AccessSection.GLOBAL_CAPABILITIES); - } + if (projectName.equals(allProjectsName) + && permissionBackend.user(user).testOrFalse(ADMINISTRATE_SERVER)) { + ownerOf.add(AccessSection.GLOBAL_CAPABILITIES); } detail.setLocal(local); detail.setOwnerOf(ownerOf); detail.setCanUpload( - metaConfigControl.isVisible() && (pc.isOwner() || metaConfigControl.canUpload())); - detail.setConfigVisible(pc.isOwner() || metaConfigControl.isVisible()); + pc.isOwner() + || (checkReadConfig && perm.ref(RefNames.REFS_CONFIG).testOrFalse(CREATE_CHANGE))); + detail.setConfigVisible(pc.isOwner() || checkReadConfig); detail.setGroupInfo(buildGroupInfo(local)); - detail.setLabelTypes(pc.getLabelTypes()); + detail.setLabelTypes(pc.getProjectState().getLabelTypes()); detail.setFileHistoryLinks(getConfigFileLogLinks(projectName.get())); return detail; } @@ -235,9 +251,33 @@ class ProjectAccessFactory extends Handler<ProjectAccess> { return Maps.filterEntries(infos, in -> in.getValue() != null); } - private ProjectControl open() throws NoSuchProjectException { - return projectControlFactory.validateFor( // - projectName, // - ProjectControl.OWNER | ProjectControl.VISIBLE); + private ProjectControl checkProjectControl() + throws NoSuchProjectException, IOException, PermissionBackendException { + ProjectControl pc = projectControlFactory.controlFor(projectName, user.get()); + try { + permissionBackend.user(user).project(projectName).check(ProjectPermission.ACCESS); + } catch (AuthException e) { + throw new NoSuchProjectException(projectName); + } + return pc; + } + + private static boolean check(PermissionBackend.ForProject ctx, String ref, RefPermission perm) + throws PermissionBackendException { + try { + ctx.ref(ref).check(perm); + return true; + } catch (AuthException denied) { + return false; + } + } + + private boolean isAdmin() throws PermissionBackendException { + try { + permissionBackend.user(user).check(GlobalPermission.ADMINISTRATE_SERVER); + return true; + } catch (AuthException e) { + return false; + } } } |