// Copyright (C) 2012 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.account; import com.google.common.base.Predicate; import com.google.common.collect.Sets; import com.google.gerrit.common.data.PermissionRule; import com.google.gerrit.common.errors.NoSuchGroupException; import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.git.AccountsSection; import com.google.gerrit.server.group.SystemGroupBackend; import com.google.gerrit.server.project.ProjectCache; import com.google.inject.Inject; import com.google.inject.Provider; import java.util.HashSet; import java.util.Set; /** Access control management for one account's access to other accounts. */ public class AccountControl { public static class Factory { private final ProjectCache projectCache; private final GroupControl.Factory groupControlFactory; private final Provider<CurrentUser> user; private final IdentifiedUser.GenericFactory userFactory; private final AccountVisibility accountVisibility; @Inject Factory(final ProjectCache projectCache, final GroupControl.Factory groupControlFactory, final Provider<CurrentUser> user, final IdentifiedUser.GenericFactory userFactory, final AccountVisibility accountVisibility) { this.projectCache = projectCache; this.groupControlFactory = groupControlFactory; this.user = user; this.userFactory = userFactory; this.accountVisibility = accountVisibility; } public AccountControl get() { return new AccountControl(projectCache, groupControlFactory, user.get(), userFactory, accountVisibility); } } private final AccountsSection accountsSection; private final GroupControl.Factory groupControlFactory; private final CurrentUser currentUser; private final IdentifiedUser.GenericFactory userFactory; private final AccountVisibility accountVisibility; AccountControl(final ProjectCache projectCache, final GroupControl.Factory groupControlFactory, final CurrentUser currentUser, final IdentifiedUser.GenericFactory userFactory, final AccountVisibility accountVisibility) { this.accountsSection = projectCache.getAllProjects().getConfig().getAccountsSection(); this.groupControlFactory = groupControlFactory; this.currentUser = currentUser; this.userFactory = userFactory; this.accountVisibility = accountVisibility; } /** * Returns true if the otherUser is allowed to see the current user, based * on the account visibility policy. Depending on the group membership * realms supported, this may not be able to determine SAME_GROUP or * VISIBLE_GROUP correctly (defaulting to not being visible). This is because * {@link GroupMembership#getKnownGroups()} may only return a subset of the * effective groups. */ public boolean canSee(final Account otherUser) { return canSee(otherUser.getId()); } /** * Returns true if the otherUser is allowed to see the current user, based * on the account visibility policy. Depending on the group membership * realms supported, this may not be able to determine SAME_GROUP or * VISIBLE_GROUP correctly (defaulting to not being visible). This is because * {@link GroupMembership#getKnownGroups()} may only return a subset of the * effective groups. */ public boolean canSee(final Account.Id otherUser) { // Special case: I can always see myself. if (currentUser.isIdentifiedUser() && ((IdentifiedUser) currentUser).getAccountId().equals(otherUser)) { return true; } if (currentUser.getCapabilities().canViewAllAccounts()) { return true; } switch (accountVisibility) { case ALL: return true; case SAME_GROUP: { Set<AccountGroup.UUID> usersGroups = groupsOf(otherUser); for (PermissionRule rule : accountsSection.getSameGroupVisibility()) { if (rule.isBlock() || rule.isDeny()) { usersGroups.remove(rule.getGroup().getUUID()); } } if (currentUser.getEffectiveGroups().containsAnyOf(usersGroups)) { return true; } break; } case VISIBLE_GROUP: { Set<AccountGroup.UUID> usersGroups = groupsOf(otherUser); for (AccountGroup.UUID usersGroup : usersGroups) { try { if (groupControlFactory.controlFor(usersGroup).isVisible()) { return true; } } catch (NoSuchGroupException e) { continue; } } break; } case NONE: break; default: throw new IllegalStateException("Bad AccountVisibility " + accountVisibility); } return false; } private Set<AccountGroup.UUID> groupsOf(Account.Id account) { return new HashSet<>(Sets.filter( userFactory.create(account).getEffectiveGroups().getKnownGroups(), new Predicate<AccountGroup.UUID>() { @Override public boolean apply(AccountGroup.UUID in) { return !SystemGroupBackend.isSystemGroup(in); } })); } }