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

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

There is a newer version: 7.0
Show newest version
/*
 * SonarQube
 * Copyright (C) 2009-2016 SonarSource SA
 * mailto:contact 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 javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.permission.PermissionRepository;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.issue.index.IssueAuthorizationIndexer;
import org.sonar.server.user.UserSession;

import static org.sonar.api.security.DefaultGroups.isAnyone;
import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdminUserByComponentKey;
import static org.sonar.server.permission.ws.PermissionRequestValidator.validateNotAnyoneAndAdminPermission;

public class PermissionUpdater {

  private enum Operation {
    ADD, REMOVE
  }

  private static final String OBJECT_TYPE_USER = "User";
  private static final String OBJECT_TYPE_GROUP = "Group";
  private static final String NOT_FOUND_FORMAT = "%s %s does not exist";

  private final DbClient dbClient;
  private final PermissionRepository permissionRepository;
  private final IssueAuthorizationIndexer issueAuthorizationIndexer;
  private final UserSession userSession;
  private final ComponentFinder componentFinder;

  public PermissionUpdater(DbClient dbClient, PermissionRepository permissionRepository,
    IssueAuthorizationIndexer issueAuthorizationIndexer, UserSession userSession, ComponentFinder componentFinder) {
    this.dbClient = dbClient;
    this.permissionRepository = permissionRepository;
    this.issueAuthorizationIndexer = issueAuthorizationIndexer;
    this.userSession = userSession;
    this.componentFinder = componentFinder;
  }

  public static List globalPermissions() {
    return GlobalPermissions.ALL;
  }

  public void addPermission(PermissionChange change) {
    DbSession session = dbClient.openSession(false);
    try {
      applyChange(Operation.ADD, change, session);
    } finally {
      dbClient.closeSession(session);
    }
  }

  public void removePermission(PermissionChange change) {
    DbSession session = dbClient.openSession(false);
    try {
      applyChange(Operation.REMOVE, change, session);
    } finally {
      session.close();
    }
  }

  private void applyChange(Operation operation, PermissionChange change, DbSession session) {
    userSession.checkLoggedIn();
    change.validate();
    boolean changed;
    if (change.userLogin() != null) {
      changed = applyChangeOnUser(session, operation, change);
    } else {
      changed = applyChangeOnGroup(session, operation, change);
    }
    if (changed) {
      session.commit();
      if (change.componentKey() != null) {
        indexProjectPermissions();
      }
    }
  }

  private boolean applyChangeOnGroup(DbSession session, Operation operation, PermissionChange permissionChange) {
    Long componentId = getComponentId(session, permissionChange.componentKey());
    checkProjectAdminUserByComponentKey(userSession, permissionChange.componentKey());

    List existingPermissions = dbClient.roleDao().selectGroupPermissions(session, permissionChange.groupName(), componentId);
    if (shouldSkipPermissionChange(operation, existingPermissions, permissionChange)) {
      return false;
    }

    Long targetedGroup = getTargetedGroup(session, permissionChange.groupName());
    String permission = permissionChange.permission();
    if (Operation.ADD == operation) {
      validateNotAnyoneAndAdminPermission(permission, permissionChange.groupName());
      permissionRepository.insertGroupPermission(componentId, targetedGroup, permission, session);
    } else {
      checkAdminUsersExistOutsideTheRemovedGroup(session, permissionChange, targetedGroup);
      permissionRepository.deleteGroupPermission(componentId, targetedGroup, permission, session);
    }
    return true;
  }

  private boolean applyChangeOnUser(DbSession session, Operation operation, PermissionChange permissionChange) {
    Long componentId = getComponentId(session, permissionChange.componentKey());
    checkProjectAdminUserByComponentKey(userSession, permissionChange.componentKey());

    List existingPermissions = dbClient.roleDao().selectUserPermissions(session, permissionChange.userLogin(), componentId);
    if (shouldSkipPermissionChange(operation, existingPermissions, permissionChange)) {
      return false;
    }

    Long targetedUser = getTargetedUser(session, permissionChange.userLogin());
    if (Operation.ADD == operation) {
      permissionRepository.insertUserPermission(componentId, targetedUser, permissionChange.permission(), session);
    } else {
      checkOtherAdminUsersExist(session, permissionChange);
      permissionRepository.deleteUserPermission(componentId, targetedUser, permissionChange.permission(), session);
    }
    return true;

  }

  private void checkOtherAdminUsersExist(DbSession session, PermissionChange permissionChange) {
    if (GlobalPermissions.SYSTEM_ADMIN.equals(permissionChange.permission())
      && permissionChange.componentKey() == null
      && dbClient.roleDao().countUserPermissions(session, permissionChange.permission(), null) <= 1) {
      throw new BadRequestException(String.format("Last user with '%s' permission. Permission cannot be removed.", GlobalPermissions.SYSTEM_ADMIN));
    }
  }

  private void checkAdminUsersExistOutsideTheRemovedGroup(DbSession session, PermissionChange permissionChange, @Nullable Long groupIdToExclude) {
    if (GlobalPermissions.SYSTEM_ADMIN.equals(permissionChange.permission())
      && groupIdToExclude != null
      && permissionChange.componentKey() == null
      && dbClient.roleDao().countUserPermissions(session, permissionChange.permission(), groupIdToExclude) <= 0) {
      throw new BadRequestException(String.format("Last group with '%s' permission. Permission cannot be removed.", GlobalPermissions.SYSTEM_ADMIN));
    }
  }

  private Long getTargetedUser(DbSession session, String userLogin) {
    UserDto user = dbClient.userDao().selectActiveUserByLogin(session, userLogin);
    badRequestIfNullResult(user, OBJECT_TYPE_USER, userLogin);
    return user.getId();
  }

  @Nullable
  private Long getTargetedGroup(DbSession session, String group) {
    if (isAnyone(group)) {
      return null;
    } else {
      GroupDto groupDto = dbClient.groupDao().selectByName(session, group);
      badRequestIfNullResult(groupDto, OBJECT_TYPE_GROUP, group);
      return groupDto.getId();
    }
  }

  private static boolean shouldSkipPermissionChange(Operation operation, List existingPermissions, PermissionChange permissionChange) {
    return (Operation.ADD == operation && existingPermissions.contains(permissionChange.permission())) ||
      (Operation.REMOVE == operation && !existingPermissions.contains(permissionChange.permission()));
  }

  @CheckForNull
  private Long getComponentId(DbSession session, @Nullable String componentKey) {
    if (componentKey == null) {
      return null;
    } else {
      ComponentDto component = componentFinder.getByKey(session, componentKey);
      return component.getId();
    }
  }

  private static Object badRequestIfNullResult(@Nullable Object component, String objectType, String objectKey) {
    if (component == null) {
      throw new BadRequestException(String.format(NOT_FOUND_FORMAT, objectType, objectKey));
    }
    return component;
  }

  private void indexProjectPermissions() {
    issueAuthorizationIndexer.index();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy