diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2017-02-16 17:36:25 +0100 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2017-02-17 15:47:10 +0100 |
commit | 011c3e3ae0bbf9ed9e9d0f75ce6d09da696c94fb (patch) | |
tree | c7c3895fc3df3a043ca6d92ec3c7c1fca8ac9973 | |
parent | 9f5ad5ec0cadc465c61e9c6b3952753e4abfa91f (diff) | |
download | sonarqube-011c3e3ae0bbf9ed9e9d0f75ce6d09da696c94fb.tar.gz sonarqube-011c3e3ae0bbf9ed9e9d0f75ce6d09da696c94fb.zip |
SONAR-8751 drop Owners group for personal organizations
user permissions replace group permissions in the default template and also SCAN permission is added to the template
3 files changed, 141 insertions, 48 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationCreation.java b/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationCreation.java index 518fc0d3134..017ca85465b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationCreation.java +++ b/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationCreation.java @@ -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 diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationCreationImpl.java b/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationCreationImpl.java index c5333acf0d0..849ebf69f4b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationCreationImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationCreationImpl.java @@ -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, diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/OrganizationCreationImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/OrganizationCreationImplTest.java index 4ebeec9bb31..5afe163a4da 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/organization/OrganizationCreationImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/organization/OrganizationCreationImplTest.java @@ -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 |