/* * SonarQube * Copyright (C) 2009-2017 SonarSource SA * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonar.db.permission; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.sonar.api.security.DefaultGroups; import org.sonar.db.Dao; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentMapper; import org.sonar.db.user.GroupMapper; import static com.google.common.base.Preconditions.checkArgument; import static org.sonar.db.DatabaseUtils.executeLargeInputs; import static org.sonar.db.DatabaseUtils.executeLargeInputsWithoutOutput; public class GroupPermissionDao implements Dao { private static final String ANYONE_GROUP_PARAMETER = "anyoneGroup"; /** * Returns the names of the groups that match the given query, for the given organization. * The virtual group "Anyone" may be returned as the value {@link DefaultGroups#ANYONE}. * @return group names, sorted in alphabetical order */ public List<String> selectGroupNamesByQuery(DbSession dbSession, PermissionQuery query) { return mapper(dbSession).selectGroupNamesByQuery(query, new RowBounds(query.getPageOffset(), query.getPageSize())); } /** * Count the number of groups returned by {@link #selectGroupNamesByQuery(DbSession, PermissionQuery)}, * without applying pagination. */ public int countGroupsByQuery(DbSession dbSession, PermissionQuery query) { return mapper(dbSession).countGroupsByQuery(query); } /** * Select global or project permission of given groups and organization. Anyone virtual group is supported * through the value "zero" (0L) in {@code groupIds}. */ public List<GroupPermissionDto> selectByGroupIds(DbSession dbSession, String organizationUuid, List<Integer> groupIds, @Nullable Long projectId) { return executeLargeInputs(groupIds, groups -> mapper(dbSession).selectByGroupIds(organizationUuid, groups, projectId)); } /** * Select global and project permissions of a given group (Anyone group is NOT supported) * Each row returns a {@link GroupPermissionDto} */ public void selectAllPermissionsByGroupId(DbSession dbSession, String organizationUuid, Integer groupId, ResultHandler resultHandler) { mapper(dbSession).selectAllPermissionsByGroupId(organizationUuid, groupId, resultHandler); } /** * Each row returns a {@link CountPerProjectPermission} */ public void groupsCountByComponentIdAndPermission(DbSession dbSession, List<Long> componentIds, ResultHandler resultHandler) { Map<String, Object> parameters = new HashMap<>(2); parameters.put(ANYONE_GROUP_PARAMETER, DefaultGroups.ANYONE); executeLargeInputsWithoutOutput( componentIds, partitionedComponentIds -> { parameters.put("componentIds", partitionedComponentIds); mapper(dbSession).groupsCountByProjectIdAndPermission(parameters, resultHandler); }); } /** * Selects the global permissions granted to group. An empty list is returned if the * group does not exist. */ public List<String> selectGlobalPermissionsOfGroup(DbSession session, String organizationUuid, @Nullable Integer groupId) { return mapper(session).selectGlobalPermissionsOfGroup(organizationUuid, groupId); } /** * Selects the permissions granted to group and project. An empty list is returned if the * group or project do not exist. */ public List<String> selectProjectPermissionsOfGroup(DbSession session, String organizationUuid, @Nullable Integer groupId, long projectId) { return mapper(session).selectProjectPermissionsOfGroup(organizationUuid, groupId, projectId); } /** * Lists id of groups with at least one permission on the specified root component but which do not have the specified * permission, <strong>excluding group "AnyOne"</strong> (which implies the returned {@code Sett} can't contain * {@code null}). */ public Set<Integer> selectGroupIdsWithPermissionOnProjectBut(DbSession session, long projectId, String permission) { return mapper(session).selectGroupIdsWithPermissionOnProjectBut(projectId, permission); } public void insert(DbSession dbSession, GroupPermissionDto dto) { ensureComponentPermissionConsistency(dbSession, dto); ensureGroupPermissionConsistency(dbSession, dto); mapper(dbSession).insert(dto); } private static void ensureComponentPermissionConsistency(DbSession dbSession, GroupPermissionDto dto) { if (dto.getResourceId() == null) { return; } ComponentMapper componentMapper = dbSession.getMapper(ComponentMapper.class); checkArgument( componentMapper.countComponentByOrganizationAndId(dto.getOrganizationUuid(), dto.getResourceId()) == 1, "Can't insert permission '%s' for component with id '%s' in organization with uuid '%s' because this component does not belong to organization with uuid '%s'", dto.getRole(), dto.getResourceId(), dto.getOrganizationUuid(), dto.getOrganizationUuid()); } private static void ensureGroupPermissionConsistency(DbSession dbSession, GroupPermissionDto dto) { if (dto.getGroupId() == null) { return; } GroupMapper groupMapper = dbSession.getMapper(GroupMapper.class); checkArgument( groupMapper.countGroupByOrganizationAndId(dto.getOrganizationUuid(), dto.getGroupId()) == 1, "Can't insert permission '%s' for group with id '%s' in organization with uuid '%s' because this group does not belong to organization with uuid '%s'", dto.getRole(), dto.getGroupId(), dto.getOrganizationUuid(), dto.getOrganizationUuid()); } /** * Delete all the permissions associated to a root component (project) */ public void deleteByRootComponentId(DbSession dbSession, long rootComponentId) { mapper(dbSession).deleteByRootComponentId(rootComponentId); } /** * Delete all permissions of the specified group (group "AnyOne" if {@code groupId} is {@code null}) for the specified * component. */ public int deleteByRootComponentIdAndGroupId(DbSession dbSession, long rootComponentId, @Nullable Integer groupId) { return mapper(dbSession).deleteByRootComponentIdAndGroupId(rootComponentId, groupId); } /** * Delete the specified permission for the specified component for any group (including group AnyOne). */ public int deleteByRootComponentIdAndPermission(DbSession dbSession, long rootComponentId, String permission) { return mapper(dbSession).deleteByRootComponentIdAndPermission(rootComponentId, permission); } /** * Delete a single permission. It can be: * <ul> * <li>a global permission granted to a group</li> * <li>a global permission granted to anyone</li> * <li>a permission granted to a group for a project</li> * <li>a permission granted to anyone for a project</li> * </ul> * @param dbSession * @param permission the kind of permission * @param organizationUuid UUID of organization, even if parameter {@code groupId} is not null * @param groupId if null, then anyone, else id of group * @param rootComponentId if null, then global permission, else id of root component (project) */ public void delete(DbSession dbSession, String permission, String organizationUuid, @Nullable Integer groupId, @Nullable Long rootComponentId) { mapper(dbSession).delete(permission, organizationUuid, groupId, rootComponentId); } public void deleteByOrganization(DbSession dbSession, String organizationUuid) { mapper(dbSession).deleteByOrganization(organizationUuid); } private static GroupPermissionMapper mapper(DbSession session) { return session.getMapper(GroupPermissionMapper.class); } }