diff options
author | Wojtek Wajerowicz <115081248+wojciech-wajerowicz-sonarsource@users.noreply.github.com> | 2023-07-28 15:45:27 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-07-28 20:03:15 +0000 |
commit | e0f8e15dbec318e77c26d24a75802c901e06e4e5 (patch) | |
tree | 5fdcd5cc9e89e17f263f794149e0b4b780fa8e4e | |
parent | c5a0b961aa8f1ab8c806b686a106fb4f76c55b52 (diff) | |
download | sonarqube-e0f8e15dbec318e77c26d24a75802c901e06e4e5.tar.gz sonarqube-e0f8e15dbec318e77c26d24a75802c901e06e4e5.zip |
SONAR-19965 Add ITs for UserService::deactivate.
-rw-r--r-- | server/sonar-webserver-common/src/it/java/org/sonar/server/common/user/service/UserServiceIT.java | 324 |
1 files changed, 296 insertions, 28 deletions
diff --git a/server/sonar-webserver-common/src/it/java/org/sonar/server/common/user/service/UserServiceIT.java b/server/sonar-webserver-common/src/it/java/org/sonar/server/common/user/service/UserServiceIT.java index 3c65ea743af..0083f73827b 100644 --- a/server/sonar-webserver-common/src/it/java/org/sonar/server/common/user/service/UserServiceIT.java +++ b/server/sonar-webserver-common/src/it/java/org/sonar/server/common/user/service/UserServiceIT.java @@ -32,20 +32,37 @@ import org.junit.Rule; import org.junit.Test; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.utils.DateUtils; +import org.sonar.api.web.UserRole; import org.sonar.core.util.UuidFactory; +import org.sonar.db.DbSession; import org.sonar.db.DbTester; +import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.db.audit.NoOpAuditPersister; +import org.sonar.db.ce.CeTaskMessageType; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.permission.GlobalPermission; +import org.sonar.db.permission.template.PermissionTemplateDto; +import org.sonar.db.permission.template.PermissionTemplateUserDto; +import org.sonar.db.project.ProjectDto; +import org.sonar.db.property.PropertyDto; +import org.sonar.db.property.PropertyQuery; +import org.sonar.db.qualitygate.QualityGateDto; +import org.sonar.db.qualityprofile.QProfileDto; import org.sonar.db.scim.ScimUserDao; import org.sonar.db.user.GroupDto; +import org.sonar.db.user.SessionTokenDto; +import org.sonar.db.user.UserDismissedMessageDto; import org.sonar.db.user.UserDto; import org.sonar.server.authentication.CredentialsLocalAuthentication; import org.sonar.server.common.SearchResults; import org.sonar.server.common.avatar.AvatarResolverImpl; import org.sonar.server.common.management.ManagedInstanceChecker; +import org.sonar.server.common.user.UserAnonymizer; import org.sonar.server.common.user.UserDeactivator; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.management.ManagedInstanceService; +import org.sonar.server.user.ExternalIdentity; import org.sonar.server.user.NewUserNotifier; import org.sonar.server.user.UserUpdater; import org.sonar.server.usergroups.DefaultGroupFinder; @@ -63,9 +80,8 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.sonar.db.property.PropertyTesting.newUserPropertyDto; import static org.sonar.db.user.UserTesting.newUserDto; public class UserServiceIT { @@ -75,9 +91,14 @@ public class UserServiceIT { @Rule public DbTester db = DbTester.create(); + private final DbSession dbSession = db.getSession(); + private final ManagedInstanceService managedInstanceService = mock(ManagedInstanceService.class); private final ManagedInstanceChecker managedInstanceChecker = mock(ManagedInstanceChecker.class); - private final UserDeactivator userDeactivator = mock(UserDeactivator.class); + + private final UserAnonymizer userAnonymizer = new UserAnonymizer(db.getDbClient(), () -> "anonymized"); + + private final UserDeactivator userDeactivator = new UserDeactivator(db.getDbClient(), userAnonymizer); private final MapSettings settings = new MapSettings().setProperty("sonar.internal.pbkdf2.iterations", "1"); private final CredentialsLocalAuthentication localAuthentication = new CredentialsLocalAuthentication(db.getDbClient(), settings.asConfig()); private final UserUpdater userUpdater = new UserUpdater(mock(NewUserNotifier.class), db.getDbClient(), new DefaultGroupFinder(db.getDbClient()), @@ -402,42 +423,261 @@ public class UserServiceIT { } @Test - public void deactivate_whenUserIsNotFound_shouldThrowNotFoundException() { - assertThatThrownBy(() -> userService.deactivate("userToDelete", false)) - .isInstanceOf(NotFoundException.class) - .hasMessage("User 'userToDelete' not found"); + public void deactivate_user_and_delete_their_related_data() { + createAdminUser(); + UserDto user = db.users().insertUser(u -> u + .setLogin("ada.lovelace") + .setEmail("ada.lovelace@noteg.com") + .setName("Ada Lovelace") + .setScmAccounts(singletonList("al"))); + + userService.deactivate(user.getLogin(), false); + + verifyThatUserIsDeactivated(user.getLogin()); + } + + @Test + public void anonymize_user_if_anonymize_is_true() { + createAdminUser(); + UserDto user = db.users().insertUser(u -> u + .setLogin("ada.lovelace") + .setEmail("ada.lovelace@noteg.com") + .setName("Ada Lovelace") + .setScmAccounts(singletonList("al"))); + + userService.deactivate(user.getLogin(), true); + + verifyThatUserIsDeactivated("anonymized"); + verifyThatUserIsAnomymized("anonymized"); } @Test - public void deactivate_whenInstanceIsManagedAndUserIsManaged_shouldThrowBadRequestException() { + public void deactivate_user_deletes_their_group_membership() { + createAdminUser(); UserDto user = db.users().insertUser(); - BadRequestException badRequestException = BadRequestException.create("Not allowed"); - doThrow(badRequestException).when(managedInstanceChecker).throwIfUserIsManaged(any(), eq(user.getUuid())); - assertThatThrownBy(() -> userService.deactivate(user.getLogin(), false)) - .isEqualTo(badRequestException); + GroupDto group1 = db.users().insertGroup(); + db.users().insertGroup(); + db.users().insertMember(group1, user); + + userService.deactivate(user.getLogin(), false); + + assertThat(db.getDbClient().groupMembershipDao().selectGroupUuidsByUserUuid(dbSession, user.getUuid())).isEmpty(); + } + + @Test + public void deactivate_user_deletes_their_tokens() { + createAdminUser(); + UserDto user = db.users().insertUser(); + db.users().insertToken(user); + db.users().insertToken(user); + db.commit(); + + userService.deactivate(user.getLogin(), false); + + assertThat(db.getDbClient().userTokenDao().selectByUser(dbSession, user)).isEmpty(); + } + + @Test + public void deactivate_user_deletes_their_properties() { + createAdminUser(); + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + db.properties().insertProperty(newUserPropertyDto(user), null, null, null, user.getLogin()); + db.properties().insertProperty(newUserPropertyDto(user), null, null, null, user.getLogin()); + db.properties().insertProperty(newUserPropertyDto(user).setEntityUuid(project.uuid()), project.getKey(), + project.name(), project.qualifier(), user.getLogin()); + + userService.deactivate(user.getLogin(), false); + + assertThat(db.getDbClient().propertiesDao().selectByQuery(PropertyQuery.builder().setUserUuid(user.getUuid()).build(), dbSession)).isEmpty(); + assertThat(db.getDbClient().propertiesDao().selectByQuery(PropertyQuery.builder().setUserUuid(user.getUuid()).setEntityUuid(project.uuid()).build(), dbSession)).isEmpty(); + } + + @Test + public void deactivate_user_deletes_their_permissions() { + createAdminUser(); + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + db.users().insertGlobalPermissionOnUser(user, GlobalPermission.SCAN); + db.users().insertGlobalPermissionOnUser(user, GlobalPermission.ADMINISTER_QUALITY_PROFILES); + db.users().insertProjectPermissionOnUser(user, UserRole.USER, project); + db.users().insertProjectPermissionOnUser(user, UserRole.CODEVIEWER, project); + + userService.deactivate(user.getLogin(), false); + + assertThat(db.getDbClient().userPermissionDao().selectGlobalPermissionsOfUser(dbSession, user.getUuid())).isEmpty(); + assertThat(db.getDbClient().userPermissionDao().selectEntityPermissionsOfUser(dbSession, user.getUuid(), project.uuid())).isEmpty(); + } + + @Test + public void deactivate_user_deletes_their_permission_templates() { + createAdminUser(); + UserDto user = db.users().insertUser(); + PermissionTemplateDto template = db.permissionTemplates().insertTemplate(); + PermissionTemplateDto anotherTemplate = db.permissionTemplates().insertTemplate(); + db.permissionTemplates().addUserToTemplate(template.getUuid(), user.getUuid(), UserRole.USER, template.getName(), user.getLogin()); + db.permissionTemplates().addUserToTemplate(anotherTemplate.getUuid(), user.getUuid(), UserRole.CODEVIEWER, anotherTemplate.getName(), user.getLogin()); + + userService.deactivate(user.getLogin(), false); + + assertThat(db.getDbClient().permissionTemplateDao().selectUserPermissionsByTemplateId(dbSession, template.getUuid())).extracting(PermissionTemplateUserDto::getUserUuid) + .isEmpty(); + assertThat(db.getDbClient().permissionTemplateDao().selectUserPermissionsByTemplateId(dbSession, anotherTemplate.getUuid())).extracting(PermissionTemplateUserDto::getUserUuid) + .isEmpty(); + } + + @Test + public void deactivate_user_deletes_their_qprofiles_permissions() { + createAdminUser(); + UserDto user = db.users().insertUser(); + QProfileDto profile = db.qualityProfiles().insert(); + db.qualityProfiles().addUserPermission(profile, user); + + userService.deactivate(user.getLogin(), false); + + assertThat(db.getDbClient().qProfileEditUsersDao().exists(dbSession, profile, user)).isFalse(); + } + + @Test + public void deactivate_user_deletes_their_default_assignee_settings() { + createAdminUser(); + UserDto user = db.users().insertUser(); + ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ComponentDto anotherProject = db.components().insertPrivateProject().getMainBranchComponent(); + db.properties().insertProperty(new PropertyDto().setKey("sonar.issues.defaultAssigneeLogin").setValue(user.getLogin()) + .setEntityUuid(project.uuid()), project.getKey(), project.name(), project.qualifier(), user.getLogin()); + db.properties().insertProperty(new PropertyDto().setKey("sonar.issues.defaultAssigneeLogin").setValue(user.getLogin()) + .setEntityUuid(anotherProject.uuid()), anotherProject.getKey(), anotherProject.name(), anotherProject.qualifier(), user.getLogin()); + db.properties().insertProperty(new PropertyDto().setKey("other").setValue(user.getLogin()) + .setEntityUuid(anotherProject.uuid()), anotherProject.getKey(), anotherProject.name(), anotherProject.qualifier(), user.getLogin()); + + userService.deactivate(user.getLogin(), false); + + assertThat(db.getDbClient().propertiesDao().selectByQuery(PropertyQuery.builder().setKey("sonar.issues.defaultAssigneeLogin").build(), db.getSession())).isEmpty(); + assertThat(db.getDbClient().propertiesDao().selectByQuery(PropertyQuery.builder().build(), db.getSession())).extracting(PropertyDto::getKey).containsOnly("other"); + } + + @Test + public void deactivate_user_deletes_their_qgate_permissions() { + createAdminUser(); + UserDto user = db.users().insertUser(); + QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); + db.qualityGates().addUserPermission(qualityGate, user); + assertThat(db.countRowsOfTable("qgate_user_permissions")).isOne(); + + userService.deactivate(user.getLogin(), false); + + assertThat(db.countRowsOfTable("qgate_user_permissions")).isZero(); + } + + @Test + public void deactivate_user_deletes_their_alm_pat() { + createAdminUser(); + AlmSettingDto almSettingDto = db.almSettings().insertBitbucketAlmSetting(); + UserDto user = db.users().insertUser(); + db.almPats().insert(p -> p.setUserUuid(user.getUuid()), p -> p.setAlmSettingUuid(almSettingDto.getUuid())); + UserDto anotherUser = db.users().insertUser(); + db.almPats().insert(p -> p.setUserUuid(anotherUser.getUuid()), p -> p.setAlmSettingUuid(almSettingDto.getUuid())); + userService.deactivate(user.getLogin(), false); + + assertThat(db.getDbClient().almPatDao().selectByUserAndAlmSetting(dbSession, user.getUuid(), almSettingDto)).isEmpty(); + assertThat(db.getDbClient().almPatDao().selectByUserAndAlmSetting(dbSession, anotherUser.getUuid(), almSettingDto)).isNotNull(); } @Test - public void deactivate_whenAnonymizeIsFalse_shouldDeactivateUser() { + public void deactivate_user_deletes_their_session_tokens() { + createAdminUser(); UserDto user = db.users().insertUser(); + SessionTokenDto sessionToken1 = db.users().insertSessionToken(user); + SessionTokenDto sessionToken2 = db.users().insertSessionToken(user); + UserDto anotherUser = db.users().insertUser(); + SessionTokenDto sessionToken3 = db.users().insertSessionToken(anotherUser); userService.deactivate(user.getLogin(), false); - verify(managedInstanceChecker).throwIfUserIsManaged(any(), eq(user.getUuid())); - verify(userDeactivator).deactivateUser(any(), eq(user.getLogin())); - verify(userDeactivator, never()).deactivateUserWithAnonymization(any(), eq(user.getLogin())); + assertThat(db.getDbClient().sessionTokensDao().selectByUuid(dbSession, sessionToken1.getUuid())).isNotPresent(); + assertThat(db.getDbClient().sessionTokensDao().selectByUuid(dbSession, sessionToken2.getUuid())).isNotPresent(); + assertThat(db.getDbClient().sessionTokensDao().selectByUuid(dbSession, sessionToken3.getUuid())).isPresent(); + } + + @Test + public void deactivate_user_deletes_their_dismissed_messages() { + createAdminUser(); + ProjectDto project1 = db.components().insertPrivateProject().getProjectDto(); + ProjectDto project2 = db.components().insertPrivateProject().getProjectDto(); + UserDto user = db.users().insertUser(); + + db.users().insertUserDismissedMessage(user, project1, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE); + db.users().insertUserDismissedMessage(user, project2, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE); + UserDto anotherUser = db.users().insertUser(); + UserDismissedMessageDto msg3 = db.users().insertUserDismissedMessage(anotherUser, project1, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE); + UserDismissedMessageDto msg4 = db.users().insertUserDismissedMessage(anotherUser, project2, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE); + + userService.deactivate(user.getLogin(), false); + + assertThat(db.getDbClient().userDismissedMessagesDao().selectByUser(dbSession, user)).isEmpty(); + assertThat(db.getDbClient().userDismissedMessagesDao().selectByUser(dbSession, anotherUser)) + .extracting(UserDismissedMessageDto::getUuid) + .containsExactlyInAnyOrder(msg3.getUuid(), msg4.getUuid()); + } + + @Test + public void fail_if_user_does_not_exist() { + + assertThatThrownBy(() -> { + userService.deactivate("someone", false); + }) + .isInstanceOf(NotFoundException.class) + .hasMessage("User 'someone' not found"); + } + + @Test + public void fail_to_deactivate_last_administrator() { + UserDto admin = db.users().insertUser(); + db.users().insertGlobalPermissionOnUser(admin, GlobalPermission.ADMINISTER); + + assertThatThrownBy(() -> { + userService.deactivate(admin.getLogin(), false); + }) + .isInstanceOf(BadRequestException.class) + .hasMessage("User is last administrator, and cannot be deactivated"); } @Test - public void deactivate_whenAnonymizeIsTrue_shouldDeactivateUserWithAnonymization() { + public void administrators_can_be_deactivated_if_there_are_still_other_administrators() { + UserDto admin = createAdminUser(); + + UserDto anotherAdmin = createAdminUser(); + + userService.deactivate(admin.getLogin(), false); + + verifyThatUserIsDeactivated(admin.getLogin()); + verifyThatUserExists(anotherAdmin.getLogin()); + } + + @Test + public void anonymizeUser_whenSamlAndScimUser_shouldDeleteScimMapping() { + createAdminUser(); UserDto user = db.users().insertUser(); + db.getDbClient().scimUserDao().enableScimForUser(dbSession, user.getUuid()); + db.commit(); userService.deactivate(user.getLogin(), true); - verify(managedInstanceChecker).throwIfUserIsManaged(any(), eq(user.getUuid())); - verify(userDeactivator).deactivateUserWithAnonymization(any(), eq(user.getLogin())); - verify(userDeactivator, never()).deactivateUser(any(), eq(user.getLogin())); + assertThat(db.getDbClient().scimUserDao().findByUserUuid(dbSession, user.getUuid())).isEmpty(); + } + + @Test + public void handle_whenUserManagedAndInstanceManaged_shouldThrow() { + createAdminUser(); + UserDto user = db.users().insertUser(); + doThrow(new IllegalStateException("User managed")).when(managedInstanceChecker).throwIfUserIsManaged(any(), eq(user.getUuid())); + + String login = user.getLogin(); + assertThatThrownBy(() -> userService.deactivate(login, false)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("User managed"); } @Test @@ -573,14 +813,14 @@ public class UserServiceIT { @Test public void createUser_whenDuplicatesInScmAccounts_shouldFail() { - UserCreateRequest userCreateRequest = UserCreateRequest.builder() - .setLogin("john") - .setName("John") - .setEmail("john@email.com") - .setScmAccounts(List.of("admin", "admin")) - .setPassword("1234") - .setLocal(true) - .build(); + UserCreateRequest userCreateRequest = UserCreateRequest.builder() + .setLogin("john") + .setName("John") + .setEmail("john@email.com") + .setScmAccounts(List.of("admin", "admin")) + .setPassword("1234") + .setLocal(true) + .build(); assertThatThrownBy(() -> userService.createUser(userCreateRequest)) .isInstanceOf(IllegalArgumentException.class) @@ -653,4 +893,32 @@ public class UserServiceIT { .isEqualTo(badRequestException); } + private void verifyThatUserIsDeactivated(String login) { + Optional<UserDto> user = db.users().selectUserByLogin(login); + assertThat(user).isPresent(); + assertThat(user.get().isActive()).isFalse(); + assertThat(user.get().getEmail()).isNull(); + assertThat(user.get().getSortedScmAccounts()).isEmpty(); + } + + private void verifyThatUserIsAnomymized(String login) { + Optional<UserDto> user = db.users().selectUserByLogin(login); + assertThat(user).isPresent(); + assertThat(user.get().getName()).isEqualTo(login); + assertThat(user.get().getExternalLogin()).isEqualTo(login); + assertThat(user.get().getExternalId()).isEqualTo(login); + assertThat(user.get().getExternalIdentityProvider()).isEqualTo(ExternalIdentity.SQ_AUTHORITY); + } + + private UserDto createAdminUser() { + UserDto admin = db.users().insertUser(); + db.users().insertGlobalPermissionOnUser(admin, GlobalPermission.ADMINISTER); + db.commit(); + return admin; + } + + private void verifyThatUserExists(String login) { + assertThat(db.users().selectUserByLogin(login)).isPresent(); + } + } |