]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8263 isolate organizations when removing user permissions
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Wed, 19 Oct 2016 14:04:34 +0000 (16:04 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Thu, 20 Oct 2016 13:10:12 +0000 (15:10 +0200)
15 files changed:
server/sonar-server/src/main/java/org/sonar/server/permission/UserId.java
server/sonar-server/src/main/java/org/sonar/server/permission/UserPermissionChanger.java
server/sonar-server/src/test/java/org/sonar/server/permission/GroupPermissionChangerTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/UserPermissionChangerTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/permission/ws/AddUserActionTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/RemoveUserActionTest.java
sonar-db/src/main/java/org/sonar/db/permission/AuthorizationDao.java
sonar-db/src/main/java/org/sonar/db/permission/AuthorizationMapper.java
sonar-db/src/main/java/org/sonar/db/permission/UserPermissionDao.java
sonar-db/src/main/java/org/sonar/db/permission/UserPermissionMapper.java
sonar-db/src/main/resources/org/sonar/db/permission/AuthorizationMapper.xml
sonar-db/src/main/resources/org/sonar/db/permission/UserPermissionMapper.xml
sonar-db/src/test/java/org/sonar/db/permission/PermissionRepositoryTest.java
sonar-db/src/test/java/org/sonar/db/permission/UserPermissionDaoTest.java
sonar-db/src/test/java/org/sonar/db/user/UserDbTester.java

index 52c348fd12e7c3d80f6e60f7c705d8e032438536..e38fef44ae71a75698cb5fad679c5f82be4bf8ed 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.permission;
 
 import javax.annotation.concurrent.Immutable;
+import org.sonar.db.user.UserDto;
 
 import static java.util.Objects.requireNonNull;
 
@@ -46,4 +47,8 @@ public class UserId {
   public String getLogin() {
     return login;
   }
+
+  public static UserId from(UserDto dto) {
+    return new UserId(dto.getId(), dto.getLogin());
+  }
 }
index 782d2c503f96290d27d87da66d68e388449386ca..c8d397b78e7776e1a5fa9aa8c7387ea7ee869834 100644 (file)
  */
 package org.sonar.server.permission;
 
+import java.util.List;
 import java.util.Optional;
-import java.util.Set;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.permission.UserPermissionDto;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.organization.DefaultOrganizationProvider;
-import org.sonar.server.permission.PermissionChange.Operation;
 
 import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
 
+/**
+ * Adds and removes user permissions. Both global and project scopes are supported.
+ */
 public class UserPermissionChanger {
 
   private final DbClient dbClient;
@@ -41,44 +43,66 @@ public class UserPermissionChanger {
   }
 
   public boolean apply(DbSession dbSession, UserPermissionChange change) {
-    if (shouldSkipChange(dbSession, change)) {
-      return false;
-    }
-
     switch (change.getOperation()) {
       case ADD:
-        UserPermissionDto dto = new UserPermissionDto(change.getOrganizationUuid(), change.getPermission(), change.getUserId().getId(), change.getNullableProjectId());
-        dbClient.userPermissionDao().insert(dbSession, dto);
-        break;
+        return addPermission(dbSession, change);
       case REMOVE:
-        checkOtherAdminUsersExist(dbSession, change);
-        Optional<ProjectId> 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());
-        }
-        break;
+        return removePermission(dbSession, change);
       default:
         throw new UnsupportedOperationException("Unsupported permission change: " + change.getOperation());
     }
-    if (SYSTEM_ADMIN.equals(change.getPermission()) && !change.getProjectId().isPresent()) {
-      dbClient.userDao().updateRootFlagFromPermissions(dbSession, change.getUserId().getId(), defaultOrganizationProvider.get().getUuid());
+  }
+
+  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);
+    updateRootFlag(dbSession, change);
+    return true;
+  }
+
+  private boolean removePermission(DbSession dbSession, UserPermissionChange change) {
+    if (!loadExistingPermissions(dbSession, change).contains(change.getPermission())) {
+      return false;
     }
+    checkOtherAdminsExist(dbSession, change);
+    Optional<ProjectId> 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());
+    }
+    updateRootFlag(dbSession, change);
     return true;
   }
 
-  private boolean shouldSkipChange(DbSession dbSession, UserPermissionChange change) {
-    Set<String> existingPermissions = dbClient.userPermissionDao().selectPermissionsByLogin(dbSession, change.getUserId().getLogin(), change.getProjectUuid());
-    return (Operation.ADD == change.getOperation() && existingPermissions.contains(change.getPermission())) ||
-      (Operation.REMOVE == change.getOperation() && !existingPermissions.contains(change.getPermission()));
+  private List<String> loadExistingPermissions(DbSession dbSession, UserPermissionChange change) {
+    Optional<ProjectId> 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 checkOtherAdminUsersExist(DbSession session, PermissionChange change) {
-    if (SYSTEM_ADMIN.equals(change.getPermission()) &&
-      !change.getProjectId().isPresent() &&
-      dbClient.roleDao().countUserPermissions(session, change.getPermission(), null) <= 1) {
-      throw new BadRequestException(String.format("Last user with '%s' permission. Permission cannot be removed.", SYSTEM_ADMIN));
+  private void checkOtherAdminsExist(DbSession dbSession, UserPermissionChange change) {
+    if (SYSTEM_ADMIN.equals(change.getPermission()) && !change.getProjectId().isPresent()) {
+      int remaining = dbClient.authorizationDao().countRemainingUsersWithGlobalPermissionExcludingUser(dbSession,
+        change.getOrganizationUuid(), change.getPermission(), change.getUserId().getId());
+      if (remaining == 0) {
+        throw new BadRequestException(String.format("Last user with permission '%s'. Permission cannot be removed.", SYSTEM_ADMIN));
+      }
+    }
+  }
+
+  private void updateRootFlag(DbSession dbSession, UserPermissionChange change) {
+    if (SYSTEM_ADMIN.equals(change.getPermission()) && !change.getProjectId().isPresent()) {
+      dbClient.userDao().updateRootFlagFromPermissions(dbSession, change.getUserId().getId(), defaultOrganizationProvider.get().getUuid());
     }
   }
 }
index d807db7531ea0f38424d8f34a55b6aeb35cec53c..423151a26d8d2953f2b4e8ebd75bb2e5d8abd29c 100644 (file)
@@ -27,9 +27,7 @@ import org.sonar.api.utils.System2;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.db.DbTester;
-import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentTesting;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDto;
@@ -55,7 +53,7 @@ public class GroupPermissionChangerTest {
   public void setUp() throws Exception {
     org = db.organizations().insert();
     group = db.users().insertGroup(org, "a-group");
-    project = new ComponentDbTester(db).insertComponent(ComponentTesting.newProjectDto());
+    project = db.components().insertProject();
   }
 
   @Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/UserPermissionChangerTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/UserPermissionChangerTest.java
new file mode 100644 (file)
index 0000000..19fb943
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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 org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.organization.OrganizationTesting;
+import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.exceptions.BadRequestException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
+import static org.sonar.api.web.UserRole.USER;
+import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN;
+import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;
+import static org.sonar.server.permission.PermissionChange.Operation.ADD;
+import static org.sonar.server.permission.PermissionChange.Operation.REMOVE;
+
+
+public class UserPermissionChangerTest {
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private UserPermissionChanger underTest = new UserPermissionChanger(db.getDbClient());
+  private OrganizationDto org1;
+  private OrganizationDto org2;
+  private UserDto user1;
+  private UserDto user2;
+  private ComponentDto project;
+
+  @Before
+  public void setUp() throws Exception {
+    org1 = OrganizationTesting.insert(db, newOrganizationDto());
+    org2 = OrganizationTesting.insert(db, newOrganizationDto());
+    user1 = db.users().insertUser();
+    user2 = db.users().insertUser();
+    project = db.components().insertProject();
+  }
+
+  @Test
+  public void add_global_permission_to_user() {
+    UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), SCAN_EXECUTION, null, UserId.from(user1));
+    apply(change);
+
+    assertThat(db.users().selectGlobalPermissionsOfUser(user1, org1)).containsOnly(SCAN_EXECUTION);
+    assertThat(db.users().selectGlobalPermissionsOfUser(user1, org2)).isEmpty();
+    assertThat(db.users().selectProjectPermissionsOfUser(user1, project)).isEmpty();
+    assertThat(db.users().selectGlobalPermissionsOfUser(user2, org1)).isEmpty();
+    assertThat(db.users().selectProjectPermissionsOfUser(user2, project)).isEmpty();
+  }
+
+  @Test
+  public void add_project_permission_to_user() {
+    UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), ISSUE_ADMIN, new ProjectId(project), UserId.from(user1));
+    apply(change);
+
+    assertThat(db.users().selectGlobalPermissionsOfUser(user1, org1)).isEmpty();
+    assertThat(db.users().selectProjectPermissionsOfUser(user1, project)).contains(ISSUE_ADMIN);
+    assertThat(db.users().selectGlobalPermissionsOfUser(user2, org1)).isEmpty();
+    assertThat(db.users().selectProjectPermissionsOfUser(user2, project)).isEmpty();
+  }
+
+  @Test
+  public void do_nothing_when_adding_global_permission_that_already_exists() {
+    db.users().insertPermissionOnUser(org1, user1, QUALITY_GATE_ADMIN);
+
+    UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), QUALITY_GATE_ADMIN, null, UserId.from(user1));
+    apply(change);
+
+    assertThat(db.users().selectGlobalPermissionsOfUser(user1, org1)).hasSize(1).containsOnly(QUALITY_GATE_ADMIN);
+  }
+
+  @Test
+  public void fail_to_add_global_permission_on_project() {
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("Invalid project permission 'gateadmin'. Valid values are [admin, codeviewer, issueadmin, scan, user]");
+
+    UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), QUALITY_GATE_ADMIN, new ProjectId(project), UserId.from(user1));
+    apply(change);
+  }
+
+  @Test
+  public void fail_to_add_project_permission_on_organization() {
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("Invalid global permission 'issueadmin'. Valid values are [admin, profileadmin, gateadmin, scan, provisioning]");
+
+    UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), ISSUE_ADMIN, null, UserId.from(user1));
+    apply(change);
+  }
+
+  @Test
+  public void remove_global_permission_from_user() {
+    db.users().insertPermissionOnUser(org1, user1, QUALITY_GATE_ADMIN);
+    db.users().insertPermissionOnUser(org1, user1, SCAN_EXECUTION);
+    db.users().insertPermissionOnUser(org2, user1, QUALITY_GATE_ADMIN);
+    db.users().insertPermissionOnUser(org1, user2, QUALITY_GATE_ADMIN);
+    db.users().insertProjectPermissionOnUser(org1, user1, ISSUE_ADMIN, project);
+
+    UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), QUALITY_GATE_ADMIN, null, UserId.from(user1));
+    apply(change);
+
+    assertThat(db.users().selectGlobalPermissionsOfUser(user1, org1)).containsOnly(SCAN_EXECUTION);
+    assertThat(db.users().selectGlobalPermissionsOfUser(user1, org2)).containsOnly(QUALITY_GATE_ADMIN);
+    assertThat(db.users().selectGlobalPermissionsOfUser(user2, org1)).containsOnly(QUALITY_GATE_ADMIN);
+    assertThat(db.users().selectProjectPermissionsOfUser(user1, project)).containsOnly(ISSUE_ADMIN);
+  }
+
+  @Test
+  public void remove_project_permission_from_user() {
+    ComponentDto project2 = db.components().insertProject();
+    db.users().insertPermissionOnUser(org1, user1, QUALITY_GATE_ADMIN);
+    db.users().insertProjectPermissionOnUser(org1, user1, ISSUE_ADMIN, project);
+    db.users().insertProjectPermissionOnUser(org1, user1, USER, project);
+    db.users().insertProjectPermissionOnUser(org1, user2, ISSUE_ADMIN, project);
+    db.users().insertProjectPermissionOnUser(org1, user1, ISSUE_ADMIN, project2);
+
+    UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), ISSUE_ADMIN, new ProjectId(project), UserId.from(user1));
+    apply(change);
+
+    assertThat(db.users().selectProjectPermissionsOfUser(user1, project)).containsOnly(USER);
+    assertThat(db.users().selectProjectPermissionsOfUser(user2, project)).containsOnly(ISSUE_ADMIN);
+    assertThat(db.users().selectProjectPermissionsOfUser(user1, project2)).containsOnly(ISSUE_ADMIN);
+  }
+
+  @Test
+  public void do_not_fail_if_removing_a_global_permission_that_does_not_exist() {
+    UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), QUALITY_GATE_ADMIN, null, UserId.from(user1));
+    apply(change);
+
+    assertThat(db.users().selectGlobalPermissionsOfUser(user1, org1)).isEmpty();
+  }
+
+  @Test
+  public void do_not_fail_if_removing_a_project_permission_that_does_not_exist() {
+    UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), ISSUE_ADMIN, new ProjectId(project), UserId.from(user1));
+    apply(change);
+
+    assertThat(db.users().selectProjectPermissionsOfUser(user1, project)).isEmpty();
+  }
+
+  @Test
+  public void fail_to_remove_admin_global_permission_if_no_more_admins() {
+    db.users().insertPermissionOnUser(org1, user1, SYSTEM_ADMIN);
+
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("Last user with permission 'admin'. Permission cannot be removed.");
+
+    UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), SYSTEM_ADMIN, null, UserId.from(user1));
+    underTest.apply(db.getSession(), change);
+  }
+
+  @Test
+  public void remove_admin_user_if_still_other_admins() {
+    db.users().insertPermissionOnUser(org1, user1, SYSTEM_ADMIN);
+    GroupDto admins = db.users().insertGroup(org1, "admins");
+    db.users().insertMember(admins, user2);
+    db.users().insertPermissionOnGroup(admins, SYSTEM_ADMIN);
+
+    UserPermissionChange change = new UserPermissionChange(REMOVE, org1.getUuid(), SYSTEM_ADMIN, null, UserId.from(user1));
+    underTest.apply(db.getSession(), change);
+
+    assertThat(db.users().selectGlobalPermissionsOfUser(user1, org1)).isEmpty();
+  }
+
+  private void apply(UserPermissionChange change) {
+    underTest.apply(db.getSession(), change);
+    db.commit();
+  }
+}
index c51a3c2a508fbcabc3fb28f703a7017055fbab58..f0ada10870f0748995e40facc9131d49b5dd1338 100644 (file)
@@ -68,7 +68,7 @@ public class AddUserActionTest extends BasePermissionWsTest<AddUserAction> {
       .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
       .execute();
 
-    assertThat(db.users().selectUserPermissions(user, null)).containsOnly(SYSTEM_ADMIN);
+    assertThat(db.users().selectGlobalPermissionsOfUser(user, db.getDefaultOrganization())).containsOnly(SYSTEM_ADMIN);
   }
 
   @Test
@@ -82,8 +82,8 @@ public class AddUserActionTest extends BasePermissionWsTest<AddUserAction> {
       .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
       .execute();
 
-    assertThat(db.users().selectUserPermissions(user, null)).isEmpty();
-    assertThat(db.users().selectUserPermissions(user, project)).containsOnly(SYSTEM_ADMIN);
+    assertThat(db.users().selectGlobalPermissionsOfUser(user, db.getDefaultOrganization())).isEmpty();
+    assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(SYSTEM_ADMIN);
   }
 
   @Test
@@ -97,8 +97,8 @@ public class AddUserActionTest extends BasePermissionWsTest<AddUserAction> {
       .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
       .execute();
 
-    assertThat(db.users().selectUserPermissions(user, null)).isEmpty();
-    assertThat(db.users().selectUserPermissions(user, project)).containsOnly(SYSTEM_ADMIN);
+    assertThat(db.users().selectGlobalPermissionsOfUser(user, db.getDefaultOrganization())).isEmpty();
+    assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(SYSTEM_ADMIN);
   }
 
   @Test
@@ -112,8 +112,8 @@ public class AddUserActionTest extends BasePermissionWsTest<AddUserAction> {
       .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
       .execute();
 
-    assertThat(db.users().selectUserPermissions(user, null)).isEmpty();
-    assertThat(db.users().selectUserPermissions(user, view)).containsOnly(SYSTEM_ADMIN);
+    assertThat(db.users().selectGlobalPermissionsOfUser(user, db.getDefaultOrganization())).isEmpty();
+    assertThat(db.users().selectProjectPermissionsOfUser(user, view)).containsOnly(SYSTEM_ADMIN);
   }
 
   @Test
@@ -246,7 +246,7 @@ public class AddUserActionTest extends BasePermissionWsTest<AddUserAction> {
       .setParam(PARAM_PERMISSION, UserRole.ISSUE_ADMIN)
       .execute();
 
-    assertThat(db.users().selectUserPermissions(user, project)).containsOnly(ISSUE_ADMIN);
+    assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(ISSUE_ADMIN);
   }
 
   @Test
index 5f2efcfedc2dda3d1869580ced402aa8038418ca..feffda0235753d7988a6a1b43bdf8e80adcabf29 100644 (file)
@@ -77,7 +77,7 @@ public class RemoveUserActionTest extends BasePermissionWsTest<RemoveUserAction>
       .setParam(PARAM_PERMISSION, QUALITY_GATE_ADMIN)
       .execute();
 
-    assertThat(db.users().selectUserPermissions(user, null)).containsOnly(PROVISIONING);
+    assertThat(db.users().selectGlobalPermissionsOfUser(user, db.getDefaultOrganization())).containsOnly(PROVISIONING);
   }
 
   @Test
@@ -87,7 +87,7 @@ public class RemoveUserActionTest extends BasePermissionWsTest<RemoveUserAction>
     loginAsAdminOnDefaultOrganization();
 
     expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("Last user with 'admin' permission. Permission cannot be removed.");
+    expectedException.expectMessage("Last user with permission 'admin'. Permission cannot be removed.");
 
     wsTester.newPostRequest(CONTROLLER, ACTION)
       .setParam(PARAM_USER_LOGIN, user.getLogin())
@@ -108,7 +108,7 @@ public class RemoveUserActionTest extends BasePermissionWsTest<RemoveUserAction>
       .setParam(PARAM_PERMISSION, CODEVIEWER)
       .execute();
 
-    assertThat(db.users().selectUserPermissions(user, project)).containsOnly(ISSUE_ADMIN);
+    assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(ISSUE_ADMIN);
   }
 
   @Test
@@ -124,7 +124,7 @@ public class RemoveUserActionTest extends BasePermissionWsTest<RemoveUserAction>
       .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
       .execute();
 
-    assertThat(db.users().selectUserPermissions(user, project)).containsOnly(CODEVIEWER);
+    assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(CODEVIEWER);
   }
 
   @Test
@@ -140,7 +140,7 @@ public class RemoveUserActionTest extends BasePermissionWsTest<RemoveUserAction>
       .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
       .execute();
 
-    assertThat(db.users().selectUserPermissions(user, view)).containsOnly(CODEVIEWER);
+    assertThat(db.users().selectProjectPermissionsOfUser(user, view)).containsOnly(CODEVIEWER);
   }
 
   @Test
@@ -329,7 +329,7 @@ public class RemoveUserActionTest extends BasePermissionWsTest<RemoveUserAction>
       .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
       .execute();
 
-    assertThat(db.users().selectUserPermissions(user, project)).containsOnly(CODEVIEWER);
+    assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(CODEVIEWER);
   }
 
 }
index dc6677e63d12183be14769957d7c92108ee36388..c85bf9732d073eb2d5668d8ad9189c0bd733713d 100644 (file)
@@ -79,13 +79,22 @@ public class AuthorizationDao implements Dao {
 
   /**
    * The number of users who will still have the permission when the group {@code excludedGroupId}
-   * is deleted.
+   * is deleted. The anyone virtual group is not taken into account.
    */
   public int countRemainingUserIdsWithGlobalPermissionIfExcludeGroup(DbSession dbSession, String organizationUuid,
     String permission, long excludedGroupId) {
     return mapper(dbSession).countRemainingUserIdsWithGlobalPermissionIfExcludeGroup(organizationUuid, permission, excludedGroupId);
   }
 
+  /**
+   * The number of users who will still have the permission when the user {@code excludedUserId}
+   * is deleted. The anyone virtual group is not taken into account.
+   */
+  public int countRemainingUsersWithGlobalPermissionExcludingUser(DbSession dbSession, String organizationUuid,
+                                                                  String permission, long excludedUSerId) {
+    return mapper(dbSession).countRemainingUsersWithGlobalPermissionExcludingUser(organizationUuid, permission, excludedUSerId);
+  }
+
   public Collection<Long> keepAuthorizedProjectIds(DbSession dbSession, Collection<Long> componentIds, @Nullable Integer userId, String role) {
     return executeLargeInputs(
       componentIds,
index dc422f10476da9246fec94cebf4f82d89ddde216..0d83a18acbdc96dbc93c642fd8946b36d3c0c855 100644 (file)
@@ -39,6 +39,8 @@ public interface AuthorizationMapper {
 
   int countRemainingUserIdsWithGlobalPermissionIfExcludeGroup(@Param("organizationUuid") String organizationUuid, @Param("permission") String permission, @Param("excludedGroupId") long excludedGroupId);
 
+  int countRemainingUsersWithGlobalPermissionExcludingUser(@Param("organizationUuid") String organizationUuid, @Param("permission") String permission, @Param("excludedUserId") long excludedUserId);
+
   List<Long> keepAuthorizedProjectIdsForAnonymous(@Param("role") String role, @Param("componentIds") Collection<Long> componentIds);
 
   List<Long> keepAuthorizedProjectIdsForUser(@Param("userId") long userId, @Param("role") String role, @Param("componentIds") Collection<Long> componentIds);
index 6772ff8f3ea03e74c5003c674ab26123665df493..bb170254026c9d7052f7f10ba2ba1596f07857e2 100644 (file)
@@ -100,6 +100,24 @@ public class UserPermissionDao implements Dao {
     return mapper(dbSession).countRowsByRootComponentId(rootComponentId) > 0;
   }
 
+  /**
+   * Gets all the global permissions granted to user for the specified organization.
+   *
+   * @return the global permissions. An empty list is returned if user or organization do not exist.
+   */
+  public List<String> selectGlobalPermissionsOfUser(DbSession dbSession, long userId, String organizationUuid) {
+    return mapper(dbSession).selectGlobalPermissionsOfUser(userId, organizationUuid);
+  }
+
+  /**
+   * Gets all the project permissions granted to user for the specified project.
+   *
+   * @return the project permissions. An empty list is returned if project or user do not exist.
+   */
+  public List<String> selectProjectPermissionsOfUser(DbSession dbSession, long userId, long projectId) {
+    return mapper(dbSession).selectProjectPermissionsOfUser(userId, projectId);
+  }
+
   public void insert(DbSession dbSession, UserPermissionDto dto) {
     mapper(dbSession).insert(dto);
   }
index fffc729fac1b37a274345894ea1f1f62acac24a9..1782c2ed49957a8ad155fcce734733f8f7fe70f1 100644 (file)
@@ -60,4 +60,7 @@ public interface UserPermissionMapper {
 
   void deleteProjectPermissions(@Param("projectId") long projectId);
 
+  List<String> selectGlobalPermissionsOfUser(@Param("userId") long userId, @Param("organizationUuid") String organizationUuid);
+
+  List<String> selectProjectPermissionsOfUser(@Param("userId") long userId, @Param("projectId") long projectId);
 }
index 504dc552c31611416964f9624485e702938590ae..28d66d9f5360ccb7c485436e49706f2976407195 100644 (file)
     ) remaining
   </select>
 
+  <select id="countRemainingUsersWithGlobalPermissionExcludingUser" parameterType="map" resultType="int">
+    select count(1) from
+    (
+    select gu.user_id
+    from groups_users gu
+    inner join group_roles gr on gr.group_id = gu.group_id
+    where
+    gr.organization_uuid = #{organizationUuid,jdbcType=VARCHAR} and
+    gr.role = #{permission,jdbcType=VARCHAR} and
+    gr.resource_id is null and
+    gr.group_id is not null
+
+    union
+
+    select ur.user_id
+    from user_roles ur
+    where
+    ur.resource_id is null and
+    ur.role = #{permission,jdbcType=VARCHAR} and
+    ur.user_id != #{excludedUserId,jdbcType=BIGINT}
+    ) remaining
+  </select>
+
   <select id="keepAuthorizedProjectIdsForUser" parameterType="map" resultType="long">
     SELECT gr.resource_id
     FROM group_roles gr
index 248b6f3c99bba4773952ad587c2ca0690740f01a..3e0ee88616ab39f5bfc65bc075259bc36ecec3e0 100644 (file)
     </where>
   </sql>
 
+  <select id="selectGlobalPermissionsOfUser" parameterType="map" resultType="string">
+    select ur.role
+    from user_roles ur
+    where
+    ur.organization_uuid = #{organizationUuid,jdbcType=VARCHAR} and
+    ur.user_id = #{userId,jdbcType=BIGINT} and
+    ur.resource_id is null
+  </select>
+
+  <select id="selectProjectPermissionsOfUser" parameterType="map" resultType="string">
+    select ur.role
+    from user_roles ur
+    where
+    ur.user_id = #{userId,jdbcType=BIGINT} and
+    ur.resource_id = #{projectId,jdbcType=BIGINT}
+  </select>
+
   <select id="countUsersByProjectPermission" resultType="org.sonar.db.permission.CountPerProjectPermission">
     select ur.resource_id as componentId, ur.role as permission, count(u.login) as count
     from users u
index 4b8ea83df2aa4c870ac338be12ae6ce17505e5b5..5d7247fd90a49a7028eaaef957ee4f6740134af6 100644 (file)
@@ -73,11 +73,12 @@ public class PermissionRepositoryTest {
   public void apply_permission_template() {
     dbTester.prepareDbUnit(getClass(), "should_apply_permission_template.xml");
 
+    UserDto marius = dbTester.users().selectUserByLogin("marius").get();
     RoleDao roleDao = dbTester.getDbClient().roleDao();
     assertThat(roleDao.selectGroupPermissions(session, "sonar-administrators", PROJECT.getId())).isEmpty();
     assertThat(roleDao.selectGroupPermissions(session, "sonar-users", PROJECT.getId())).isEmpty();
     assertThat(roleDao.selectGroupPermissions(session, "Anyone", PROJECT.getId())).isEmpty();
-    assertThat(dbTester.getDbClient().userPermissionDao().selectPermissionsByLogin(session, "marius", PROJECT.uuid())).isEmpty();
+    assertThat(dbTester.getDbClient().userPermissionDao().selectProjectPermissionsOfUser(session, marius.getId(), PROJECT.getId())).isEmpty();
 
     PermissionTemplateDto template = dbTester.getDbClient().permissionTemplateDao().selectByUuid(session, "default_20130101_010203");
     underTest.apply(session, template, PROJECT, null);
@@ -85,7 +86,7 @@ public class PermissionRepositoryTest {
     assertThat(roleDao.selectGroupPermissions(session, "sonar-administrators", PROJECT.getId())).containsOnly("admin", "issueadmin");
     assertThat(roleDao.selectGroupPermissions(session, "sonar-users", PROJECT.getId())).containsOnly("user", "codeviewer");
     assertThat(roleDao.selectGroupPermissions(session, "Anyone", PROJECT.getId())).containsOnly("user", "codeviewer");
-    assertThat(dbTester.getDbClient().userPermissionDao().selectPermissionsByLogin(session, "marius", PROJECT.uuid())).containsOnly("admin");
+    assertThat(dbTester.getDbClient().userPermissionDao().selectProjectPermissionsOfUser(session, marius.getId(), PROJECT.getId())).containsOnly("admin");
 
     checkAuthorizationUpdatedAtIsUpdated();
   }
index 52e16f21b43ffe9c55be1c70ea84423244a18d2f..8cfe4d3c5bccd93ce9cc98d3efb01f74857b031f 100644 (file)
@@ -33,6 +33,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.organization.OrganizationTesting;
 import org.sonar.db.user.UserDto;
 
 import static java.util.Arrays.asList;
@@ -42,6 +43,7 @@ import static org.sonar.api.web.UserRole.USER;
 import static org.sonar.core.permission.GlobalPermissions.PROVISIONING;
 import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
 import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;
 import static org.sonar.db.user.UserTesting.newUserDto;
 
 public class UserPermissionDaoTest {
@@ -305,7 +307,6 @@ public class UserPermissionDaoTest {
     assertThatProjectHasNoPermissions(project1);
   }
 
-
   @Test
   public void projectHasPermissions() {
     addGlobalPermissionOnDefaultOrganization(SYSTEM_ADMIN, user1);
@@ -315,6 +316,36 @@ public class UserPermissionDaoTest {
     assertThat(underTest.hasRootComponentPermissions(dbSession, project2.getId())).isFalse();
   }
 
+  @Test
+  public void selectGlobalPermissionsOfUser() {
+    OrganizationDto org = OrganizationTesting.insert(dbTester, newOrganizationDto());
+    addGlobalPermissionOnDefaultOrganization("perm1", user1);
+    addGlobalPermissionOnDefaultOrganization("perm2", user2);
+    addGlobalPermission(org, "perm3", user1);
+    addProjectPermissionOnDefaultOrganization("perm4", user1, project1);
+    addProjectPermission(org, "perm5", user1, project1);
+
+    assertThat(underTest.selectGlobalPermissionsOfUser(dbSession, user1.getId(), org.getUuid())).containsOnly("perm3");
+    assertThat(underTest.selectGlobalPermissionsOfUser(dbSession, user1.getId(), dbTester.getDefaultOrganization().getUuid())).containsOnly("perm1");
+    assertThat(underTest.selectGlobalPermissionsOfUser(dbSession, user1.getId(), "otherOrg")).isEmpty();
+    assertThat(underTest.selectGlobalPermissionsOfUser(dbSession, user3.getId(), org.getUuid())).isEmpty();
+  }
+
+  @Test
+  public void selectProjectPermissionsOfUser() {
+    OrganizationDto org = OrganizationTesting.insert(dbTester, newOrganizationDto());
+    ComponentDto project3 = dbTester.components().insertProject();
+    addGlobalPermission(org, "perm1", user1);
+    addProjectPermission(org, "perm2", user1, project1);
+    addProjectPermission(org, "perm3", user1, project1);
+    addProjectPermission(org, "perm4", user1, project2);
+    addProjectPermission(org, "perm5", user2, project1);
+
+    assertThat(underTest.selectProjectPermissionsOfUser(dbSession, user1.getId(), project1.getId())).containsOnly("perm2", "perm3");
+    assertThat(underTest.selectProjectPermissionsOfUser(dbSession, user1.getId(), project2.getId())).containsOnly("perm4");
+    assertThat(underTest.selectProjectPermissionsOfUser(dbSession, user1.getId(), project3.getId())).isEmpty();
+  }
+
   private void expectCount(List<Long> projectIds, CountPerProjectPermission... expected) {
     List<CountPerProjectPermission> got = underTest.countUsersByProjectPermission(dbSession, projectIds);
     assertThat(got).hasSize(expected.length);
index 3f8e9f63dfb94a3348a65fa0ff134f3663707e0f..d81044aa564afa79f4cb12b16eb14c264dff0deb 100644 (file)
@@ -22,7 +22,6 @@ package org.sonar.db.user;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
-import java.util.Set;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.core.permission.GlobalPermissions;
@@ -344,7 +343,11 @@ public class UserDbTester {
     return dto;
   }
 
-  public Set<String> selectUserPermissions(UserDto user, @Nullable ComponentDto project) {
-    return db.getDbClient().userPermissionDao().selectPermissionsByLogin(db.getSession(), user.getLogin(), project == null ? null : project.uuid());
+  public List<String> selectGlobalPermissionsOfUser(UserDto user, OrganizationDto organization) {
+    return db.getDbClient().userPermissionDao().selectGlobalPermissionsOfUser(db.getSession(), user.getId(), organization.getUuid());
+  }
+
+  public List<String> selectProjectPermissionsOfUser(UserDto user, ComponentDto project) {
+    return db.getDbClient().userPermissionDao().selectProjectPermissionsOfUser(db.getSession(), user.getId(), project.getId());
   }
 }