api 'com.google.guava:guava'
api project(':server:sonar-db-dao')
+ api project(':server:sonar-webserver-auth')
api project(':server:sonar-webserver-ws')
compileOnlyApi 'com.google.code.findbugs:jsr305'
import org.sonar.db.user.UserDto;
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.UserDeactivator;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.management.ManagedInstanceService;
import static java.util.Arrays.asList;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.ArgumentMatchers.any;
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;
public class UserServiceIT {
private final ManagedInstanceService managedInstanceService = mock(ManagedInstanceService.class);
- private final UserService userService = new UserService(db.getDbClient(), new AvatarResolverImpl(), managedInstanceService);
+ private final ManagedInstanceChecker managedInstanceChecker = mock(ManagedInstanceChecker.class);
+
+ private final UserDeactivator userDeactivator = mock(UserDeactivator.class);
+
+ private final UserService userService = new UserService(db.getDbClient(), new AvatarResolverImpl(), managedInstanceService, managedInstanceChecker, userDeactivator);
@Test
public void search_for_all_active_users() {
.extracting(r -> r.userDto().getLogin(), UserSearchResult::managed)
.containsExactlyInAnyOrder(
tuple(managedUser.getLogin(), true),
- tuple(nonManagedUser.getLogin(), false)
- );
+ tuple(nonManagedUser.getLogin(), false));
}
assertThat(users.searchResults())
.extracting(r -> r.userDto().getLogin(), UserSearchResult::managed)
.containsExactlyInAnyOrder(
- tuple(managedUser.getLogin(), true)
- );
+ tuple(managedUser.getLogin(), true));
}
assertThat(users.searchResults())
.extracting(r -> r.userDto().getLogin(), UserSearchResult::managed)
.containsExactlyInAnyOrder(
- tuple(nonManagedUser.getLogin(), false)
- );
+ tuple(nonManagedUser.getLogin(), false));
}
private void mockInstanceExternallyManagedAndFilterForManagedUsers() {
.extracting(
r -> r.userDto().getLogin(),
userSearchResult -> userSearchResult.userDto().getExternalLogin(),
- userSearchResult -> userSearchResult.userDto().getExternalIdentityProvider()
- )
+ userSearchResult -> userSearchResult.userDto().getExternalIdentityProvider())
.containsExactlyInAnyOrder(tuple(user.getLogin(), user.getExternalLogin(), user.getExternalIdentityProvider()));
}
assertUserWithFilter(b -> b.setSonarLintLastConnectionDateFrom(DateUtils.formatDateTime(lastConnection.toEpochMilli())), user.getLogin(), false);
assertUserWithFilter(b -> b.setSonarLintLastConnectionDateTo(DateUtils.formatDateTime(lastConnection.toEpochMilli())), user.getLogin(), true);
+ }
+
+ @Test
+ public void deactivate_whenUserIsNotFound_shouldThrowNotFoundException() {
+ assertThatThrownBy(() -> userService.deactivate("userToDelete", false))
+ .isInstanceOf(NotFoundException.class)
+ .hasMessage("User 'userToDelete' not found");
+ }
+
+ @Test
+ public void deactivate_whenInstanceIsManagedAndUserIsManaged_shouldThrowBadRequestException() {
+ 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);
+
+ }
+
+ @Test
+ public void deactivate_whenAnonymizeIsFalse_shouldDeactivateUser() {
+ UserDto user = db.users().insertUser();
+
+ 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()));
+ }
+
+ @Test
+ public void deactivate_whenAnonymizeIsTrue_shouldDeactivateUserWithAnonymization() {
+ UserDto user = db.users().insertUser();
+
+ 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()));
}
private void assertUserWithFilter(Function<UsersSearchRequest.Builder, UsersSearchRequest.Builder> query, String userLogin, boolean isExpectedToBeThere) {
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info 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.common.management;
+
+import org.sonar.db.DbSession;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.management.ManagedInstanceService;
+import org.sonar.server.management.ManagedProjectService;
+
+public class ManagedInstanceChecker {
+
+ private static final String INSTANCE_EXCEPTION_MESSAGE = "Operation not allowed when the instance is externally managed.";
+ private static final String PROJECT_EXCEPTION_MESSAGE = "Operation not allowed when the project is externally managed.";
+
+ private final ManagedInstanceService managedInstanceService;
+ private final ManagedProjectService managedProjectService;
+
+ public ManagedInstanceChecker(ManagedInstanceService managedInstanceService, ManagedProjectService managedProjectService) {
+ this.managedInstanceService = managedInstanceService;
+ this.managedProjectService = managedProjectService;
+ }
+
+ public void throwIfInstanceIsManaged() {
+ BadRequestException.checkRequest(!managedInstanceService.isInstanceExternallyManaged(), INSTANCE_EXCEPTION_MESSAGE);
+ }
+
+ public void throwIfProjectIsManaged(DbSession dbSession, String projectUuid) {
+ BadRequestException.checkRequest(!managedProjectService.isProjectManaged(dbSession, projectUuid), PROJECT_EXCEPTION_MESSAGE);
+ }
+
+ public void throwIfUserIsManaged(DbSession dbSession, String userUuid) {
+ BadRequestException.checkRequest(!managedInstanceService.isUserManaged(dbSession, userUuid), INSTANCE_EXCEPTION_MESSAGE);
+ }
+
+ public void throwIfUserAndProjectAreManaged(DbSession dbSession, String userUuid, String projectUuid) {
+ boolean isUserManaged = managedInstanceService.isUserManaged(dbSession, userUuid);
+ boolean isProjectManaged = managedProjectService.isProjectManaged(dbSession, projectUuid);
+ BadRequestException.checkRequest(!(isUserManaged && isProjectManaged), PROJECT_EXCEPTION_MESSAGE);
+ }
+
+ public void throwIfGroupAndProjectAreManaged(DbSession dbSession, String groupUuid, String projectUuid) {
+ boolean isGroupManaged = managedInstanceService.isGroupManaged(dbSession, groupUuid);
+ boolean isProjectManaged = managedProjectService.isProjectManaged(dbSession, projectUuid);
+ BadRequestException.checkRequest(!(isGroupManaged && isProjectManaged), PROJECT_EXCEPTION_MESSAGE);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.common.management;
+
+import javax.annotation.ParametersAreNonnullByDefault;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info 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.common.user;
+
+import java.util.function.Supplier;
+import javax.inject.Inject;
+import org.apache.commons.lang.RandomStringUtils;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.user.ExternalIdentity;
+
+public class UserAnonymizer {
+ private static final int LOGIN_RANDOM_LENGTH = 6;
+
+ private final DbClient dbClient;
+ private final Supplier<String> randomNameGenerator;
+
+ @Inject
+ public UserAnonymizer(DbClient dbClient) {
+ this(dbClient, () -> "sq-removed-" + RandomStringUtils.randomAlphanumeric(LOGIN_RANDOM_LENGTH));
+ }
+
+ public UserAnonymizer(DbClient dbClient, Supplier<String> randomNameGenerator) {
+ this.dbClient = dbClient;
+ this.randomNameGenerator = randomNameGenerator;
+ }
+
+ public void anonymize(DbSession session, UserDto user) {
+ String newLogin = generateAnonymousLogin(session);
+ user
+ .setLogin(newLogin)
+ .setName(newLogin)
+ .setExternalIdentityProvider(ExternalIdentity.SQ_AUTHORITY)
+ .setLocal(true)
+ .setExternalId(newLogin)
+ .setExternalLogin(newLogin);
+ }
+
+ private String generateAnonymousLogin(DbSession session) {
+ for (int i = 0; i < 10; i++) {
+ String candidate = randomNameGenerator.get();
+ if (dbClient.userDao().selectByLogin(session, candidate) == null) {
+ return candidate;
+ }
+ }
+ throw new IllegalStateException("Could not find a unique login");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info 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.common.user;
+
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.property.PropertyQuery;
+import org.sonar.db.user.UserDto;
+
+import static org.sonar.api.CoreProperties.DEFAULT_ISSUE_ASSIGNEE;
+import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
+import static org.sonar.server.exceptions.BadRequestException.checkRequest;
+import static org.sonar.server.exceptions.NotFoundException.checkFound;
+
+public class UserDeactivator {
+ private final DbClient dbClient;
+ private final UserAnonymizer userAnonymizer;
+
+ public UserDeactivator(DbClient dbClient, UserAnonymizer userAnonymizer) {
+ this.dbClient = dbClient;
+ this.userAnonymizer = userAnonymizer;
+ }
+
+ public UserDto deactivateUser(DbSession dbSession, String login) {
+ UserDto user = doBeforeDeactivation(dbSession, login);
+ deactivateUser(dbSession, user);
+ return user;
+ }
+
+ public UserDto deactivateUserWithAnonymization(DbSession dbSession, String login) {
+ UserDto user = doBeforeDeactivation(dbSession, login);
+ anonymizeUser(dbSession, user);
+ deactivateUser(dbSession, user);
+ return user;
+ }
+
+ private UserDto doBeforeDeactivation(DbSession dbSession, String login) {
+ UserDto user = getUserOrThrow(dbSession, login);
+ ensureNotLastAdministrator(dbSession, user);
+ deleteRelatedData(dbSession, user);
+ return user;
+ }
+
+ private UserDto getUserOrThrow(DbSession dbSession, String login) {
+ UserDto user = dbClient.userDao().selectByLogin(dbSession, login);
+ return checkFound(user, "User '%s' doesn't exist", login);
+ }
+
+ private void ensureNotLastAdministrator(DbSession dbSession, UserDto user) {
+ boolean isLastAdmin = dbClient.authorizationDao().countUsersWithGlobalPermissionExcludingUser(dbSession, ADMINISTER.getKey(), user.getUuid()) == 0;
+ checkRequest(!isLastAdmin, "User is last administrator, and cannot be deactivated");
+ }
+
+ private void deleteRelatedData(DbSession dbSession, UserDto user) {
+ String userUuid = user.getUuid();
+ dbClient.userTokenDao().deleteByUser(dbSession, user);
+ dbClient.propertiesDao().deleteByKeyAndValue(dbSession, DEFAULT_ISSUE_ASSIGNEE, user.getLogin());
+ dbClient.propertiesDao().deleteByQuery(dbSession, PropertyQuery.builder().setUserUuid(userUuid).build());
+ dbClient.userGroupDao().deleteByUserUuid(dbSession, user);
+ dbClient.userPermissionDao().deleteByUserUuid(dbSession, user);
+ dbClient.permissionTemplateDao().deleteUserPermissionsByUserUuid(dbSession, userUuid, user.getLogin());
+ dbClient.qProfileEditUsersDao().deleteByUser(dbSession, user);
+ dbClient.almPatDao().deleteByUser(dbSession, user);
+ dbClient.sessionTokensDao().deleteByUser(dbSession, user);
+ dbClient.userDismissedMessagesDao().deleteByUser(dbSession, user);
+ dbClient.qualityGateUserPermissionDao().deleteByUser(dbSession, user);
+ }
+
+ private void anonymizeUser(DbSession dbSession, UserDto user) {
+ userAnonymizer.anonymize(dbSession, user);
+ dbClient.userDao().update(dbSession, user);
+ dbClient.scimUserDao().deleteByUserUuid(dbSession, user.getUuid());
+ }
+
+ private void deactivateUser(DbSession dbSession, UserDto user) {
+ dbClient.userDao().deactivateUser(dbSession, user);
+ dbSession.commit();
+ }
+}
import org.sonar.db.user.UserQuery;
import org.sonar.server.common.SearchResults;
import org.sonar.server.common.avatar.AvatarResolver;
+import org.sonar.server.common.management.ManagedInstanceChecker;
+import org.sonar.server.common.user.UserDeactivator;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.management.ManagedInstanceService;
import static java.util.Comparator.comparing;
+import static org.sonar.server.exceptions.NotFoundException.checkFound;
public class UserService {
private final DbClient dbClient;
private final AvatarResolver avatarResolver;
private final ManagedInstanceService managedInstanceService;
-
- public UserService(DbClient dbClient, AvatarResolver avatarResolver, ManagedInstanceService managedInstanceService) {
+ private final ManagedInstanceChecker managedInstanceChecker;
+ private final UserDeactivator userDeactivator;
+
+ public UserService(
+ DbClient dbClient,
+ AvatarResolver avatarResolver,
+ ManagedInstanceService managedInstanceService,
+ ManagedInstanceChecker managedInstanceChecker,
+ UserDeactivator userDeactivator) {
this.dbClient = dbClient;
this.avatarResolver = avatarResolver;
this.managedInstanceService = managedInstanceService;
+ this.managedInstanceChecker = managedInstanceChecker;
+ this.userDeactivator = userDeactivator;
}
public SearchResults<UserSearchResult> findUsers(UsersSearchRequest request) {
Map<String, Boolean> userUuidToIsManaged = managedInstanceService.getUserUuidToManaged(dbSession, getUserUuids(userDtos));
return userDtos.stream()
.map(userDto -> toUserSearchResult(
- groupsByLogin.get(userDto.getLogin()),
- tokenCountsByLogin.getOrDefault(userDto.getUuid(), 0),
- userUuidToIsManaged.getOrDefault(userDto.getUuid(), false),
- userDto
- )
- ).toList();
+ groupsByLogin.get(userDto.getLogin()),
+ tokenCountsByLogin.getOrDefault(userDto.getUuid(), 0),
+ userUuidToIsManaged.getOrDefault(userDto.getUuid(), false),
+ userDto))
+ .toList();
}
private UserSearchResult toUserSearchResult(Collection<String> groups, int tokenCount, boolean managed, UserDto userDto) {
managed,
findAvatar(userDto),
groups,
- tokenCount
- );
+ tokenCount);
}
private List<UserDto> findUsersAndSortByLogin(DbSession dbSession, UserQuery userQuery, int page, int pageSize) {
return users.stream().map(UserDto::getUuid).collect(Collectors.toSet());
}
+ public UserDto deactivate(String login, Boolean anonymize) {
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ UserDto userDto = checkFound(dbClient.userDao().selectByLogin(dbSession, login), "User '%s' not found", login);
+ managedInstanceChecker.throwIfUserIsManaged(dbSession, userDto.getUuid());
+ UserDto deactivatedUser;
+ if (Boolean.TRUE.equals(anonymize)) {
+ deactivatedUser = userDeactivator.deactivateUserWithAnonymization(dbSession, login);
+ } else {
+ deactivatedUser = userDeactivator.deactivateUser(dbSession, login);
+ }
+ dbSession.commit();
+ return deactivatedUser;
+ }
+ }
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info 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 com.sonar.server.common.management;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.sonar.db.DbSession;
+import org.sonar.db.project.ProjectDto;
+import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.common.management.ManagedInstanceChecker;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.management.ManagedInstanceService;
+import org.sonar.server.management.ManagedProjectService;
+
+import static org.assertj.core.api.Assertions.assertThatNoException;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ManagedInstanceCheckerTest {
+
+ private static final String INSTANCE_EXCEPTION_MESSAGE = "Operation not allowed when the instance is externally managed.";
+ private static final String PROJECT_EXCEPTION_MESSAGE = "Operation not allowed when the project is externally managed.";
+
+ @Mock
+ private DbSession dbSession;
+ @Mock
+ private ManagedInstanceService managedInstanceService;
+ @Mock
+ private ManagedProjectService managedProjectService;
+ @InjectMocks
+ private ManagedInstanceChecker managedInstanceChecker;
+
+ @Test
+ public void throwIfInstanceIsManaged_whenInstanceExternallyManaged_shouldThrow() {
+ when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(true);
+
+ assertThatThrownBy(() -> managedInstanceChecker.throwIfInstanceIsManaged())
+ .isInstanceOf(BadRequestException.class)
+ .hasMessage(INSTANCE_EXCEPTION_MESSAGE);
+ }
+
+ @Test
+ public void throwIfInstanceIsManaged_whenInstanceNotExternallyManaged_shouldNotThrow() {
+ when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(false);
+
+ assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfInstanceIsManaged());
+ }
+
+ @Test
+ public void throwIfProjectIsManaged_whenProjectIsManaged_shouldThrow() {
+ ProjectDto projectDto = mockManagedProject();
+
+ String projectUuid = projectDto.getUuid();
+ assertThatThrownBy(() -> managedInstanceChecker.throwIfProjectIsManaged(dbSession, projectUuid))
+ .isInstanceOf(BadRequestException.class)
+ .hasMessage(PROJECT_EXCEPTION_MESSAGE);
+ }
+
+ @Test
+ public void throwIfProjectIsManaged_whenProjectIsNotManaged_shouldNotThrow() {
+ ProjectDto projectDto = mockNotManagedProject();
+
+ assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfProjectIsManaged(dbSession, projectDto.getUuid()));
+ }
+
+ @Test
+ public void throwIfUserIsManaged_whenUserIsManaged_shouldThrow() {
+ UserDto userDto = mockManagedUser();
+
+ String userUuid = userDto.getUuid();
+ assertThatThrownBy(() -> managedInstanceChecker.throwIfUserIsManaged(dbSession, userUuid))
+ .isInstanceOf(BadRequestException.class)
+ .hasMessage(INSTANCE_EXCEPTION_MESSAGE);
+ }
+
+ @Test
+ public void throwIfUserIsManaged_whenUserIsNotManaged_shouldNotThrow() {
+ UserDto userDto = mockNotManagedUser();
+
+ assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfUserIsManaged(dbSession, userDto.getUuid()));
+ }
+
+ @Test
+ public void throwIfUserAndProjectAreManaged_whenUserAndProjectAreManaged_shouldThrow() {
+ ProjectDto projectDto = mockManagedProject();
+ UserDto userDto = mockManagedUser();
+
+ String userUuid = userDto.getUuid();
+ String projectUuid = projectDto.getUuid();
+ assertThatThrownBy(() -> managedInstanceChecker.throwIfUserAndProjectAreManaged(dbSession, userUuid, projectUuid))
+ .isInstanceOf(BadRequestException.class)
+ .hasMessage(PROJECT_EXCEPTION_MESSAGE);
+ }
+
+ @Test
+ public void throwIfUserAndProjectAreManaged_whenOnlyUserIsManaged_shouldNotThrow() {
+ ProjectDto projectDto = mockNotManagedProject();
+ UserDto userDto = mockManagedUser();
+
+ assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfUserAndProjectAreManaged(dbSession, userDto.getUuid(), projectDto.getUuid()));
+ }
+
+ @Test
+ public void throwIfUserAndProjectAreManaged_whenOnlyProjectIsManaged_shouldNotThrow() {
+ ProjectDto projectDto = mockManagedProject();
+ UserDto userDto = mockNotManagedUser();
+
+ assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfUserAndProjectAreManaged(dbSession, userDto.getUuid(), projectDto.getUuid()));
+ }
+
+ @Test
+ public void throwIfUserAndProjectAreManaged_whenNothingIsManaged_shouldNotThrow() {
+ ProjectDto projectDto = mockNotManagedProject();
+ UserDto userDto = mockNotManagedUser();
+
+ assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfUserAndProjectAreManaged(dbSession, userDto.getUuid(), projectDto.getUuid()));
+ }
+
+ @Test
+ public void throwIfGroupAndProjectAreManaged_whenGroupAndProjectAreManaged_shouldThrow() {
+ ProjectDto projectDto = mockManagedProject();
+ GroupDto groupDto = mockManagedGroup();
+
+ String groupDtoUuid = groupDto.getUuid();
+ String projectDtoUuid = projectDto.getUuid();
+ assertThatThrownBy(() -> managedInstanceChecker.throwIfGroupAndProjectAreManaged(dbSession, groupDtoUuid, projectDtoUuid))
+ .isInstanceOf(BadRequestException.class)
+ .hasMessage(PROJECT_EXCEPTION_MESSAGE);
+ }
+
+ @Test
+ public void throwIfGroupAndProjectAreManaged_whenOnlyGroupIsManaged_shouldNotThrow() {
+ ProjectDto projectDto = mockNotManagedProject();
+ GroupDto groupDto = mockManagedGroup();
+
+ assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfGroupAndProjectAreManaged(dbSession, groupDto.getUuid(), projectDto.getUuid()));
+ }
+
+ @Test
+ public void throwIfGroupAndProjectAreManaged_whenOnlyProjectIsManaged_shouldNotThrow() {
+ ProjectDto projectDto = mockManagedProject();
+ GroupDto groupDto = mockNotManagedGroup();
+
+ assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfGroupAndProjectAreManaged(dbSession, groupDto.getUuid(), projectDto.getUuid()));
+ }
+
+ @Test
+ public void throwIfGroupAndProjectAreManaged_whenNothingIsManaged_shouldNotThrow() {
+ ProjectDto projectDto = mockNotManagedProject();
+ GroupDto groupDto = mockNotManagedGroup();
+
+ assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfGroupAndProjectAreManaged(dbSession, groupDto.getUuid(), projectDto.getUuid()));
+ }
+
+ private ProjectDto mockManagedProject() {
+ return mockProject(true);
+ }
+
+ private ProjectDto mockNotManagedProject() {
+ return mockProject(false);
+ }
+
+ private ProjectDto mockProject(boolean isManaged) {
+ ProjectDto projectDto = mock(ProjectDto.class);
+ when(managedProjectService.isProjectManaged(dbSession, projectDto.getUuid())).thenReturn(isManaged);
+ return projectDto;
+ }
+
+ private UserDto mockManagedUser() {
+ return mockUser(true);
+ }
+
+ private UserDto mockNotManagedUser() {
+ return mockUser(false);
+ }
+
+ private UserDto mockUser(boolean isManaged) {
+ UserDto userDto = mock(UserDto.class);
+ when(managedInstanceService.isUserManaged(dbSession, userDto.getUuid())).thenReturn(isManaged);
+ return userDto;
+ }
+
+ private GroupDto mockManagedGroup() {
+ return mockGroup(true);
+ }
+
+ private GroupDto mockNotManagedGroup() {
+ return mockGroup(false);
+ }
+
+ private GroupDto mockGroup(boolean isManaged) {
+ GroupDto groupDto = mock(GroupDto.class);
+ when(managedInstanceService.isGroupManaged(dbSession, groupDto.getUuid())).thenReturn(isManaged);
+ return groupDto;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info 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.v2.api.user.controller;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.sonar.db.DbClient;
+import org.sonar.db.user.UserDao;
+import org.sonar.server.common.user.service.UserService;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.user.AbstractUserSession;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.v2.common.ControllerIT;
+
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.sonar.server.v2.WebApiEndpoints.USER_ENDPOINT;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+public class DefaultUserControllerIT extends ControllerIT {
+
+ @After
+ public void resetUsedMocks() {
+ Mockito.reset(webAppContext.getBean(UserService.class));
+ Mockito.reset(webAppContext.getBean(UserSession.class));
+ }
+
+ @Before
+ public void setUp() {
+ UserSession userSession = webAppContext.getBean(UserSession.class);
+ when(userSession.checkLoggedIn()).thenReturn(userSession);
+ }
+
+ @Test
+ public void deactivate_whenUserIsNotLoggedIn_shouldReturnForbidden() throws Exception {
+ when(webAppContext.getBean(UserSession.class).checkLoggedIn()).thenThrow(new UnauthorizedException("unauthorized"));
+ mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
+ .andExpectAll(
+ status().isUnauthorized(),
+ content().string("{\"message\":\"unauthorized\"}"));
+ }
+
+ @Test
+ public void deactivate_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
+ when(webAppContext.getBean(UserSession.class).checkIsSystemAdministrator()).thenThrow(AbstractUserSession.insufficientPrivilegesException());
+ mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
+ .andExpectAll(
+ status().isForbidden(),
+ content().json("{\"message\":\"Insufficient privileges\"}"));
+ }
+
+ @Test
+ public void deactivate_whenUserServiceThrowsNotFoundException_shouldReturnNotFound() throws Exception {
+ doThrow(new NotFoundException("User not found.")).when(webAppContext.getBean(UserService.class)).deactivate("userToDelete", false);
+ mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
+ .andExpectAll(
+ status().isNotFound(),
+ content().json("{\"message\":\"User not found.\"}"));
+ }
+
+ @Test
+ public void deactivate_whenUserServiceThrowsBadRequestException_shouldReturnBadRequest() throws Exception {
+ doThrow(BadRequestException.create("Not allowed")).when(webAppContext.getBean(UserService.class)).deactivate("userToDelete", false);
+ mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
+ .andExpectAll(
+ status().isBadRequest(),
+ content().json("{\"message\":\"Not allowed\"}"));
+ }
+
+ @Test
+ public void deactivate_whenUserTryingToDeactivateThemself_shouldReturnBadRequest() throws Exception {
+ when(webAppContext.getBean(DbClient.class).userDao()).thenReturn(mock(UserDao.class));
+ when(webAppContext.getBean(UserSession.class).getLogin()).thenReturn("userToDelete");
+ mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
+ .andExpectAll(
+ status().isBadRequest(),
+ content().json("{\"message\":\"Self-deactivation is not possible\"}"));
+ }
+
+ @Test
+ public void deactivate_whenAnonymizeParameterIsNotBoolean_shouldReturnBadRequest() throws Exception {
+ mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete?anonymize=maybe"))
+ .andExpect(
+ status().isBadRequest());
+ }
+
+ @Test
+ public void deactivate_whenAnonymizeIsNotSpecified_shouldDeactivateUserWithoutAnonymization() throws Exception {
+ mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete"))
+ .andExpect(status().isNoContent());
+
+ verify(webAppContext.getBean(UserService.class)).deactivate("userToDelete", false);
+ }
+
+ @Test
+ public void deactivate_whenAnonymizeFalse_shouldDeactivateUserWithoutAnonymization() throws Exception {
+ mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete?anonymize=false"))
+ .andExpect(status().isNoContent());
+
+ verify(webAppContext.getBean(UserService.class)).deactivate("userToDelete", false);
+ }
+
+ @Test
+ public void deactivate_whenAnonymizeTrue_shouldDeactivateUserWithAnonymization() throws Exception {
+ mockMvc.perform(delete(USER_ENDPOINT + "/userToDelete?anonymize=true"))
+ .andExpect(status().isNoContent());
+
+ verify(webAppContext.getBean(UserService.class)).deactivate("userToDelete", true);
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info 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.v2.api.user.controller;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class DefaultUserControllerTest {
-
-}
import org.sonar.server.health.EsStatusNodeCheck;
import org.sonar.server.health.HealthChecker;
import org.sonar.server.health.WebServerStatusNodeCheck;
-import org.sonar.server.management.ManagedInstanceChecker;
import org.sonar.server.platform.NodeInformation;
import org.sonar.server.platform.ws.LivenessChecker;
import org.sonar.server.user.SystemPasscode;
return mock(UserUpdater.class);
}
- @Bean
- ManagedInstanceChecker managedInstanceChecker() {
- return mock(ManagedInstanceChecker.class);
- }
-
@Bean
UserService userService() {
return mock(UserService.class);
}
+
}
import org.sonar.server.v2.api.user.response.UsersSearchRestResponse;
import static org.sonar.api.utils.Paging.forPageIndex;
+import static org.sonar.server.exceptions.BadRequestException.checkRequest;
public class DefaultUserController implements UserController {
private final UsersSearchRestResponseGenerator usersSearchResponseGenerator;
private final UserService userService;
private final UserSession userSession;
- public DefaultUserController(UserSession userSession, UserService userService, UsersSearchRestResponseGenerator usersSearchResponseGenerator) {
+ public DefaultUserController(
+ UserSession userSession,
+ UserService userService,
+ UsersSearchRestResponseGenerator usersSearchResponseGenerator) {
this.userSession = userSession;
this.usersSearchResponseGenerator = usersSearchResponseGenerator;
this.userService = userService;
.build();
}
+ @Override
+ public void deactivate(String login, Boolean anonymize) {
+ userSession.checkLoggedIn().checkIsSystemAdministrator();
+ checkRequest(!login.equals(userSession.getLogin()), "Self-deactivation is not possible");
+ userService.deactivate(login, anonymize);
+ }
}
package org.sonar.server.v2.api.user.controller;
import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
import javax.validation.Valid;
import org.sonar.server.v2.api.model.RestPage;
import org.sonar.server.v2.api.user.request.UsersSearchRestRequest;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
Field 'sonarqubeLastConnectionDate' is only updated every hour, so it may not be accurate, for instance when a user authenticates many times in less than one hour.
""")
UsersSearchRestResponse search(@ParameterObject UsersSearchRestRequest usersSearchRestRequest, @Valid @ParameterObject RestPage restPage);
+
+ @DeleteMapping(path = "/{login}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ @Operation(summary = "Deactivate a user", description = "Deactivate a user. Requires Administer System permission.")
+ void deactivate(
+ @PathVariable("login") @Parameter(description = "The login of the user to delete.", required = true, in = ParameterIn.PATH) String login,
+ @RequestParam(value = "anonymize", required = false, defaultValue = "false") @Parameter(description = "Anonymize user in addition to deactivating it.") Boolean anonymize);
}
}
@Bean
- public UserController userController(UserSession userSession, UsersSearchRestResponseGenerator usersSearchResponseGenerator, UserService userService) {
+ public UserController userController(
+ UserSession userSession,
+ UsersSearchRestResponseGenerator usersSearchResponseGenerator,
+ UserService userService) {
return new DefaultUserController(userSession, userService, usersSearchResponseGenerator);
}
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.ServerException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionServiceImpl;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.ServerException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionServiceImpl;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionServiceImpl;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.ServerException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionServiceImpl;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.management.ManagedProjectService;
import org.sonar.server.permission.DefaultTemplatesResolver;
import org.sonar.server.permission.DefaultTemplatesResolverImpl;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionServiceImpl;
import org.sonar.server.permission.index.FooIndexDefinition;
import org.sonar.db.DbTester;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserQuery;
+import org.sonar.server.common.user.UserAnonymizer;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.user.NewUserNotifier;
import org.sonar.server.user.UserUpdater;
import org.sonar.db.user.SessionTokenDto;
import org.sonar.db.user.UserDismissedMessageDto;
import org.sonar.db.user.UserDto;
+import org.sonar.server.common.avatar.AvatarResolver;
+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.common.user.service.UserService;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.management.ManagedInstanceService;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.user.ExternalIdentity;
import org.sonar.server.ws.TestRequest;
private final UserDeactivator userDeactivator = new UserDeactivator(dbClient, userAnonymizer);
private final ManagedInstanceChecker managedInstanceChecker = mock(ManagedInstanceChecker.class);
- private final WsActionTester ws = new WsActionTester(new DeactivateAction(dbClient, userSession, new UserJsonWriter(userSession), userDeactivator, managedInstanceChecker));
+ private final UserService userService = new UserService(dbClient, mock(AvatarResolver.class), mock(ManagedInstanceService.class), managedInstanceChecker, userDeactivator);
+ private final WsActionTester ws = new WsActionTester(new DeactivateAction(dbClient, userSession, new UserJsonWriter(userSession), userService));
@Test
public void deactivate_user_and_delete_their_related_data() {
deactivate("someone");
})
.isInstanceOf(NotFoundException.class)
- .hasMessage("User 'someone' doesn't exist");
+ .hasMessage("User 'someone' not found");
}
@Test
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.common.avatar.AvatarResolverImpl;
+import org.sonar.server.common.management.ManagedInstanceChecker;
+import org.sonar.server.common.user.UserDeactivator;
import org.sonar.server.common.user.service.UserService;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ServerException;
private final ManagedInstanceService managedInstanceService = mock(ManagedInstanceService.class);
- private final UserService userService = new UserService(db.getDbClient(), new AvatarResolverImpl(), managedInstanceService);
+ private final UserService userService = new UserService(
+ db.getDbClient(),
+ new AvatarResolverImpl(),
+ managedInstanceService,
+ mock(ManagedInstanceChecker.class),
+ mock(UserDeactivator.class));
private final SearchWsReponseGenerator searchWsReponseGenerator = new SearchWsReponseGenerator(userSession);
.extracting(User::getLogin, User::getManaged)
.containsExactlyInAnyOrder(
tuple(managedUser.getLogin(), true),
- tuple(nonManagedUser.getLogin(), false)
- );
+ tuple(nonManagedUser.getLogin(), false));
}
@Test
assertThat(response.getUsersList())
.extracting(User::getLogin, User::getManaged)
.containsExactlyInAnyOrder(
- tuple(managedUser.getLogin(), true)
- );
+ tuple(managedUser.getLogin(), true));
}
@Test
assertThat(response.getUsersList())
.extracting(User::getLogin, User::getManaged)
.containsExactlyInAnyOrder(
- tuple(nonManagedUser.getLogin(), false)
- );
+ tuple(nonManagedUser.getLogin(), false));
}
private void mockInstanceExternallyManagedAndFilterForManagedUsers() {
userSession.logIn();
Stream.of(SearchAction.LAST_CONNECTION_DATE_FROM, SearchAction.LAST_CONNECTION_DATE_TO,
- SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_FROM, SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_TO)
+ SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_FROM, SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_TO)
.map(param -> ws.newRequest().setParam(param, formatDateTime(OffsetDateTime.now())))
.forEach(SearchActionIT::assertForbiddenException);
}
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.user.NewUserNotifier;
import org.sonar.server.user.UserUpdater;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.user.NewUserNotifier;
import org.sonar.server.user.UserUpdater;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.user.NewUserNotifier;
import org.sonar.server.user.UserUpdater;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.user.UserDto;
+import org.sonar.server.common.user.UserAnonymizer;
import org.sonar.server.user.ExternalIdentity;
import static org.assertj.core.api.Assertions.assertThat;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.usergroups.DefaultGroupFinder;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.ServerException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.usergroups.DefaultGroupFinder;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.ServerException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info 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.management;
-
-import org.sonar.db.DbSession;
-import org.sonar.server.exceptions.BadRequestException;
-
-public class ManagedInstanceChecker {
-
- private static final String INSTANCE_EXCEPTION_MESSAGE = "Operation not allowed when the instance is externally managed.";
- private static final String PROJECT_EXCEPTION_MESSAGE = "Operation not allowed when the project is externally managed.";
-
- private final ManagedInstanceService managedInstanceService;
- private final ManagedProjectService managedProjectService;
-
- public ManagedInstanceChecker(ManagedInstanceService managedInstanceService, ManagedProjectService managedProjectService) {
- this.managedInstanceService = managedInstanceService;
- this.managedProjectService = managedProjectService;
- }
-
- public void throwIfInstanceIsManaged() {
- BadRequestException.checkRequest(!managedInstanceService.isInstanceExternallyManaged(), INSTANCE_EXCEPTION_MESSAGE);
- }
-
- public void throwIfProjectIsManaged(DbSession dbSession, String projectUuid) {
- BadRequestException.checkRequest(!managedProjectService.isProjectManaged(dbSession, projectUuid), PROJECT_EXCEPTION_MESSAGE);
- }
-
- public void throwIfUserIsManaged(DbSession dbSession, String userUuid) {
- BadRequestException.checkRequest(!managedInstanceService.isUserManaged(dbSession, userUuid), INSTANCE_EXCEPTION_MESSAGE);
- }
-
- public void throwIfUserAndProjectAreManaged(DbSession dbSession, String userUuid, String projectUuid) {
- boolean isUserManaged = managedInstanceService.isUserManaged(dbSession, userUuid);
- boolean isProjectManaged = managedProjectService.isProjectManaged(dbSession, projectUuid);
- BadRequestException.checkRequest(!(isUserManaged && isProjectManaged), PROJECT_EXCEPTION_MESSAGE);
- }
-
- public void throwIfGroupAndProjectAreManaged(DbSession dbSession, String groupUuid, String projectUuid) {
- boolean isGroupManaged = managedInstanceService.isGroupManaged(dbSession, groupUuid);
- boolean isProjectManaged = managedProjectService.isProjectManaged(dbSession, projectUuid);
- BadRequestException.checkRequest(!(isGroupManaged && isProjectManaged), PROJECT_EXCEPTION_MESSAGE);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info 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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.server.management;
-
-import javax.annotation.ParametersAreNonnullByDefault;
import org.sonar.db.DbSession;
import org.sonar.db.entity.EntityDto;
import org.sonar.db.user.GroupDto;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.permission.GroupPermissionChange;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.permission.PermissionService;
import org.sonar.db.DbSession;
import org.sonar.db.entity.EntityDto;
import org.sonar.db.user.UserId;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.db.DbSession;
import org.sonar.db.entity.EntityDto;
import org.sonar.db.user.GroupDto;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.permission.GroupPermissionChange;
import org.sonar.server.permission.GroupUuidOrAnyone;
import org.sonar.server.permission.PermissionChange;
import org.sonar.db.DbSession;
import org.sonar.db.entity.EntityDto;
import org.sonar.db.user.UserId;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.db.entity.EntityDto;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.permission.PermissionTemplateService;
import org.sonar.server.permission.ws.PermissionWsSupport;
import org.sonar.server.permission.ws.PermissionsWsAction;
import org.sonar.db.DbSession;
import org.sonar.db.entity.EntityDto;
import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.project.Visibility;
import org.sonar.server.project.VisibilityService;
import org.sonar.server.user.UserSession;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.user.UserDto;
+import org.sonar.server.common.user.UserAnonymizer;
import org.sonar.server.user.UserSession;
import static org.sonar.server.exceptions.NotFoundException.checkFound;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.user.UserDto;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.user.ExternalIdentity;
import org.sonar.server.user.NewUser;
import org.sonar.server.user.UserSession;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.user.UserDto;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.user.service.UserService;
import org.sonar.server.user.UserSession;
import static java.util.Collections.singletonList;
private final DbClient dbClient;
private final UserSession userSession;
private final UserJsonWriter userWriter;
- private final UserDeactivator userDeactivator;
- private final ManagedInstanceChecker managedInstanceChecker;
+ private final UserService userService;
- public DeactivateAction(DbClient dbClient, UserSession userSession, UserJsonWriter userWriter,
- UserDeactivator userDeactivator, ManagedInstanceChecker managedInstanceChecker) {
+ public DeactivateAction(DbClient dbClient, UserSession userSession, UserJsonWriter userWriter, UserService userService) {
this.dbClient = dbClient;
this.userSession = userSession;
this.userWriter = userWriter;
- this.userDeactivator = userDeactivator;
- this.managedInstanceChecker = managedInstanceChecker;
+ this.userService = userService;
}
@Override
userSession.checkLoggedIn().checkIsSystemAdministrator();
String login = request.mandatoryParam(PARAM_LOGIN);
checkRequest(!login.equals(userSession.getLogin()), "Self-deactivation is not possible");
- try (DbSession dbSession = dbClient.openSession(false)) {
- UserDto userDto = dbClient.userDao().selectByLogin(dbSession, login);
- if (userDto != null) {
- managedInstanceChecker.throwIfUserIsManaged(dbSession, userDto.getUuid());
- }
- boolean shouldAnonymize = request.mandatoryParamAsBoolean(PARAM_ANONYMIZE);
- userDto = shouldAnonymize
- ? userDeactivator.deactivateUserWithAnonymization(dbSession, login)
- : userDeactivator.deactivateUser(dbSession, login);
- writeResponse(response, userDto.getLogin());
- }
+ boolean shouldAnonymize = request.mandatoryParamAsBoolean(PARAM_ANONYMIZE);
+ UserDto deactivatedUser = userService.deactivate(login, shouldAnonymize);
+ writeResponse(response, deactivatedUser.getLogin());
}
private void writeResponse(Response response, String login) {
}
}
-
-
}
import org.sonar.db.DbSession;
import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.user.UpdateUser;
import org.sonar.server.user.UserSession;
import org.sonar.server.user.UserUpdater;
import org.sonar.db.user.UserDto;
import org.sonar.server.authentication.IdentityProviderRepository;
import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.user.ExternalIdentity;
import org.sonar.server.user.UpdateUser;
import org.sonar.server.user.UserSession;
import org.sonar.db.DbSession;
import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.user.UpdateUser;
import org.sonar.server.user.UserSession;
import org.sonar.server.user.UserUpdater;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info 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.user.ws;
-
-import java.util.function.Supplier;
-import javax.inject.Inject;
-import org.apache.commons.lang.RandomStringUtils;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.user.UserDto;
-import org.sonar.server.user.ExternalIdentity;
-
-public class UserAnonymizer {
- private static final int LOGIN_RANDOM_LENGTH = 6;
-
- private final DbClient dbClient;
- private final Supplier<String> randomNameGenerator;
-
- @Inject
- public UserAnonymizer(DbClient dbClient) {
- this(dbClient, () -> "sq-removed-" + RandomStringUtils.randomAlphanumeric(LOGIN_RANDOM_LENGTH));
- }
-
- public UserAnonymizer(DbClient dbClient, Supplier<String> randomNameGenerator) {
- this.dbClient = dbClient;
- this.randomNameGenerator = randomNameGenerator;
- }
-
- public void anonymize(DbSession session, UserDto user) {
- String newLogin = generateAnonymousLogin(session);
- user
- .setLogin(newLogin)
- .setName(newLogin)
- .setExternalIdentityProvider(ExternalIdentity.SQ_AUTHORITY)
- .setLocal(true)
- .setExternalId(newLogin)
- .setExternalLogin(newLogin);
- }
-
- private String generateAnonymousLogin(DbSession session) {
- for (int i = 0; i < 10; i++) {
- String candidate = randomNameGenerator.get();
- if (dbClient.userDao().selectByLogin(session, candidate) == null) {
- return candidate;
- }
- }
- throw new IllegalStateException("Could not find a unique login");
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info 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.user.ws;
-
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.property.PropertyQuery;
-import org.sonar.db.user.UserDto;
-
-import static org.sonar.api.CoreProperties.DEFAULT_ISSUE_ASSIGNEE;
-import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
-import static org.sonar.server.exceptions.BadRequestException.checkRequest;
-import static org.sonar.server.exceptions.NotFoundException.checkFound;
-
-public class UserDeactivator {
- private final DbClient dbClient;
- private final UserAnonymizer userAnonymizer;
-
- public UserDeactivator(DbClient dbClient, UserAnonymizer userAnonymizer) {
- this.dbClient = dbClient;
- this.userAnonymizer = userAnonymizer;
- }
-
- public UserDto deactivateUser(DbSession dbSession, String login) {
- UserDto user = doBeforeDeactivation(dbSession, login);
- deactivateUser(dbSession, user);
- return user;
- }
-
- public UserDto deactivateUserWithAnonymization(DbSession dbSession, String login) {
- UserDto user = doBeforeDeactivation(dbSession, login);
- anonymizeUser(dbSession, user);
- deactivateUser(dbSession, user);
- return user;
- }
-
- private UserDto doBeforeDeactivation(DbSession dbSession, String login) {
- UserDto user = getUserOrThrow(dbSession, login);
- ensureNotLastAdministrator(dbSession, user);
- deleteRelatedData(dbSession, user);
- return user;
- }
-
- private UserDto getUserOrThrow(DbSession dbSession, String login) {
- UserDto user = dbClient.userDao().selectByLogin(dbSession, login);
- return checkFound(user, "User '%s' doesn't exist", login);
- }
-
- private void ensureNotLastAdministrator(DbSession dbSession, UserDto user) {
- boolean isLastAdmin = dbClient.authorizationDao().countUsersWithGlobalPermissionExcludingUser(dbSession, ADMINISTER.getKey(), user.getUuid()) == 0;
- checkRequest(!isLastAdmin, "User is last administrator, and cannot be deactivated");
- }
-
- private void deleteRelatedData(DbSession dbSession, UserDto user) {
- String userUuid = user.getUuid();
- dbClient.userTokenDao().deleteByUser(dbSession, user);
- dbClient.propertiesDao().deleteByKeyAndValue(dbSession, DEFAULT_ISSUE_ASSIGNEE, user.getLogin());
- dbClient.propertiesDao().deleteByQuery(dbSession, PropertyQuery.builder().setUserUuid(userUuid).build());
- dbClient.userGroupDao().deleteByUserUuid(dbSession, user);
- dbClient.userPermissionDao().deleteByUserUuid(dbSession, user);
- dbClient.permissionTemplateDao().deleteUserPermissionsByUserUuid(dbSession, userUuid, user.getLogin());
- dbClient.qProfileEditUsersDao().deleteByUser(dbSession, user);
- dbClient.almPatDao().deleteByUser(dbSession, user);
- dbClient.sessionTokensDao().deleteByUser(dbSession, user);
- dbClient.userDismissedMessagesDao().deleteByUser(dbSession, user);
- dbClient.qualityGateUserPermissionDao().deleteByUser(dbSession, user);
- }
-
- private void anonymizeUser(DbSession dbSession, UserDto user) {
- userAnonymizer.anonymize(dbSession, user);
- dbClient.userDao().update(dbSession, user);
- dbClient.scimUserDao().deleteByUserUuid(dbSession, user.getUuid());
- }
-
- private void deactivateUser(DbSession dbSession, UserDto user) {
- dbClient.userDao().deactivateUser(dbSession, user);
- dbSession.commit();
- }
-}
package org.sonar.server.user.ws;
import org.sonar.core.platform.Module;
+import org.sonar.server.common.user.UserAnonymizer;
+import org.sonar.server.common.user.UserDeactivator;
import org.sonar.server.common.user.service.UserService;
public class UsersWsModule extends Module {
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDto;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.user.UserSession;
import static java.lang.String.format;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.user.GroupDto;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.UserGroups;
import org.sonar.db.permission.GlobalPermission;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.user.UserSession;
import static java.lang.String.format;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserMembershipQuery;
import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.UserGroups;
package org.sonar.server.usergroups.ws;
import org.sonar.core.platform.Module;
-import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.common.management.ManagedInstanceChecker;
public class UserGroupsModule extends Module {
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info 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.management;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-import org.sonar.db.DbSession;
-import org.sonar.db.project.ProjectDto;
-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.assertThatNoException;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class ManagedInstanceCheckerTest {
-
- private static final String INSTANCE_EXCEPTION_MESSAGE = "Operation not allowed when the instance is externally managed.";
- private static final String PROJECT_EXCEPTION_MESSAGE = "Operation not allowed when the project is externally managed.";
-
- @Mock
- private DbSession dbSession;
- @Mock
- private ManagedInstanceService managedInstanceService;
- @Mock
- private ManagedProjectService managedProjectService;
- @InjectMocks
- private ManagedInstanceChecker managedInstanceChecker;
-
- @Test
- public void throwIfInstanceIsManaged_whenInstanceExternallyManaged_shouldThrow() {
- when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(true);
-
- assertThatThrownBy(() -> managedInstanceChecker.throwIfInstanceIsManaged())
- .isInstanceOf(BadRequestException.class)
- .hasMessage(INSTANCE_EXCEPTION_MESSAGE);
- }
-
- @Test
- public void throwIfInstanceIsManaged_whenInstanceNotExternallyManaged_shouldNotThrow() {
- when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(false);
-
- assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfInstanceIsManaged());
- }
-
- @Test
- public void throwIfProjectIsManaged_whenProjectIsManaged_shouldThrow() {
- ProjectDto projectDto = mockManagedProject();
-
- String projectUuid = projectDto.getUuid();
- assertThatThrownBy(() -> managedInstanceChecker.throwIfProjectIsManaged(dbSession, projectUuid))
- .isInstanceOf(BadRequestException.class)
- .hasMessage(PROJECT_EXCEPTION_MESSAGE);
- }
-
- @Test
- public void throwIfProjectIsManaged_whenProjectIsNotManaged_shouldNotThrow() {
- ProjectDto projectDto = mockNotManagedProject();
-
- assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfProjectIsManaged(dbSession, projectDto.getUuid()));
- }
-
- @Test
- public void throwIfUserIsManaged_whenUserIsManaged_shouldThrow() {
- UserDto userDto = mockManagedUser();
-
- String userUuid = userDto.getUuid();
- assertThatThrownBy(() -> managedInstanceChecker.throwIfUserIsManaged(dbSession, userUuid))
- .isInstanceOf(BadRequestException.class)
- .hasMessage(INSTANCE_EXCEPTION_MESSAGE);
- }
-
- @Test
- public void throwIfUserIsManaged_whenUserIsNotManaged_shouldNotThrow() {
- UserDto userDto = mockNotManagedUser();
-
- assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfUserIsManaged(dbSession, userDto.getUuid()));
- }
-
- @Test
- public void throwIfUserAndProjectAreManaged_whenUserAndProjectAreManaged_shouldThrow() {
- ProjectDto projectDto = mockManagedProject();
- UserDto userDto = mockManagedUser();
-
- String userUuid = userDto.getUuid();
- String projectUuid = projectDto.getUuid();
- assertThatThrownBy(() -> managedInstanceChecker.throwIfUserAndProjectAreManaged(dbSession, userUuid, projectUuid))
- .isInstanceOf(BadRequestException.class)
- .hasMessage(PROJECT_EXCEPTION_MESSAGE);
- }
-
- @Test
- public void throwIfUserAndProjectAreManaged_whenOnlyUserIsManaged_shouldNotThrow() {
- ProjectDto projectDto = mockNotManagedProject();
- UserDto userDto = mockManagedUser();
-
- assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfUserAndProjectAreManaged(dbSession, userDto.getUuid(), projectDto.getUuid()));
- }
-
- @Test
- public void throwIfUserAndProjectAreManaged_whenOnlyProjectIsManaged_shouldNotThrow() {
- ProjectDto projectDto = mockManagedProject();
- UserDto userDto = mockNotManagedUser();
-
- assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfUserAndProjectAreManaged(dbSession, userDto.getUuid(), projectDto.getUuid()));
- }
-
- @Test
- public void throwIfUserAndProjectAreManaged_whenNothingIsManaged_shouldNotThrow() {
- ProjectDto projectDto = mockNotManagedProject();
- UserDto userDto = mockNotManagedUser();
-
- assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfUserAndProjectAreManaged(dbSession, userDto.getUuid(), projectDto.getUuid()));
- }
-
- @Test
- public void throwIfGroupAndProjectAreManaged_whenGroupAndProjectAreManaged_shouldThrow() {
- ProjectDto projectDto = mockManagedProject();
- GroupDto groupDto = mockManagedGroup();
-
- String groupDtoUuid = groupDto.getUuid();
- String projectDtoUuid = projectDto.getUuid();
- assertThatThrownBy(() -> managedInstanceChecker.throwIfGroupAndProjectAreManaged(dbSession, groupDtoUuid, projectDtoUuid))
- .isInstanceOf(BadRequestException.class)
- .hasMessage(PROJECT_EXCEPTION_MESSAGE);
- }
-
- @Test
- public void throwIfGroupAndProjectAreManaged_whenOnlyGroupIsManaged_shouldNotThrow() {
- ProjectDto projectDto = mockNotManagedProject();
- GroupDto groupDto = mockManagedGroup();
-
- assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfGroupAndProjectAreManaged(dbSession, groupDto.getUuid(), projectDto.getUuid()));
- }
-
- @Test
- public void throwIfGroupAndProjectAreManaged_whenOnlyProjectIsManaged_shouldNotThrow() {
- ProjectDto projectDto = mockManagedProject();
- GroupDto groupDto = mockNotManagedGroup();
-
- assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfGroupAndProjectAreManaged(dbSession, groupDto.getUuid(), projectDto.getUuid()));
- }
-
- @Test
- public void throwIfGroupAndProjectAreManaged_whenNothingIsManaged_shouldNotThrow() {
- ProjectDto projectDto = mockNotManagedProject();
- GroupDto groupDto = mockNotManagedGroup();
-
- assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfGroupAndProjectAreManaged(dbSession, groupDto.getUuid(), projectDto.getUuid()));
- }
-
- private ProjectDto mockManagedProject() {
- return mockProject(true);
- }
-
- private ProjectDto mockNotManagedProject() {
- return mockProject(false);
- }
-
- private ProjectDto mockProject(boolean isManaged) {
- ProjectDto projectDto = mock(ProjectDto.class);
- when(managedProjectService.isProjectManaged(dbSession, projectDto.getUuid())).thenReturn(isManaged);
- return projectDto;
- }
-
- private UserDto mockManagedUser() {
- return mockUser(true);
- }
-
- private UserDto mockNotManagedUser() {
- return mockUser(false);
- }
-
- private UserDto mockUser(boolean isManaged) {
- UserDto userDto = mock(UserDto.class);
- when(managedInstanceService.isUserManaged(dbSession, userDto.getUuid())).thenReturn(isManaged);
- return userDto;
- }
-
- private GroupDto mockManagedGroup() {
- return mockGroup(true);
- }
-
- private GroupDto mockNotManagedGroup() {
- return mockGroup(false);
- }
-
- private GroupDto mockGroup(boolean isManaged) {
- GroupDto groupDto = mock(GroupDto.class);
- when(managedInstanceService.isGroupManaged(dbSession, groupDto.getUuid())).thenReturn(isManaged);
- return groupDto;
- }
-
-}