summaryrefslogtreecommitdiffstats
path: root/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java')
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java512
1 files changed, 0 insertions, 512 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
deleted file mode 100644
index e97411e556..0000000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
+++ /dev/null
@@ -1,512 +0,0 @@
-// Copyright (C) 2009 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 static com.google.common.base.Preconditions.checkArgument;
-import static com.google.gerrit.reviewdb.client.RefNames.REFS_TAGS;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import com.google.gerrit.common.data.AccessSection;
-import com.google.gerrit.common.data.Capable;
-import com.google.gerrit.common.data.Permission;
-import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.extensions.restapi.AuthException;
-import com.google.gerrit.metrics.Counter0;
-import com.google.gerrit.metrics.Description;
-import com.google.gerrit.metrics.MetricMaker;
-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.account.GroupMembership;
-import com.google.gerrit.server.config.GitReceivePackGroups;
-import com.google.gerrit.server.config.GitUploadPackGroups;
-import com.google.gerrit.server.group.SystemGroupBackend;
-import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.permissions.FailedPermissionBackend;
-import com.google.gerrit.server.permissions.GlobalPermission;
-import com.google.gerrit.server.permissions.PermissionBackend;
-import com.google.gerrit.server.permissions.PermissionBackend.ForChange;
-import com.google.gerrit.server.permissions.PermissionBackend.ForProject;
-import com.google.gerrit.server.permissions.PermissionBackend.ForRef;
-import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gerrit.server.permissions.ProjectPermission;
-import com.google.gerrit.server.query.change.ChangeData;
-import com.google.gwtorm.server.OrmException;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import com.google.inject.assistedinject.Assisted;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefDatabase;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** Access control management for a user accessing a project's data. */
-public class ProjectControl {
- private static final Logger log = LoggerFactory.getLogger(ProjectControl.class);
-
- public static class GenericFactory {
- private final ProjectCache projectCache;
-
- @Inject
- GenericFactory(ProjectCache pc) {
- projectCache = pc;
- }
-
- public ProjectControl controlFor(Project.NameKey nameKey, CurrentUser user)
- throws NoSuchProjectException, IOException {
- final ProjectState p = projectCache.checkedGet(nameKey);
- if (p == null) {
- throw new NoSuchProjectException(nameKey);
- }
- return p.controlFor(user);
- }
- }
-
- public static class Factory {
- private final Provider<PerRequestProjectControlCache> userCache;
-
- @Inject
- Factory(Provider<PerRequestProjectControlCache> uc) {
- userCache = uc;
- }
-
- public ProjectControl controlFor(Project.NameKey nameKey) throws NoSuchProjectException {
- return userCache.get().get(nameKey);
- }
- }
-
- public interface AssistedFactory {
- ProjectControl create(CurrentUser who, ProjectState ps);
- }
-
- @Singleton
- protected static class Metrics {
- final Counter0 claCheckCount;
-
- @Inject
- Metrics(MetricMaker metricMaker) {
- claCheckCount =
- metricMaker.newCounter(
- "license/cla_check_count",
- new Description("Total number of CLA check requests").setRate().setUnit("requests"));
- }
- }
-
- private final Set<AccountGroup.UUID> uploadGroups;
- private final Set<AccountGroup.UUID> receiveGroups;
- 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 List<SectionMatcher> allSections;
- private Map<String, RefControl> refControls;
- private Boolean declaredOwner;
-
- @Inject
- ProjectControl(
- @GitUploadPackGroups Set<AccountGroup.UUID> uploadGroups,
- @GitReceivePackGroups Set<AccountGroup.UUID> receiveGroups,
- PermissionCollection.Factory permissionFilter,
- CommitsCollection commits,
- ChangeControl.Factory changeControlFactory,
- PermissionBackend permissionBackend,
- @Assisted CurrentUser who,
- @Assisted ProjectState ps) {
- this.changeControlFactory = changeControlFactory;
- this.uploadGroups = uploadGroups;
- this.receiveGroups = receiveGroups;
- this.permissionFilter = permissionFilter;
- this.commits = commits;
- this.perm = permissionBackend.user(who);
- user = who;
- state = ps;
- }
-
- public ProjectControl forUser(CurrentUser who) {
- ProjectControl r = state.controlFor(who);
- // Not per-user, and reusing saves lookup time.
- r.allSections = allSections;
- return r;
- }
-
- public ChangeControl controlFor(ReviewDb db, Change change) throws OrmException {
- return changeControlFactory.create(
- controlForRef(change.getDest()), db, change.getProject(), change.getId());
- }
-
- public ChangeControl controlFor(ChangeNotes notes) {
- return changeControlFactory.create(controlForRef(notes.getChange().getDest()), notes);
- }
-
- public RefControl controlForRef(Branch.NameKey ref) {
- return controlForRef(ref.get());
- }
-
- public RefControl controlForRef(String refName) {
- if (refControls == null) {
- refControls = new HashMap<>();
- }
- RefControl ctl = refControls.get(refName);
- if (ctl == null) {
- PermissionCollection relevant = permissionFilter.filter(access(), refName, user);
- ctl = new RefControl(this, refName, relevant);
- refControls.put(refName, ctl);
- }
- return ctl;
- }
-
- public CurrentUser getUser() {
- return user;
- }
-
- public ProjectState getProjectState() {
- return state;
- }
-
- public Project getProject() {
- return state.getProject();
- }
-
- /** 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. 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() + "'");
- }
- return Capable.OK;
- }
-
- /** Can the user run upload pack? */
- private boolean canRunUploadPack() {
- for (AccountGroup.UUID group : uploadGroups) {
- if (match(group)) {
- return true;
- }
- }
- return false;
- }
-
- /** Can the user run receive pack? */
- private boolean canRunReceivePack() {
- for (AccountGroup.UUID group : receiveGroups) {
- if (match(group)) {
- return true;
- }
- }
- 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);
- }
-
- private boolean canAddRefs() {
- return (canPerformOnAnyRef(Permission.CREATE) || isAdmin());
- }
-
- private boolean canAddTagRefs() {
- return (canPerformOnTagRef(Permission.CREATE) || isAdmin());
- }
-
- private boolean canCreateChanges() {
- for (SectionMatcher matcher : access()) {
- AccessSection section = matcher.section;
- if (section.getName().startsWith("refs/for/")) {
- Permission permission = section.getPermission(Permission.PUSH);
- if (permission != null && controlForRef(section.getName()).canPerform(Permission.PUSH)) {
- return true;
- }
- }
- }
- return false;
- }
-
- boolean isAdmin() {
- try {
- perm.check(GlobalPermission.ADMINISTRATE_SERVER);
- return true;
- } catch (AuthException | PermissionBackendException e) {
- return false;
- }
- }
-
- private boolean isDeclaredOwner() {
- if (declaredOwner == null) {
- GroupMembership effectiveGroups = user.getEffectiveGroups();
- declaredOwner = effectiveGroups.containsAnyOf(state.getAllOwners());
- }
- return declaredOwner;
- }
-
- private boolean canPerformOnTagRef(String permissionName) {
- for (SectionMatcher matcher : access()) {
- AccessSection section = matcher.section;
-
- if (section.getName().startsWith(REFS_TAGS)) {
- Permission permission = section.getPermission(permissionName);
- if (permission == null) {
- continue;
- }
-
- Boolean can = canPerform(permissionName, section, permission);
- if (can != null) {
- return can;
- }
- }
- }
-
- return false;
- }
-
- private boolean canPerformOnAnyRef(String permissionName) {
- for (SectionMatcher matcher : access()) {
- AccessSection section = matcher.section;
- Permission permission = section.getPermission(permissionName);
- if (permission == null) {
- continue;
- }
-
- Boolean can = canPerform(permissionName, section, permission);
- if (can != null) {
- return can;
- }
- }
-
- return false;
- }
-
- private Boolean canPerform(String permissionName, AccessSection section, Permission permission) {
- for (PermissionRule rule : permission.getRules()) {
- if (rule.isBlock() || rule.isDeny() || !match(rule)) {
- continue;
- }
-
- // Being in a group that was granted this permission is only an
- // approximation. There might be overrides and doNotInherit
- // that would render this to be false.
- //
- if (controlForRef(section.getName()).canPerform(permissionName)) {
- return true;
- }
- break;
- }
- return null;
- }
-
- private boolean canPerformOnAllRefs(String permission, Set<String> ignore) {
- boolean canPerform = false;
- Set<String> patterns = allRefPatterns(permission);
- if (patterns.contains(AccessSection.ALL)) {
- // Only possible if granted on the pattern that
- // matches every possible reference. Check all
- // patterns also have the permission.
- //
- for (String pattern : patterns) {
- if (controlForRef(pattern).canPerform(permission)) {
- canPerform = true;
- } else if (ignore.contains(pattern)) {
- continue;
- } else {
- return false;
- }
- }
- }
- return canPerform;
- }
-
- private Set<String> allRefPatterns(String permissionName) {
- Set<String> all = new HashSet<>();
- for (SectionMatcher matcher : access()) {
- AccessSection section = matcher.section;
- Permission permission = section.getPermission(permissionName);
- if (permission != null) {
- all.add(section.getName());
- }
- }
- return all;
- }
-
- private List<SectionMatcher> access() {
- if (allSections == null) {
- allSections = state.getAllSections();
- }
- return allSections;
- }
-
- boolean match(PermissionRule rule) {
- return match(rule.getGroup().getUUID());
- }
-
- boolean match(PermissionRule rule, boolean isChangeOwner) {
- return match(rule.getGroup().getUUID(), isChangeOwner);
- }
-
- boolean match(AccountGroup.UUID uuid) {
- return match(uuid, false);
- }
-
- boolean match(AccountGroup.UUID uuid, boolean isChangeOwner) {
- if (SystemGroupBackend.PROJECT_OWNERS.equals(uuid)) {
- return isDeclaredOwner();
- } else if (SystemGroupBackend.CHANGE_OWNER.equals(uuid)) {
- return isChangeOwner;
- } else {
- return user.getEffectiveGroups().contains(uuid);
- }
- }
-
- boolean isReachableFromHeadsOrTags(Repository repo, RevCommit commit) {
- try {
- RefDatabase refdb = repo.getRefDatabase();
- Collection<Ref> heads = refdb.getRefs(Constants.R_HEADS).values();
- Collection<Ref> tags = refdb.getRefs(Constants.R_TAGS).values();
- Map<String, Ref> refs = Maps.newHashMapWithExpectedSize(heads.size() + tags.size());
- for (Ref r : Iterables.concat(heads, tags)) {
- refs.put(r.getName(), r);
- }
- return commits.isReachableFrom(state, repo, commit, refs);
- } catch (IOException e) {
- log.error(
- "Cannot verify permissions to commit object {} in repository {}",
- commit.name(),
- getProject().getNameKey(),
- e);
- return false;
- }
- }
-
- ForProject asForProject() {
- return new ForProjectImpl();
- }
-
- private class ForProjectImpl extends ForProject {
- @Override
- public ForProject user(CurrentUser user) {
- return forUser(user).asForProject().database(db);
- }
-
- @Override
- public ForRef ref(String ref) {
- return controlForRef(ref).asForRef().database(db);
- }
-
- @Override
- public ForChange change(ChangeData cd) {
- try {
- checkProject(cd.change());
- return super.change(cd);
- } catch (OrmException e) {
- return FailedPermissionBackend.change("unavailable", e);
- }
- }
-
- @Override
- public ForChange change(ChangeNotes notes) {
- checkProject(notes.getChange());
- return super.change(notes);
- }
-
- private void checkProject(Change change) {
- Project.NameKey project = getProject().getNameKey();
- checkArgument(
- project.equals(change.getProject()),
- "expected change in project %s, not %s",
- project,
- change.getProject());
- }
-
- @Override
- public void check(ProjectPermission perm) throws AuthException, PermissionBackendException {
- if (!can(perm)) {
- throw new AuthException(perm.describeForException() + " not permitted");
- }
- }
-
- @Override
- public Set<ProjectPermission> test(Collection<ProjectPermission> permSet)
- throws PermissionBackendException {
- EnumSet<ProjectPermission> ok = EnumSet.noneOf(ProjectPermission.class);
- for (ProjectPermission perm : permSet) {
- if (can(perm)) {
- ok.add(perm);
- }
- }
- return ok;
- }
-
- private boolean can(ProjectPermission perm) throws PermissionBackendException {
- switch (perm) {
- case ACCESS:
- return (!isHidden() && (user.isInternalUser() || canPerformOnAnyRef(Permission.READ)))
- || isOwner();
-
- 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_TAG_REF:
- return canAddTagRefs();
- case CREATE_CHANGE:
- return canCreateChanges();
-
- case RUN_RECEIVE_PACK:
- return canRunReceivePack();
- case RUN_UPLOAD_PACK:
- return canRunUploadPack();
- }
- throw new PermissionBackendException(perm + " unsupported");
- }
- }
-}