]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-18654 prevent editing groups when instance is managed.
authorWojtek Wajerowicz <115081248+wojciech-wajerowicz-sonarsource@users.noreply.github.com>
Wed, 8 Mar 2023 15:13:35 +0000 (16:13 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 22 Mar 2023 20:04:07 +0000 (20:04 +0000)
14 files changed:
server/sonar-webserver-webapi/src/it/java/org/sonar/server/usergroups/ws/AddUserActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/usergroups/ws/CreateActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/usergroups/ws/DeleteActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/usergroups/ws/RemoveUserActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/usergroups/ws/UpdateActionIT.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/management/ManagedInstanceChecker.java [new file with mode: 0644]
server/sonar-webserver-webapi/src/main/java/org/sonar/server/usergroups/ws/AddUserAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/usergroups/ws/CreateAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/usergroups/ws/DeleteAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/usergroups/ws/ManagedInstanceChecker.java [deleted file]
server/sonar-webserver-webapi/src/main/java/org/sonar/server/usergroups/ws/RemoveUserAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/usergroups/ws/UpdateAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/usergroups/ws/UserGroupsModule.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/management/ManagedInstanceCheckerTest.java [new file with mode: 0644]

index 63b9bc81f4736a10c15a9e96cae5583904bed93b..eae0bc78ecb710c3d4dc2c3bef3e602a7a6884e0 100644 (file)
@@ -27,8 +27,10 @@ import org.sonar.api.server.ws.WebService.Action;
 import org.sonar.db.DbTester;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDto;
+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.tester.UserSessionRule;
 import org.sonar.server.usergroups.DefaultGroupFinder;
 import org.sonar.server.ws.TestRequest;
@@ -39,6 +41,8 @@ import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
 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.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
 import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
 import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_NAME;
 import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_LOGIN;
@@ -50,7 +54,9 @@ public class AddUserActionIT {
   @Rule
   public UserSessionRule userSession = UserSessionRule.standalone();
 
-  private final WsActionTester ws = new WsActionTester(new AddUserAction(db.getDbClient(), userSession, newGroupWsSupport()));
+  private ManagedInstanceChecker managedInstanceChecker = mock(ManagedInstanceChecker.class);
+
+  private final WsActionTester ws = new WsActionTester(new AddUserAction(db.getDbClient(), userSession, newGroupWsSupport(), managedInstanceChecker));
 
   @Test
   public void verify_definition() {
@@ -212,6 +218,17 @@ public class AddUserActionIT {
       .hasMessage("Default group cannot be found");
   }
 
+  @Test
+  public void fail_if_instance_is_externally_managed() {
+    loginAsAdmin();
+    BadRequestException exception = BadRequestException.create("Not allowed");
+    doThrow(exception).when(managedInstanceChecker).throwIfInstanceIsManaged();
+    TestRequest testRequest = newRequest()
+      .setParam("name", "long-desc");
+    assertThatThrownBy(testRequest::execute)
+      .isEqualTo(exception);
+  }
+
   private void executeRequest(GroupDto groupDto, UserDto userDto) {
     newRequest()
       .setParam(PARAM_GROUP_NAME, groupDto.getName())
index 91a5963a31e894684100f717c6fc2394655e04dc..42043b7af36c0118dab342158540695f3cb6ccf9 100644 (file)
@@ -31,12 +31,16 @@ import org.sonar.db.user.GroupDto;
 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.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.WsActionTester;
 
 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.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
 import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
 
 public class CreateActionIT {
@@ -44,8 +48,9 @@ public class CreateActionIT {
   public DbTester db = DbTester.create(System2.INSTANCE);
   @Rule
   public UserSessionRule userSession = UserSessionRule.standalone();
+  private ManagedInstanceChecker managedInstanceChecker = mock(ManagedInstanceChecker.class);
 
-  private final CreateAction underTest = new CreateAction(db.getDbClient(), userSession, newGroupService());
+  private final CreateAction underTest = new CreateAction(db.getDbClient(), userSession, newGroupService(), managedInstanceChecker);
   private final WsActionTester tester = new WsActionTester(underTest);
 
   @Test
@@ -173,6 +178,16 @@ public class CreateActionIT {
       .isInstanceOf(IllegalArgumentException.class);
   }
 
+  @Test
+  public void fail_if_instance_is_externally_managed() {
+    loginAsAdmin();
+    BadRequestException exception = BadRequestException.create("Not allowed");
+    doThrow(exception).when(managedInstanceChecker).throwIfInstanceIsManaged();
+    TestRequest testRequest = tester.newRequest();
+    assertThatThrownBy(testRequest::execute)
+      .isEqualTo(exception);
+  }
+
   private void loginAsAdmin() {
     userSession.logIn().addPermission(ADMINISTER);
   }
index 46fe34bfde035026fbdfc3eed9a8f1937a00f4e0..81fa9575690cd7368cb4435fe4dc9e0b4f662b1c 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.server.usergroups.ws;
 
+import java.util.Map;
+import java.util.Set;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
@@ -26,6 +28,7 @@ import org.sonar.api.server.ws.Change;
 import org.sonar.api.server.ws.WebService.Action;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.util.UuidFactoryImpl;
+import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
@@ -35,7 +38,9 @@ import org.sonar.db.qualitygate.QualityGateDto;
 import org.sonar.db.qualityprofile.QProfileDto;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDto;
+import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.management.ManagedInstanceService;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.TestResponse;
@@ -45,6 +50,10 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 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.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
 import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_NAME;
 
@@ -57,7 +66,9 @@ public class DeleteActionIT {
 
   private final ComponentDbTester componentTester = new ComponentDbTester(db);
   private final GroupService groupService = new GroupService(db.getDbClient(), UuidFactoryImpl.INSTANCE);
-  private final WsActionTester ws = new WsActionTester(new DeleteAction(db.getDbClient(), userSession, groupService));
+
+  private final ManagedInstanceService managedInstanceService = mock(ManagedInstanceService.class);
+  private final WsActionTester ws = new WsActionTester(new DeleteAction(db.getDbClient(), userSession, groupService, managedInstanceService));
 
   @Test
   public void verify_definition() {
@@ -273,6 +284,46 @@ public class DeleteActionIT {
     assertThat(db.users().selectGroupPermissions(adminGroup2, null)).hasSize(1);
   }
 
+  @Test
+  public void delete_local_group_when_instance_is_managed_shouldSucceed() {
+    when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(true);
+
+    addAdmin();
+    insertDefaultGroup();
+    GroupDto group = insertGroupAndMockIsManaged(false);
+
+    loginAsAdmin();
+    TestResponse response = newRequest()
+      .setParam(PARAM_GROUP_NAME, group.getName())
+      .execute();
+
+    assertThat(response.getStatus()).isEqualTo(204);
+  }
+
+  @Test
+  public void fail_to_delete_managed_group_when_instance_is_managed() {
+    when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(true);
+    addAdmin();
+    insertDefaultGroup();
+    GroupDto group = insertGroupAndMockIsManaged(true);
+
+    loginAsAdmin();
+    TestRequest request = newRequest()
+      .setParam(PARAM_GROUP_NAME, group.getName());
+
+    assertThatThrownBy(request::execute)
+      .isInstanceOf(BadRequestException.class)
+      .hasMessage("Deleting managed groups is not allowed.");
+
+  }
+
+  private GroupDto insertGroupAndMockIsManaged(boolean isManaged) {
+    GroupDto group = db.users().insertGroup();
+    when(managedInstanceService.getGroupUuidToManaged(any(DbSession.class), eq(Set.of(group.getUuid()))))
+      .thenReturn(Map.of(group.getUuid(), isManaged));
+    return group;
+  }
+
   private void executeDeleteGroupRequest(GroupDto adminGroup1) {
     newRequest()
       .setParam(PARAM_GROUP_NAME, adminGroup1.getName())
index a8cef179bf1927e96e3c673e3b9235bd08383f04..088f91aef2d6031ef351752e537512e80d27f790 100644 (file)
@@ -30,6 +30,7 @@ import org.sonar.db.user.UserDto;
 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.tester.UserSessionRule;
 import org.sonar.server.usergroups.DefaultGroupFinder;
 import org.sonar.server.ws.TestRequest;
@@ -40,6 +41,8 @@ import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
 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.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
 import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
 import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_NAME;
 import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_LOGIN;
@@ -51,8 +54,9 @@ public class RemoveUserActionIT {
   @Rule
   public UserSessionRule userSession = UserSessionRule.standalone();
 
+  private ManagedInstanceChecker managedInstanceChecker = mock(ManagedInstanceChecker.class);
   private final WsActionTester ws = new WsActionTester(
-    new RemoveUserAction(db.getDbClient(), userSession, new GroupWsSupport(db.getDbClient(), new DefaultGroupFinder(db.getDbClient()))));
+    new RemoveUserAction(db.getDbClient(), userSession, new GroupWsSupport(db.getDbClient(), new DefaultGroupFinder(db.getDbClient())), managedInstanceChecker));
 
   @Test
   public void verify_definition() {
@@ -212,6 +216,16 @@ public class RemoveUserActionIT {
       .hasMessage("Default group 'sonar-users' cannot be used to perform this action");
   }
 
+  @Test
+  public void fail_if_instance_is_externally_managed() {
+    loginAsAdmin();
+    BadRequestException exception = BadRequestException.create("Not allowed");
+    doThrow(exception).when(managedInstanceChecker).throwIfInstanceIsManaged();
+    TestRequest testRequest = newRequest();
+    assertThatThrownBy(testRequest::execute)
+      .isEqualTo(exception);
+  }
+
   private TestRequest newRequest() {
     return ws.newRequest();
   }
index e77c5088a132719b26d2194fe013d3c3f826a2e3..c065b8e5300fe5b9e68d97dc92a0bbf47ea409c5 100644 (file)
@@ -32,12 +32,15 @@ import org.sonar.server.exceptions.BadRequestException;
 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.tester.UserSessionRule;
 import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.WsActionTester;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
 import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
 import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_CURRENT_NAME;
 import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_DESCRIPTION;
@@ -51,8 +54,10 @@ public class UpdateActionIT {
   @Rule
   public UserSessionRule userSession = UserSessionRule.standalone();
 
+  private ManagedInstanceChecker managedInstanceChecker = mock(ManagedInstanceChecker.class);
+
   private final WsActionTester ws = new WsActionTester(
-    new UpdateAction(db.getDbClient(), userSession, new GroupService(db.getDbClient(), UuidFactoryImpl.INSTANCE)));
+    new UpdateAction(db.getDbClient(), userSession, new GroupService(db.getDbClient(), UuidFactoryImpl.INSTANCE), managedInstanceChecker));
 
   @Test
   public void verify_definition() {
@@ -187,6 +192,7 @@ public class UpdateActionIT {
     TestRequest request = newRequest()
       .setParam(PARAM_GROUP_NAME, "newname");
 
+    loginAsAdmin();
     assertThatThrownBy(request::execute)
       .isInstanceOf(IllegalArgumentException.class)
       .hasMessage("The 'currentName' parameter is missing");
@@ -259,6 +265,16 @@ public class UpdateActionIT {
       .hasMessage("Default group 'sonar-users' cannot be used to perform this action");
   }
 
+  @Test
+  public void fail_if_instance_is_externally_managed() {
+    loginAsAdmin();
+    BadRequestException exception = BadRequestException.create("Not allowed");
+    doThrow(exception).when(managedInstanceChecker).throwIfInstanceIsManaged();
+    TestRequest testRequest = newRequest();
+    assertThatThrownBy(testRequest::execute)
+      .isEqualTo(exception);
+  }
+
   private TestRequest newRequest() {
     return ws.newRequest();
   }
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/management/ManagedInstanceChecker.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/management/ManagedInstanceChecker.java
new file mode 100644 (file)
index 0000000..ce27b4b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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.server.exceptions.BadRequestException;
+
+public class ManagedInstanceChecker {
+
+  private final ManagedInstanceService managedInstanceService;
+
+  public ManagedInstanceChecker(ManagedInstanceService managedInstanceService) {
+    this.managedInstanceService = managedInstanceService;
+  }
+
+  public void throwIfInstanceIsManaged() {
+    BadRequestException.checkRequest(!managedInstanceService.isInstanceExternallyManaged(), "Operation not allowed when the instance is externally managed.");
+  }
+}
index 51ddfd119bca62735f47672aae5a10d8661174cf..dfd97224ee690f29c8ea2393370336dbbd1e1ec5 100644 (file)
@@ -29,6 +29,7 @@ import org.sonar.db.DbSession;
 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.user.UserSession;
 
 import static java.lang.String.format;
@@ -44,11 +45,13 @@ public class AddUserAction implements UserGroupsWsAction {
   private final DbClient dbClient;
   private final UserSession userSession;
   private final GroupWsSupport support;
+  private final ManagedInstanceChecker managedInstanceChecker;
 
-  public AddUserAction(DbClient dbClient, UserSession userSession, GroupWsSupport support) {
+  public AddUserAction(DbClient dbClient, UserSession userSession, GroupWsSupport support, ManagedInstanceChecker managedInstanceChecker) {
     this.dbClient = dbClient;
     this.userSession = userSession;
     this.support = support;
+    this.managedInstanceChecker = managedInstanceChecker;
   }
 
   @Override
@@ -71,8 +74,9 @@ public class AddUserAction implements UserGroupsWsAction {
   @Override
   public void handle(Request request, Response response) throws Exception {
     try (DbSession dbSession = dbClient.openSession(false)) {
-      GroupDto group = support.findGroupDto(dbSession, request);
       userSession.checkLoggedIn().checkPermission(ADMINISTER);
+      managedInstanceChecker.throwIfInstanceIsManaged();
+      GroupDto group = support.findGroupDto(dbSession, request);
 
       String login = request.mandatoryParam(PARAM_LOGIN);
       UserDto user = dbClient.userDao().selectActiveUserByLogin(dbSession, login);
index 2448bbfdae58f775a574350d039acb9f06a7a938..cfc53523bfb600f1ccc3230a95d891d1e6f45f38 100644 (file)
@@ -27,6 +27,7 @@ import org.sonar.api.server.ws.WebService.NewController;
 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.user.UserSession;
 import org.sonarqube.ws.UserGroups;
 
@@ -44,11 +45,13 @@ public class CreateAction implements UserGroupsWsAction {
   private final DbClient dbClient;
   private final UserSession userSession;
   private final GroupService groupService;
+  private final ManagedInstanceChecker managedInstanceChecker;
 
-  public CreateAction(DbClient dbClient, UserSession userSession, GroupService groupService) {
+  public CreateAction(DbClient dbClient, UserSession userSession, GroupService groupService, ManagedInstanceChecker managedInstanceService) {
     this.dbClient = dbClient;
     this.userSession = userSession;
     this.groupService = groupService;
+    this.managedInstanceChecker = managedInstanceService;
   }
 
   @Override
@@ -81,7 +84,7 @@ public class CreateAction implements UserGroupsWsAction {
 
     try (DbSession dbSession = dbClient.openSession(false)) {
       userSession.checkPermission(ADMINISTER);
-
+      managedInstanceChecker.throwIfInstanceIsManaged();
       String groupName = request.mandatoryParam(PARAM_GROUP_NAME);
       String groupDescription = request.param(PARAM_GROUP_DESCRIPTION);
       GroupDto group = groupService.createGroup(dbSession, groupName, groupDescription);
index 91f6e62b2f090d1b937e6cda78b69add59534d88..bc16c54cca6cc893ecb862bd518779c89d5b6c6f 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.usergroups.ws;
 
+import java.util.Set;
 import org.sonar.api.server.ws.Change;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
@@ -28,7 +29,9 @@ import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.permission.GlobalPermission;
 import org.sonar.db.user.GroupDto;
+import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.management.ManagedInstanceService;
 import org.sonar.server.user.UserSession;
 
 import static java.lang.String.format;
@@ -40,11 +43,13 @@ public class DeleteAction implements UserGroupsWsAction {
   private final DbClient dbClient;
   private final UserSession userSession;
   private final GroupService groupService;
+  private final ManagedInstanceService managedInstanceService;
 
-  public DeleteAction(DbClient dbClient, UserSession userSession, GroupService groupService) {
+  public DeleteAction(DbClient dbClient, UserSession userSession, GroupService groupService, ManagedInstanceService managedInstanceService) {
     this.dbClient = dbClient;
     this.userSession = userSession;
     this.groupService = groupService;
+    this.managedInstanceService = managedInstanceService;
   }
 
   @Override
@@ -67,8 +72,8 @@ public class DeleteAction implements UserGroupsWsAction {
   public void handle(Request request, Response response) throws Exception {
     try (DbSession dbSession = dbClient.openSession(false)) {
       userSession.checkPermission(GlobalPermission.ADMINISTER);
-
       GroupDto group = findGroupOrThrow(request, dbSession);
+      checkIfInstanceAndGroupAreManaged(dbSession, group);
       groupService.delete(dbSession, group);
 
       dbSession.commit();
@@ -76,6 +81,13 @@ public class DeleteAction implements UserGroupsWsAction {
     }
   }
 
+  private void checkIfInstanceAndGroupAreManaged(DbSession dbSession, GroupDto group) {
+    boolean isGroupManaged = managedInstanceService.getGroupUuidToManaged(dbSession, Set.of(group.getUuid())).getOrDefault(group.getUuid(), false);
+    if (isGroupManaged) {
+      throw BadRequestException.create("Deleting managed groups is not allowed.");
+    }
+  }
+
   private GroupDto findGroupOrThrow(Request request, DbSession dbSession) {
     String groupName = request.mandatoryParam(PARAM_GROUP_NAME);
     return groupService.findGroup(dbSession, groupName)
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/usergroups/ws/ManagedInstanceChecker.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/usergroups/ws/ManagedInstanceChecker.java
deleted file mode 100644 (file)
index ed87df8..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.sonar.server.usergroups.ws;
-
-import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.management.ManagedInstanceService;
-
-public class ManagedInstanceChecker {
-
-  private final ManagedInstanceService managedInstanceService;
-
-  public ManagedInstanceChecker(ManagedInstanceService managedInstanceService) {
-    this.managedInstanceService = managedInstanceService;
-  }
-
-  public void checkInstanceIsNotExternallyManaged() {
-    BadRequestException.checkRequest(!managedInstanceService.isInstanceExternallyManaged(), "Operation not allowed when instance is externally managed.");
-  }
-}
index a7ef68faaa8bad25909510e93b7c7c6a93179220..7e4d301fd7612a1d63494d7f51b97bd53494713a 100644 (file)
@@ -29,6 +29,7 @@ import org.sonar.db.DbSession;
 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.user.UserSession;
 
 import static java.lang.String.format;
@@ -45,10 +46,13 @@ public class RemoveUserAction implements UserGroupsWsAction {
   private final UserSession userSession;
   private final GroupWsSupport support;
 
-  public RemoveUserAction(DbClient dbClient, UserSession userSession, GroupWsSupport support) {
+  private final ManagedInstanceChecker managedInstanceChecker;
+
+  public RemoveUserAction(DbClient dbClient, UserSession userSession, GroupWsSupport support, ManagedInstanceChecker managedInstanceChecker) {
     this.dbClient = dbClient;
     this.userSession = userSession;
     this.support = support;
+    this.managedInstanceChecker = managedInstanceChecker;
   }
 
   @Override
@@ -73,8 +77,9 @@ public class RemoveUserAction implements UserGroupsWsAction {
     userSession.checkLoggedIn();
 
     try (DbSession dbSession = dbClient.openSession(false)) {
-      GroupDto group = support.findGroupDto(dbSession, request);
       userSession.checkPermission(GlobalPermission.ADMINISTER);
+      managedInstanceChecker.throwIfInstanceIsManaged();
+      GroupDto group = support.findGroupDto(dbSession, request);
       support.checkGroupIsNotDefault(dbSession, group);
 
       String login = request.mandatoryParam(PARAM_LOGIN);
index 7c31c49b206f64d94dbdf3fcb2908d73776c4565..e67a3ae888780201e1337296391ce0af5eabd054 100644 (file)
@@ -29,6 +29,7 @@ import org.sonar.db.DbSession;
 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.user.UserSession;
 import org.sonarqube.ws.UserGroups;
 
@@ -49,10 +50,13 @@ public class UpdateAction implements UserGroupsWsAction {
   private final UserSession userSession;
   private final GroupService groupService;
 
-  public UpdateAction(DbClient dbClient, UserSession userSession, GroupService groupService) {
+  private final ManagedInstanceChecker managedInstanceChecker;
+
+  public UpdateAction(DbClient dbClient, UserSession userSession, GroupService groupService, ManagedInstanceChecker managedInstanceChecker) {
     this.dbClient = dbClient;
     this.userSession = userSession;
     this.groupService = groupService;
+    this.managedInstanceChecker = managedInstanceChecker;
   }
 
   @Override
@@ -92,12 +96,13 @@ public class UpdateAction implements UserGroupsWsAction {
   @Override
   public void handle(Request request, Response response) throws Exception {
     try (DbSession dbSession = dbClient.openSession(false)) {
+      userSession.checkPermission(ADMINISTER);
+      managedInstanceChecker.throwIfInstanceIsManaged();
       String currentName = request.mandatoryParam(PARAM_GROUP_CURRENT_NAME);
 
       GroupDto group = dbClient.groupDao().selectByName(dbSession, currentName)
         .orElseThrow(() -> new NotFoundException(format("Could not find a user group with name '%s'.", currentName)));
 
-      userSession.checkPermission(ADMINISTER);
       String newName = request.param(PARAM_GROUP_NAME);
       String description = request.param(PARAM_GROUP_DESCRIPTION);
 
index 9ca4ba906925725832b6cd37c6c86f90919d477d..b4dd9c03a1f7ae2a2b1344dac9695e11ed347ef5 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.usergroups.ws;
 
 import org.sonar.core.platform.Module;
+import org.sonar.server.management.ManagedInstanceChecker;
 
 public class UserGroupsModule extends Module {
 
@@ -28,6 +29,7 @@ public class UserGroupsModule extends Module {
     add(
       UserGroupsWs.class,
       GroupWsSupport.class,
+      ManagedInstanceChecker.class,
       GroupService.class,
       // actions
       SearchAction.class,
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/management/ManagedInstanceCheckerTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/management/ManagedInstanceCheckerTest.java
new file mode 100644 (file)
index 0000000..827bab8
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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.server.exceptions.BadRequestException;
+
+import static org.assertj.core.api.Assertions.assertThatNoException;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ManagedInstanceCheckerTest {
+
+  @Mock
+  private ManagedInstanceService managedInstanceService;
+
+  @InjectMocks
+  private ManagedInstanceChecker managedInstanceChecker;
+
+  @Test
+  public void throwIfInstanceIsManaged_whenInstanceExternallyManaged_throws() {
+    when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(true);
+    assertThatThrownBy(() -> managedInstanceChecker.throwIfInstanceIsManaged())
+      .isInstanceOf(BadRequestException.class)
+      .hasMessage("Operation not allowed when the instance is externally managed.");
+  }
+
+  @Test
+  public void throwIfInstanceIsManaged_whenInstanceNotExternallyManaged_doesntThrow() {
+    when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(false);
+    assertThatNoException().isThrownBy(() -> managedInstanceChecker.throwIfInstanceIsManaged());
+  }
+}