]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8751 drop Owners group for personal organizations
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 16 Feb 2017 16:36:25 +0000 (17:36 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Fri, 17 Feb 2017 14:47:10 +0000 (15:47 +0100)
user permissions replace group permissions in the default template and also SCAN permission is added to the template

server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationCreation.java
server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationCreationImpl.java
server/sonar-server/src/test/java/org/sonar/server/organization/OrganizationCreationImplTest.java

index 518fc0d31342c574385ea355570158be15befb82..017ca85465b9d31810f47bd08d7c04442af636c5 100644 (file)
@@ -23,6 +23,7 @@ import java.util.Optional;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.api.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.db.DbSession;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.user.UserDto;
@@ -32,6 +33,7 @@ import static java.util.Objects.requireNonNull;
 public interface OrganizationCreation {
   String OWNERS_GROUP_NAME = "Owners";
   String OWNERS_GROUP_DESCRIPTION_PATTERN = "Owners of organization %s";
+  String PERM_TEMPLATE_NAME = "Default template";
   String PERM_TEMPLATE_DESCRIPTION_PATTERN = "Default permission template of organization %s";
   String PERSONAL_ORGANIZATION_DESCRIPTION_PATTERN = "%s's personal organization";
 
@@ -67,16 +69,36 @@ public interface OrganizationCreation {
   /**
    * Create a new guarded organization which details are based on the login of the specified User.
    * <p>
-   * This method create the organization and its associated elements in exactly the same was as
-   * {@link #create(DbSession, long, NewOrganization)} with the organization's details computed from the
-   * user's login:
-   * <ul>
-   *   <li>key: generated from the user's login</li>
-   *   <li>name: the user's name if set, otherwise the user's login</li>
-   *   <li>description: {@link #PERSONAL_ORGANIZATION_DESCRIPTION_PATTERN "[name]'s personal organization"} where name
-   *       is user name (when non null and non empty) or login</li>
-   *   <li>url and avatar: null</li>
-   * </ul>
+   * This method does several operations at once:
+   * <ol>
+   *   <li>
+   *     create a guarded organization with the details computed from user's details:
+   *     <ul>
+   *       <li>key: generated from the user's login</li>
+   *       <li>name: the user's name if set, otherwise the user's login</li>
+   *       <li>description: {@link #PERSONAL_ORGANIZATION_DESCRIPTION_PATTERN "[name]'s personal organization"} where name
+   *           is user name (when non null and non empty) or login</li>
+   *       <li>url and avatar: null</li>
+   *     </ul>
+   *   </li>
+   *   <li>give all organization wide permissions to the user</li>
+   *   <li>create a default template for the organization
+   *       <ul>
+   *         <li>name is {@link #PERM_TEMPLATE_NAME Default template}</li>
+   *         <li>description follows pattern {@link #PERM_TEMPLATE_DESCRIPTION_PATTERN} based on the organization name</li>
+   *       </ul>
+   *   </li>
+   *   <li>this permission template defines the specified permissions (which effectively makes projects public and
+   *       automatically adds new projects to the user's favorites):
+   *     <ul>
+   *       <li>project creator : {@link UserRole#ADMIN ADMIN}</li>
+   *       <li>project creator : {@link UserRole#ISSUE_ADMIN ISSUE_ADMIN}</li>
+   *       <li>project creator : {@link GlobalPermissions#SCAN_EXECUTION SCAN_EXECUTION}</li>
+   *       <li>anyone : {@link UserRole#USER USER}</li>
+   *       <li>anyone : {@link UserRole#CODEVIEWER CODEVIEWER}</li>
+   *     </ul>
+   *   </li>
+   * </ol>
    * </p>
    *
    * @return the created organization or empty if feature is disabled
index c5333acf0d0582fabe4b593b4f8e379b0c2ccf4f..849ebf69f4bf741d8094636260428fc4c081ee44 100644 (file)
@@ -34,6 +34,8 @@ import org.sonar.db.DbSession;
 import org.sonar.db.organization.DefaultTemplates;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.permission.GroupPermissionDto;
+import org.sonar.db.permission.UserPermissionDto;
+import org.sonar.db.permission.template.PermissionTemplateCharacteristicDto;
 import org.sonar.db.permission.template.PermissionTemplateDto;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDto;
@@ -99,9 +101,8 @@ public class OrganizationCreationImpl implements OrganizationCreation {
 
     OrganizationDto organization = insertOrganization(dbSession, newOrganization,
       dto -> dto.setGuarded(true).setUserId(newUser.getId()));
-    GroupDto group = insertOwnersGroup(dbSession, organization);
-    insertDefaultTemplate(dbSession, organization, group);
-    addCurrentUserToGroup(dbSession, group, newUser.getId());
+    GlobalPermissions.ALL.forEach(permission -> insertUserPermissions(dbSession, newUser, organization, permission));
+    insertPersonalOrgDefaultTemplate(dbSession, organization);
 
     dbSession.commit();
 
@@ -160,7 +161,7 @@ public class OrganizationCreationImpl implements OrganizationCreation {
       new PermissionTemplateDto()
         .setOrganizationUuid(organizationDto.getUuid())
         .setUuid(uuidFactory.create())
-        .setName("Default template")
+        .setName(PERM_TEMPLATE_NAME)
         .setDescription(format(PERM_TEMPLATE_DESCRIPTION_PATTERN, organizationDto.getName()))
         .setCreatedAt(now)
         .setUpdatedAt(now));
@@ -176,6 +177,42 @@ public class OrganizationCreationImpl implements OrganizationCreation {
       new DefaultTemplates().setProjectUuid(permissionTemplateDto.getUuid()));
   }
 
+  private void insertPersonalOrgDefaultTemplate(DbSession dbSession, OrganizationDto organizationDto) {
+    long now = system2.now();
+    Date dateNow = new Date(now);
+    PermissionTemplateDto permissionTemplateDto = dbClient.permissionTemplateDao().insert(
+      dbSession,
+      new PermissionTemplateDto()
+        .setOrganizationUuid(organizationDto.getUuid())
+        .setUuid(uuidFactory.create())
+        .setName("Default template")
+        .setDescription(format(PERM_TEMPLATE_DESCRIPTION_PATTERN, organizationDto.getName()))
+        .setCreatedAt(dateNow)
+        .setUpdatedAt(dateNow));
+
+    insertProjectCreatorPermission(dbSession, permissionTemplateDto, UserRole.ADMIN, now);
+    insertProjectCreatorPermission(dbSession, permissionTemplateDto, UserRole.ISSUE_ADMIN, now);
+    insertProjectCreatorPermission(dbSession, permissionTemplateDto, GlobalPermissions.SCAN_EXECUTION, now);
+    insertGroupPermission(dbSession, permissionTemplateDto, UserRole.USER, null);
+    insertGroupPermission(dbSession, permissionTemplateDto, UserRole.CODEVIEWER, null);
+
+    dbClient.organizationDao().setDefaultTemplates(
+      dbSession,
+      organizationDto.getUuid(),
+      new DefaultTemplates().setProjectUuid(permissionTemplateDto.getUuid()));
+  }
+
+  private void insertProjectCreatorPermission(DbSession dbSession, PermissionTemplateDto permissionTemplateDto, String permission, long now) {
+    dbClient.permissionTemplateCharacteristicDao().insert(
+      dbSession,
+      new PermissionTemplateCharacteristicDto()
+        .setTemplateId(permissionTemplateDto.getId())
+        .setWithProjectCreator(true)
+        .setPermission(permission)
+        .setCreatedAt(now)
+        .setUpdatedAt(now));
+  }
+
   private void insertGroupPermission(DbSession dbSession, PermissionTemplateDto template, String permission, @Nullable GroupDto group) {
     dbClient.permissionTemplateDao().insertGroupPermission(dbSession, template.getId(), group == null ? null : group.getId(), permission);
   }
@@ -201,6 +238,12 @@ public class OrganizationCreationImpl implements OrganizationCreation {
         .setRole(permission));
   }
 
+  private void insertUserPermissions(DbSession dbSession, UserDto userDto, OrganizationDto organization, String permission) {
+    dbClient.userPermissionDao().insert(
+      dbSession,
+      new UserPermissionDto(organization.getUuid(), permission, userDto.getId(), null));
+  }
+
   private void addCurrentUserToGroup(DbSession dbSession, GroupDto group, long createUserId) {
     dbClient.userGroupDao().insert(
       dbSession,
index 4ebeec9bb31c098ae3304579b0cf69daa9fa4485..5afe163a4dad7b3f174dbee6d066f7ea85896d0f 100644 (file)
@@ -19,8 +19,8 @@
  */
 package org.sonar.server.organization;
 
+import java.util.Collections;
 import java.util.List;
-import java.util.Optional;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -35,6 +35,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.organization.DefaultTemplates;
 import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.permission.template.PermissionTemplateCharacteristicDto;
 import org.sonar.db.permission.template.PermissionTemplateDto;
 import org.sonar.db.permission.template.PermissionTemplateGroupDto;
 import org.sonar.db.user.GroupDto;
@@ -57,14 +58,15 @@ public class OrganizationCreationImplTest {
   private static final String SLUG_OF_A_LOGIN = "slug-of-a-login";
   private static final String STRING_64_CHARS = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
   private static final String A_NAME = "a name";
+  private static final long ANYONE_GROUP_ID = 0L;
 
   private OrganizationCreation.NewOrganization FULL_POPULATED_NEW_ORGANIZATION = newOrganizationBuilder()
-    .setName("a-name")
-    .setKey("a-key")
-    .setDescription("a-description")
-    .setUrl("a-url")
-    .setAvatarUrl("a-avatar")
-    .build();
+      .setName("a-name")
+      .setKey("a-key")
+      .setDescription("a-description")
+      .setUrl("a-url")
+      .setAvatarUrl("a-avatar")
+      .build();
 
   private System2 system2 = mock(System2.class);
 
@@ -94,7 +96,7 @@ public class OrganizationCreationImplTest {
   @Test
   public void create_throws_exception_thrown_by_checkValidKey() throws OrganizationCreation.KeyConflictException {
     when(organizationValidation.checkKey(FULL_POPULATED_NEW_ORGANIZATION.getKey()))
-      .thenThrow(exceptionThrownByOrganizationValidation);
+        .thenThrow(exceptionThrownByOrganizationValidation);
 
     createThrowsExceptionThrownByOrganizationValidation();
   }
@@ -174,9 +176,9 @@ public class OrganizationCreationImplTest {
     mockForSuccessfulInsert(SOME_UUID, SOME_DATE);
 
     underTest.create(dbSession, SOME_USER_ID, newOrganizationBuilder()
-      .setKey("key")
-      .setName("name")
-      .build());
+        .setKey("key")
+        .setName("name")
+        .build());
 
     OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, "key").get();
     assertThat(organization.getKey()).isEqualTo("key");
@@ -194,7 +196,19 @@ public class OrganizationCreationImplTest {
 
     underTest.create(dbSession, SOME_USER_ID, FULL_POPULATED_NEW_ORGANIZATION);
 
-    verifyDefaultTemplate(FULL_POPULATED_NEW_ORGANIZATION.getKey(), FULL_POPULATED_NEW_ORGANIZATION.getName());
+    OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, FULL_POPULATED_NEW_ORGANIZATION.getKey()).get();
+    GroupDto ownersGroup = dbClient.groupDao().selectByName(dbSession, organization.getUuid(), "Owners").get();
+    PermissionTemplateDto defaultTemplate = dbClient.permissionTemplateDao().selectByName(dbSession, organization.getUuid(), "default template");
+    assertThat(defaultTemplate.getName()).isEqualTo("Default template");
+    assertThat(defaultTemplate.getDescription()).isEqualTo("Default permission template of organization " + FULL_POPULATED_NEW_ORGANIZATION.getName());
+    DefaultTemplates defaultTemplates = dbClient.organizationDao().getDefaultTemplates(dbSession, organization.getUuid()).get();
+    assertThat(defaultTemplates.getProjectUuid()).isEqualTo(defaultTemplate.getUuid());
+    assertThat(defaultTemplates.getViewUuid()).isNull();
+    assertThat(dbClient.permissionTemplateDao().selectGroupPermissionsByTemplateId(dbSession, defaultTemplate.getId()))
+        .extracting(PermissionTemplateGroupDto::getGroupId, PermissionTemplateGroupDto::getPermission)
+        .containsOnly(
+            tuple(ownersGroup.getId(), UserRole.ADMIN), tuple(ownersGroup.getId(), UserRole.ISSUE_ADMIN),
+            tuple(ANYONE_GROUP_ID, UserRole.USER), tuple(ANYONE_GROUP_ID, UserRole.CODEVIEWER));
   }
 
   @Test
@@ -258,13 +272,13 @@ public class OrganizationCreationImplTest {
 
     expectedException.expect(IllegalStateException.class);
     expectedException.expectMessage("Can't create organization with key '" + SLUG_OF_A_LOGIN + "' for new user '" + A_LOGIN
-      + "' because an organization with this key already exists");
+        + "' because an organization with this key already exists");
 
     underTest.createForUser(dbSession, user);
   }
 
   @Test
-  public void createForUser_creates_owners_group_with_all_permissions_for_new_organization_and_add_current_user_to_it() throws OrganizationCreation.KeyConflictException {
+  public void createForUser_gives_all_permissions_for_new_organization_to_current_user() throws OrganizationCreation.KeyConflictException {
     UserDto user = dbTester.users().insertUser(dto -> dto.setLogin(A_LOGIN).setName(A_NAME));
     when(organizationValidation.generateKeyFrom(A_LOGIN)).thenReturn(SLUG_OF_A_LOGIN);
     mockForSuccessfulInsert(SOME_UUID, SOME_DATE);
@@ -272,23 +286,40 @@ public class OrganizationCreationImplTest {
 
     underTest.createForUser(dbSession, user);
 
-    verifyGroupOwners(user, SLUG_OF_A_LOGIN, A_NAME);
+    OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, SLUG_OF_A_LOGIN).get();
+    assertThat(dbClient.userPermissionDao().selectGlobalPermissionsOfUser(dbSession, user.getId(), organization.getUuid()))
+        .containsOnly(GlobalPermissions.ALL.toArray(new String[GlobalPermissions.ALL.size()]));
+  }
+
+  @Test
+  public void createForUser_does_not_create_any_group() throws OrganizationCreation.KeyConflictException {
+    UserDto user = dbTester.users().insertUser(dto -> dto.setLogin(A_LOGIN).setName(A_NAME));
+    when(organizationValidation.generateKeyFrom(A_LOGIN)).thenReturn(SLUG_OF_A_LOGIN);
+    mockForSuccessfulInsert(SOME_UUID, SOME_DATE);
+    enableCreatePersonalOrg(true);
+
+    underTest.createForUser(dbSession, user);
+
+    OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, SLUG_OF_A_LOGIN).get();
+    assertThat(dbClient.groupDao().selectByOrganizationUuid(dbSession, organization.getUuid())).isEmpty();
   }
 
   private void verifyGroupOwners(UserDto user, String organizationKey, String organizationName) {
     OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, organizationKey).get();
-    Optional<GroupDto> groupDtoOptional = dbClient.groupDao().selectByName(dbSession, organization.getUuid(), "Owners");
-    assertThat(groupDtoOptional).isNotEmpty();
-    GroupDto groupDto = groupDtoOptional.get();
+    List<GroupDto> groups = dbClient.groupDao().selectByOrganizationUuid(dbSession, organization.getUuid());
+    assertThat(groups)
+        .extracting(GroupDto::getName)
+        .containsOnly("Owners");
+    GroupDto groupDto = groups.iterator().next();
     assertThat(groupDto.getDescription()).isEqualTo("Owners of organization " + organizationName);
     assertThat(dbClient.groupPermissionDao().selectGlobalPermissionsOfGroup(dbSession, groupDto.getOrganizationUuid(), groupDto.getId()))
-      .containsOnly(GlobalPermissions.ALL.toArray(new String[GlobalPermissions.ALL.size()]));
+        .containsOnly(GlobalPermissions.ALL.toArray(new String[GlobalPermissions.ALL.size()]));
     List<UserMembershipDto> members = dbClient.groupMembershipDao().selectMembers(
-      dbSession,
-      UserMembershipQuery.builder().groupId(groupDto.getId()).membership(UserMembershipQuery.IN).build(), 0, Integer.MAX_VALUE);
+        dbSession,
+        UserMembershipQuery.builder().groupId(groupDto.getId()).membership(UserMembershipQuery.IN).build(), 0, Integer.MAX_VALUE);
     assertThat(members)
-      .extracting(UserMembershipDto::getLogin)
-      .containsOnly(user.getLogin());
+        .extracting(UserMembershipDto::getLogin)
+        .containsOnly(user.getLogin());
   }
 
   @Test
@@ -300,23 +331,20 @@ public class OrganizationCreationImplTest {
 
     underTest.createForUser(dbSession, user);
 
-    verifyDefaultTemplate(SLUG_OF_A_LOGIN, A_NAME);
-  }
-
-  private void verifyDefaultTemplate(String organizationKey, String organizationName) {
-    OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, organizationKey).get();
-    GroupDto ownersGroup = dbClient.groupDao().selectByName(dbSession, organization.getUuid(), "Owners").get();
+    OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, SLUG_OF_A_LOGIN).get();
     PermissionTemplateDto defaultTemplate = dbClient.permissionTemplateDao().selectByName(dbSession, organization.getUuid(), "default template");
     assertThat(defaultTemplate.getName()).isEqualTo("Default template");
-    assertThat(defaultTemplate.getDescription()).isEqualTo("Default permission template of organization " + organizationName);
+    assertThat(defaultTemplate.getDescription()).isEqualTo("Default permission template of organization " + A_NAME);
     DefaultTemplates defaultTemplates = dbClient.organizationDao().getDefaultTemplates(dbSession, organization.getUuid()).get();
     assertThat(defaultTemplates.getProjectUuid()).isEqualTo(defaultTemplate.getUuid());
     assertThat(defaultTemplates.getViewUuid()).isNull();
     assertThat(dbClient.permissionTemplateDao().selectGroupPermissionsByTemplateId(dbSession, defaultTemplate.getId()))
-      .extracting(PermissionTemplateGroupDto::getGroupId, PermissionTemplateGroupDto::getPermission)
-      .containsOnly(
-        tuple(ownersGroup.getId(), UserRole.ADMIN), tuple(ownersGroup.getId(), UserRole.ISSUE_ADMIN),
-        tuple(0L, UserRole.USER), tuple(0L, UserRole.CODEVIEWER));
+        .extracting(PermissionTemplateGroupDto::getGroupId, PermissionTemplateGroupDto::getPermission)
+        .containsOnly(tuple(ANYONE_GROUP_ID, UserRole.USER), tuple(ANYONE_GROUP_ID, UserRole.CODEVIEWER));
+    assertThat(dbClient.permissionTemplateCharacteristicDao().selectByTemplateIds(dbSession, Collections.singletonList(defaultTemplate.getId())))
+        .extracting(PermissionTemplateCharacteristicDto::getWithProjectCreator, PermissionTemplateCharacteristicDto::getPermission)
+        .containsOnly(
+            tuple(true, UserRole.ADMIN), tuple(true, UserRole.ISSUE_ADMIN), tuple(true, GlobalPermissions.SCAN_EXECUTION));
   }
 
   @Test