diff options
Diffstat (limited to 'java/com/google/gerrit/server/restapi/project/CheckAccess.java')
-rw-r--r-- | java/com/google/gerrit/server/restapi/project/CheckAccess.java | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/java/com/google/gerrit/server/restapi/project/CheckAccess.java b/java/com/google/gerrit/server/restapi/project/CheckAccess.java new file mode 100644 index 0000000000..1664635579 --- /dev/null +++ b/java/com/google/gerrit/server/restapi/project/CheckAccess.java @@ -0,0 +1,138 @@ +// 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.restapi.project; + +import static com.google.gerrit.reviewdb.client.RefNames.REFS_HEADS; + +import com.google.common.base.Strings; +import com.google.gerrit.extensions.api.config.AccessCheckInfo; +import com.google.gerrit.extensions.api.config.AccessCheckInput; +import com.google.gerrit.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.extensions.restapi.UnprocessableEntityException; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.Branch; +import com.google.gerrit.server.account.AccountResolver; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.permissions.DefaultPermissionMappings; +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.ProjectResource; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import java.io.IOException; +import java.util.Optional; +import javax.servlet.http.HttpServletResponse; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.lib.Repository; + +@Singleton +public class CheckAccess implements RestModifyView<ProjectResource, AccessCheckInput> { + private final AccountResolver accountResolver; + private final PermissionBackend permissionBackend; + private final GitRepositoryManager gitRepositoryManager; + + @Inject + CheckAccess( + AccountResolver resolver, + PermissionBackend permissionBackend, + GitRepositoryManager gitRepositoryManager) { + this.accountResolver = resolver; + this.permissionBackend = permissionBackend; + this.gitRepositoryManager = gitRepositoryManager; + } + + @Override + public AccessCheckInfo apply(ProjectResource rsrc, AccessCheckInput input) + throws OrmException, PermissionBackendException, RestApiException, IOException, + ConfigInvalidException { + permissionBackend.user(rsrc.getUser()).check(GlobalPermission.VIEW_ACCESS); + + rsrc.getProjectState().checkStatePermitsRead(); + + if (input == null) { + throw new BadRequestException("input is required"); + } + if (Strings.isNullOrEmpty(input.account)) { + throw new BadRequestException("input requires 'account'"); + } + + Account match = accountResolver.find(input.account); + if (match == null) { + throw new UnprocessableEntityException( + String.format("cannot find account %s", input.account)); + } + + AccessCheckInfo info = new AccessCheckInfo(); + try { + permissionBackend + .absentUser(match.getId()) + .project(rsrc.getNameKey()) + .check(ProjectPermission.ACCESS); + } catch (AuthException e) { + info.message = String.format("user %s cannot see project %s", match.getId(), rsrc.getName()); + info.status = HttpServletResponse.SC_FORBIDDEN; + return info; + } + + RefPermission refPerm; + if (!Strings.isNullOrEmpty(input.permission)) { + if (Strings.isNullOrEmpty(input.ref)) { + throw new BadRequestException("must set 'ref' when specifying 'permission'"); + } + Optional<RefPermission> rp = DefaultPermissionMappings.refPermission(input.permission); + if (!rp.isPresent()) { + throw new BadRequestException( + String.format("'%s' is not recognized as ref permission", input.permission)); + } + + refPerm = rp.get(); + } else { + refPerm = RefPermission.READ; + } + + if (!Strings.isNullOrEmpty(input.ref)) { + try { + permissionBackend + .absentUser(match.getId()) + .ref(new Branch.NameKey(rsrc.getNameKey(), input.ref)) + .check(refPerm); + } catch (AuthException e) { + info.status = HttpServletResponse.SC_FORBIDDEN; + info.message = + String.format( + "user %s lacks permission %s for %s in project %s", + match.getId(), input.permission, input.ref, rsrc.getName()); + return info; + } + } else { + // We say access is okay if there are no refs, but this warrants a warning, + // as access denied looks the same as no branches to the user. + try (Repository repo = gitRepositoryManager.openRepository(rsrc.getNameKey())) { + if (repo.getRefDatabase().getRefsByPrefix(REFS_HEADS).isEmpty()) { + info.message = "access is OK, but repository has no branches under refs/heads/"; + } + } + } + info.status = HttpServletResponse.SC_OK; + return info; + } +} |