All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.server.permission.UserPermissionChanger Maven / Gradle / Ivy

There is a newer version: 7.2.1
Show newest version
/*
 * SonarQube
 * Copyright (C) 2009-2018 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.server.permission;

import java.util.List;
import java.util.Optional;
import org.sonar.core.permission.ProjectPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.permission.UserPermissionDto;

import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.server.permission.PermissionChange.Operation.ADD;
import static org.sonar.server.permission.PermissionChange.Operation.REMOVE;
import static org.sonar.server.ws.WsUtils.checkRequest;

/**
 * Adds and removes user permissions. Both global and project scopes are supported.
 */
public class UserPermissionChanger {

  private final DbClient dbClient;

  public UserPermissionChanger(DbClient dbClient) {
    this.dbClient = dbClient;
  }

  public boolean apply(DbSession dbSession, UserPermissionChange change) {
    ensureConsistencyWithVisibility(change);
    if (isImplicitlyAlreadyDone(change)) {
      return false;
    }
    switch (change.getOperation()) {
      case ADD:
        return addPermission(dbSession, change);
      case REMOVE:
        return removePermission(dbSession, change);
      default:
        throw new UnsupportedOperationException("Unsupported permission change: " + change.getOperation());
    }
  }

  private static boolean isImplicitlyAlreadyDone(UserPermissionChange change) {
    return change.getProjectId()
      .map(projectId -> isImplicitlyAlreadyDone(projectId, change))
      .orElse(false);
  }

  private static boolean isImplicitlyAlreadyDone(ProjectId projectId, UserPermissionChange change) {
    return isAttemptToAddPublicPermissionToPublicComponent(change, projectId);
  }

  private static boolean isAttemptToAddPublicPermissionToPublicComponent(UserPermissionChange change, ProjectId projectId) {
    return !projectId.isPrivate()
      && change.getOperation() == ADD
      && ProjectPermissions.PUBLIC_PERMISSIONS.contains(change.getPermission());
  }

  private static void ensureConsistencyWithVisibility(UserPermissionChange change) {
    change.getProjectId()
      .ifPresent(projectId -> checkRequest(
        !isAttemptToRemovePublicPermissionFromPublicComponent(change, projectId),
        "Permission %s can't be removed from a public component", change.getPermission()));
  }

  private static boolean isAttemptToRemovePublicPermissionFromPublicComponent(UserPermissionChange change, ProjectId projectId) {
    return !projectId.isPrivate()
      && change.getOperation() == REMOVE
      && ProjectPermissions.PUBLIC_PERMISSIONS.contains(change.getPermission());
  }

  private boolean addPermission(DbSession dbSession, UserPermissionChange change) {
    if (loadExistingPermissions(dbSession, change).contains(change.getPermission())) {
      return false;
    }
    UserPermissionDto dto = new UserPermissionDto(change.getOrganizationUuid(), change.getPermission(), change.getUserId().getId(), change.getNullableProjectId());
    dbClient.userPermissionDao().insert(dbSession, dto);
    return true;
  }

  private boolean removePermission(DbSession dbSession, UserPermissionChange change) {
    if (!loadExistingPermissions(dbSession, change).contains(change.getPermission())) {
      return false;
    }
    checkOtherAdminsExist(dbSession, change);
    Optional projectId = change.getProjectId();
    if (projectId.isPresent()) {
      dbClient.userPermissionDao().deleteProjectPermission(dbSession, change.getUserId().getId(), change.getPermission(), projectId.get().getId());
    } else {
      dbClient.userPermissionDao().deleteGlobalPermission(dbSession, change.getUserId().getId(), change.getPermission(), change.getOrganizationUuid());
    }
    return true;
  }

  private List loadExistingPermissions(DbSession dbSession, UserPermissionChange change) {
    Optional projectId = change.getProjectId();
    if (projectId.isPresent()) {
      return dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession,
        change.getUserId().getId(),
        projectId.get().getId());
    }
    return dbClient.userPermissionDao().selectGlobalPermissionsOfUser(dbSession,
      change.getUserId().getId(),
      change.getOrganizationUuid());
  }

  private void checkOtherAdminsExist(DbSession dbSession, UserPermissionChange change) {
    if (SYSTEM_ADMIN.equals(change.getPermission()) && !change.getProjectId().isPresent()) {
      int remaining = dbClient.authorizationDao().countUsersWithGlobalPermissionExcludingUserPermission(dbSession,
        change.getOrganizationUuid(), change.getPermission(), change.getUserId().getId());
      checkRequest(remaining > 0, "Last user with permission '%s'. Permission cannot be removed.", SYSTEM_ADMIN);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy