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

org.sonar.server.permission.index.PermissionIndexerDao Maven / Gradle / Ivy

There is a newer version: 7.2.1
Show newest version
/*
 * 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.server.permission.index;

import com.google.common.collect.ImmutableList;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;

import static org.apache.commons.lang.StringUtils.repeat;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;

/**
 * No streaming because of union of joins -> no need to use ResultSetIterator
 */
public class PermissionIndexerDao {

  public static final class Dto {
    private final String projectUuid;
    private final String qualifier;
    private final List userIds = new ArrayList<>();
    private final List groupIds = new ArrayList<>();
    private boolean allowAnyone = false;

    public Dto(String projectUuid, String qualifier) {
      this.projectUuid = projectUuid;
      this.qualifier = qualifier;
    }

    public String getProjectUuid() {
      return projectUuid;
    }

    public String getQualifier() {
      return qualifier;
    }

    public List getUserIds() {
      return userIds;
    }

    public Dto addUserId(int l) {
      userIds.add(l);
      return this;
    }

    public Dto addGroupId(int id) {
      groupIds.add(id);
      return this;
    }

    public List getGroupIds() {
      return groupIds;
    }

    public void allowAnyone() {
      this.allowAnyone = true;
    }

    public boolean isAllowAnyone() {
      return allowAnyone;
    }
  }

  private enum RowKind {
    USER, GROUP, ANYONE, NONE
  }

  private static final String SQL_TEMPLATE = "SELECT " +
    "  project_authorization.kind as kind, " +
    "  project_authorization.project as project, " +
    "  project_authorization.user_id as user_id, " +
    "  project_authorization.group_id as group_id, " +
    "  project_authorization.qualifier as qualifier " +
    "FROM ( " +

    // users

    "      SELECT '" + RowKind.USER + "' as kind," +
    "      projects.uuid AS project, " +
    "      projects.qualifier AS qualifier, " +
    "      user_roles.user_id  AS user_id, " +
    "      NULL  AS group_id " +
    "      FROM projects " +
    "      INNER JOIN user_roles ON user_roles.resource_id = projects.id AND user_roles.role = 'user' " +
    "      WHERE " +
    "        (projects.qualifier = 'TRK' " +
    "         or  projects.qualifier = 'VW' " +
    "         or  projects.qualifier = 'APP') " +
    "        AND projects.copy_component_uuid is NULL " +
    "        {projectsCondition} " +
    "      UNION " +

    // groups

    "      SELECT '" + RowKind.GROUP + "' as kind," +
    "      projects.uuid AS project, " +
    "      projects.qualifier AS qualifier, " +
    "      NULL  AS user_id, " +
    "      groups.id  AS group_id " +
    "      FROM projects " +
    "      INNER JOIN group_roles ON group_roles.resource_id = projects.id AND group_roles.role = 'user' " +
    "      INNER JOIN groups ON groups.id = group_roles.group_id " +
    "      WHERE " +
    "        (projects.qualifier = 'TRK' " +
    "         or  projects.qualifier = 'VW' " +
    "         or  projects.qualifier = 'APP') " +
    "        AND projects.copy_component_uuid is NULL " +
    "        {projectsCondition} " +
    "        AND group_id IS NOT NULL " +
    "      UNION " +

    // public projects are accessible to any one

    "      SELECT '" + RowKind.ANYONE + "' as kind," +
    "      projects.uuid AS project, " +
    "      projects.qualifier AS qualifier, " +
    "      NULL         AS user_id, " +
    "      NULL     AS group_id " +
    "      FROM projects " +
    "      WHERE " +
    "        (projects.qualifier = 'TRK' " +
    "         or  projects.qualifier = 'VW' " +
    "         or  projects.qualifier = 'APP') " +
    "        AND projects.copy_component_uuid is NULL " +
    "        AND projects.private = ? " +
    "        {projectsCondition} " +
    "      UNION " +

    // private project is returned when no authorization
    "      SELECT '" + RowKind.NONE + "' as kind," +
    "      projects.uuid AS project, " +
    "      projects.qualifier AS qualifier, " +
    "      NULL AS user_id, " +
    "      NULL  AS group_id " +
    "      FROM projects " +
    "      WHERE " +
    "        (projects.qualifier = 'TRK' " +
    "         or  projects.qualifier = 'VW' " +
    "         or  projects.qualifier = 'APP') " +
    "        AND projects.copy_component_uuid is NULL " +
    "        AND projects.private = ? " +
    "        {projectsCondition} " +

    "    ) project_authorization";

  List selectAll(DbClient dbClient, DbSession session) {
    return doSelectByProjects(dbClient, session, Collections.emptyList());
  }

  List selectByUuids(DbClient dbClient, DbSession session, Collection projectOrViewUuids) {
    return executeLargeInputs(projectOrViewUuids, subProjectOrViewUuids -> doSelectByProjects(dbClient, session, subProjectOrViewUuids));
  }

  private static List doSelectByProjects(DbClient dbClient, DbSession session, List projectUuids) {
    try {
      Map dtosByProjectUuid = new HashMap<>();
      try (PreparedStatement stmt = createStatement(dbClient, session, projectUuids);
        ResultSet rs = stmt.executeQuery()) {
        while (rs.next()) {
          processRow(rs, dtosByProjectUuid);
        }
        return ImmutableList.copyOf(dtosByProjectUuid.values());
      }
    } catch (SQLException e) {
      throw new IllegalStateException("Fail to select authorizations", e);
    }
  }

  private static PreparedStatement createStatement(DbClient dbClient, DbSession session, List projectUuids) throws SQLException {
    String sql;
    if (projectUuids.isEmpty()) {
      sql = StringUtils.replace(SQL_TEMPLATE, "{projectsCondition}", "");
    } else {
      sql = StringUtils.replace(SQL_TEMPLATE, "{projectsCondition}", " AND (" + repeat("projects.uuid = ?", " or ", projectUuids.size()) + ")");
    }
    PreparedStatement stmt = dbClient.getMyBatis().newScrollingSelectStatement(session, sql);
    int index = 1;
    // query for RowKind.USER
    index = populateProjectUuidPlaceholders(stmt, projectUuids, index);
    // query for RowKind.GROUP
    index = populateProjectUuidPlaceholders(stmt, projectUuids, index);
    // query for RowKind.ANYONE
    index = setPrivateProjectPlaceHolder(stmt, index, false);
    index = populateProjectUuidPlaceholders(stmt, projectUuids, index);
    // query for RowKind.NONE
    index = setPrivateProjectPlaceHolder(stmt, index, true);
    populateProjectUuidPlaceholders(stmt, projectUuids, index);
    return stmt;
  }

  private static int populateProjectUuidPlaceholders(PreparedStatement stmt, List projectUuids, int index) throws SQLException {
    int newIndex = index;
    for (String projectUuid : projectUuids) {
      stmt.setString(newIndex, projectUuid);
      newIndex++;
    }
    return newIndex;
  }

  private static int setPrivateProjectPlaceHolder(PreparedStatement stmt, int index, boolean isPrivate) throws SQLException {
    int newIndex = index;
    stmt.setBoolean(newIndex, isPrivate);
    newIndex++;
    return newIndex;
  }

  private static void processRow(ResultSet rs, Map dtosByProjectUuid) throws SQLException {
    RowKind rowKind = RowKind.valueOf(rs.getString(1));
    String projectUuid = rs.getString(2);

    Dto dto = dtosByProjectUuid.get(projectUuid);
    if (dto == null) {
      String qualifier = rs.getString(5);
      dto = new Dto(projectUuid, qualifier);
      dtosByProjectUuid.put(projectUuid, dto);
    }
    switch (rowKind) {
      case NONE:
        break;
      case USER:
        dto.addUserId(rs.getInt(3));
        break;
      case GROUP:
        dto.addGroupId(rs.getInt(4));
        break;
      case ANYONE:
        dto.allowAnyone();
        break;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy