]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8134 add support of organizations in UserSession
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Fri, 14 Oct 2016 05:55:13 +0000 (07:55 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Sun, 16 Oct 2016 17:10:44 +0000 (19:10 +0200)
server/sonar-ce/src/main/java/org/sonar/ce/user/CeUserSession.java
server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java
server/sonar-server/src/main/java/org/sonar/server/user/DoPrivileged.java
server/sonar-server/src/main/java/org/sonar/server/user/ServerUserSession.java
server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java
server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java
server/sonar-server/src/test/java/org/sonar/server/tester/AbstractMockUserSession.java
server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java
server/sonar-server/src/test/java/org/sonar/server/user/ServerUserSessionTest.java

index b805e1749be7048649d0aa3fb223241aab0ae200..421b94711af252c68ec95fa0be3c6501f8f4facc 100644 (file)
@@ -100,6 +100,16 @@ public class CeUserSession implements UserSession {
     return notImplementedBooleanMethod();
   }
 
+  @Override
+  public boolean hasOrganizationPermission(String organizationUuid, String permission) {
+    return notImplementedBooleanMethod();
+  }
+
+  @Override
+  public UserSession checkOrganizationPermission(String organizationUuid, String permission) {
+    return notImplemented();
+  }
+
   @Override
   public boolean hasGlobalPermission(String globalPermission) {
     return notImplementedBooleanMethod();
index c530addeb1e4cb567eb4b7be23a38367822b6c7b..f769729758ca7e3e294bc6208aa4aff0ce28d4de 100644 (file)
@@ -57,6 +57,17 @@ public abstract class AbstractUserSession implements UserSession {
     return this;
   }
 
+  @Override
+  public UserSession checkOrganizationPermission(String organizationUuid, String permission) {
+    if (isRoot()) {
+      return this;
+    }
+    if (!hasOrganizationPermission(organizationUuid, permission)) {
+      throw new ForbiddenException(INSUFFICIENT_PRIVILEGES_MESSAGE);
+    }
+    return this;
+  }
+
   @Override
   public UserSession checkGlobalPermission(String globalPermission) {
     return checkPermission(globalPermission);
index cd00aaddf34250662b38c1583a1f041d43321843..80f3699a046894913cc08058a767413766c60e81 100644 (file)
@@ -107,6 +107,11 @@ public final class DoPrivileged {
         return true;
       }
 
+      @Override
+      public boolean hasOrganizationPermission(String organizationUuid, String permission) {
+        return true;
+      }
+
       @Override
       public List<String> globalPermissions() {
         return Collections.emptyList();
index 08fdb3864b70bdb0ad20633abd9dbab01ab5b409..748d022386fb6c6ec14d56197babad87478ce946 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.server.user;
 
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.SetMultimap;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -57,8 +58,9 @@ public class ServerUserSession extends AbstractUserSession {
   private final ResourceDao resourceDao;
   private final Set<String> userGroups;
   private List<String> globalPermissions = null;
-  private HashMultimap<String, String> projectKeyByPermission = HashMultimap.create();
-  private HashMultimap<String, String> projectUuidByPermission = HashMultimap.create();
+  private SetMultimap<String, String> projectKeyByPermission = HashMultimap.create();
+  private SetMultimap<String, String> projectUuidByPermission = HashMultimap.create();
+  private SetMultimap<String, String> permissionsByOrganizationUuid;
   private Map<String, String> projectUuidByComponentUuid = newHashMap();
   private List<String> projectPermissionsCheckedByKey = new ArrayList<>();
   private List<String> projectPermissionsCheckedByUuid = new ArrayList<>();
@@ -130,6 +132,30 @@ public class ServerUserSession extends AbstractUserSession {
     return userDto != null && userDto.isRoot();
   }
 
+  @Override
+  public boolean hasOrganizationPermission(String organizationUuid, String permission) {
+    if (permissionsByOrganizationUuid == null) {
+      permissionsByOrganizationUuid = HashMultimap.create();
+    }
+    Set<String> permissions;
+    if (permissionsByOrganizationUuid.containsKey(organizationUuid)) {
+      permissions = permissionsByOrganizationUuid.get(organizationUuid);
+    } else {
+      permissions = loadOrganizationPermissions(organizationUuid);
+      permissionsByOrganizationUuid.putAll(organizationUuid, permissions);
+    }
+    return permissions.contains(permission);
+  }
+
+  private Set<String> loadOrganizationPermissions(String organizationUuid) {
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      if (userDto != null && userDto.getId() != null) {
+        return dbClient.authorizationDao().selectOrganizationPermissions(dbSession, organizationUuid, userDto.getId());
+      }
+      return dbClient.authorizationDao().selectOrganizationPermissionsOfAnonymous(dbSession, organizationUuid);
+    }
+  }
+
   @Override
   public List<String> globalPermissions() {
     if (globalPermissions == null) {
index 12594ace5978128d586e76afcb802431bb2d8509..deaaf1406c1529f47cb9021dd6ff4cade95d14e2 100644 (file)
@@ -157,4 +157,15 @@ public class ThreadLocalUserSession implements UserSession {
   public boolean hasComponentUuidPermission(String permission, String componentUuid) {
     return get().hasComponentUuidPermission(permission, componentUuid);
   }
+
+  @Override
+  public UserSession checkOrganizationPermission(String organizationUuid, String permission) {
+    get().checkOrganizationPermission(organizationUuid, permission);
+    return this;
+  }
+
+  @Override
+  public boolean hasOrganizationPermission(String organizationUuid, String permission) {
+    return get().hasOrganizationPermission(organizationUuid, permission);
+  }
 }
index 2373cf0c9fee83254820418d69c230ef47ba130a..0bfe75549b1c15c5712345f88376eff4191254f4 100644 (file)
@@ -35,6 +35,10 @@ public interface UserSession {
   @CheckForNull
   Integer getUserId();
 
+  /**
+   * @deprecated does not support organizations as group names are not unique
+   */
+  @Deprecated
   Set<String> getUserGroups();
 
   boolean isLoggedIn();
@@ -79,6 +83,18 @@ public interface UserSession {
    */
   boolean hasPermission(String globalPermission);
 
+  /**
+   * Returns {@code true} if the permission is granted on the organization, else {@code false}.
+   * Root status is not verified, so the method may return {@code false} even for root users.
+   */
+  boolean hasOrganizationPermission(String organizationUuid, String permission);
+
+  /**
+   * Ensures that user implies the specified organization permission,
+   * otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException}.
+   */
+  UserSession checkOrganizationPermission(String organizationUuid, String permission);
+
   /**
    * @deprecated Only used by Views and the Developer Cockpit plugins.
    */
index 6a4cd804e164f7f7a371904eb6d86321f34bcb5e..4d93bd164f46e75ce8e9013b75d733f7fefac3bc 100644 (file)
@@ -43,6 +43,7 @@ public abstract class AbstractMockUserSession<T extends AbstractMockUserSession>
   private List<String> globalPermissions = Collections.emptyList();
   private HashMultimap<String, String> projectKeyByPermission = HashMultimap.create();
   private HashMultimap<String, String> projectUuidByPermission = HashMultimap.create();
+  private HashMultimap<String, String> permissionsByOrganizationUuid = HashMultimap.create();
   private Map<String, String> projectUuidByComponentUuid = newHashMap();
   private List<String> projectPermissionsCheckedByKey = newArrayList();
   private List<String> projectPermissionsCheckedByUuid = newArrayList();
@@ -141,4 +142,14 @@ public abstract class AbstractMockUserSession<T extends AbstractMockUserSession>
   private boolean hasProjectPermissionByUuid(String permission, String projectUuid) {
     return projectPermissionsCheckedByUuid.contains(permission) && projectUuidByPermission.get(permission).contains(projectUuid);
   }
+
+  @Override
+  public boolean hasOrganizationPermission(String organizationUuid, String permission) {
+    return permissionsByOrganizationUuid.get(organizationUuid).contains(permission);
+  }
+
+  public T addOrganizationPermission(String organizationUuid, String permission) {
+    permissionsByOrganizationUuid.put(organizationUuid, permission);
+    return clazz.cast(this);
+  }
 }
index 2da0a3a079440dfbab39496a33744f851be5f051..8370eee75911593d1112d3b93786c3177fd39b8c 100644 (file)
@@ -189,6 +189,11 @@ public class UserSessionRule implements TestRule, UserSession {
     return this;
   }
 
+  public UserSessionRule addOrganizationPermission(String organizationUuid, String permission) {
+    ensureAbstractMockUserSession().addOrganizationPermission(organizationUuid, permission);
+    return this;
+  }
+
   public UserSessionRule setUserId(@Nullable Integer userId) {
     ensureMockUserSession().setUserId(userId);
     return this;
@@ -324,6 +329,11 @@ public class UserSessionRule implements TestRule, UserSession {
     return currentUserSession.hasGlobalPermission(globalPermission);
   }
 
+  @Override
+  public boolean hasOrganizationPermission(String organizationUuid, String permission) {
+    return currentUserSession.hasOrganizationPermission(organizationUuid, permission);
+  }
+
   @Override
   public UserSession checkComponentPermission(String projectPermission, String componentKey) {
     currentUserSession.checkComponentPermission(projectPermission, componentKey);
@@ -336,5 +346,9 @@ public class UserSessionRule implements TestRule, UserSession {
     return this;
   }
 
-
+  @Override
+  public UserSession checkOrganizationPermission(String organizationUuid, String permission) {
+    currentUserSession.checkOrganizationPermission(organizationUuid, permission);
+    return this;
+  }
 }
index ebffd03f7056905ef9d249803464e7ad63d1de5a..e2c13126df9fcc8df885120f9ca6b8276f3585bb 100644 (file)
@@ -28,10 +28,11 @@ import org.sonar.api.utils.System2;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ComponentTesting;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.organization.OrganizationTesting;
 import org.sonar.db.user.UserDto;
 import org.sonar.server.exceptions.ForbiddenException;
 
@@ -39,6 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN;
 import static org.sonar.core.permission.GlobalPermissions.QUALITY_PROFILE_ADMIN;
 import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;
 import static org.sonar.db.user.UserTesting.newUserDto;
 import static org.sonar.server.user.ServerUserSession.createForAnonymous;
 import static org.sonar.server.user.ServerUserSession.createForUser;
@@ -322,6 +324,35 @@ public class ServerUserSessionTest {
     assertThat(session.hasComponentPermission(UserRole.ADMIN, FILE_KEY)).isFalse();
   }
 
+  @Test
+  public void checkOrganizationPermission_fails_with_ForbiddenException_when_user_has_no_permissions_on_organization() {
+    expectInsufficientPrivilegesForbiddenException();
+
+    newUserSession(NON_ROOT_USER_DTO).checkOrganizationPermission("org-uuid", "perm1");
+  }
+
+  @Test
+  public void hasOrganizationPermission_for_logged_in_user() {
+    OrganizationDto org = OrganizationTesting.insert(db, newOrganizationDto());
+    db.users().insertPermissionOnUser(org, userDto, GlobalPermissions.PROVISIONING);
+
+    UserSession session = newUserSession(userDto);
+    assertThat(session.hasOrganizationPermission(org.getUuid(), GlobalPermissions.PROVISIONING)).isTrue();
+    assertThat(session.hasOrganizationPermission(org.getUuid(), GlobalPermissions.SYSTEM_ADMIN)).isFalse();
+    assertThat(session.hasOrganizationPermission("another-org", GlobalPermissions.PROVISIONING)).isFalse();
+  }
+
+  @Test
+  public void hasOrganizationPermission_for_anonymous_user() {
+    OrganizationDto org = OrganizationTesting.insert(db, newOrganizationDto());
+    db.users().insertPermissionOnAnyone(org, GlobalPermissions.PROVISIONING);
+
+    UserSession session = newAnonymousSession();
+    assertThat(session.hasOrganizationPermission(org.getUuid(), GlobalPermissions.PROVISIONING)).isTrue();
+    assertThat(session.hasOrganizationPermission(org.getUuid(), GlobalPermissions.SYSTEM_ADMIN)).isFalse();
+    assertThat(session.hasOrganizationPermission("another-org", GlobalPermissions.PROVISIONING)).isFalse();
+  }
+
   private ServerUserSession newUserSession(UserDto userDto) {
     return createForUser(dbClient, userDto);
   }