]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-17456 Fix SSF-326
authoralain <108417558+alain-kermis-sonarsource@users.noreply.github.com>
Thu, 20 Oct 2022 09:29:15 +0000 (11:29 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 20 Oct 2022 20:03:02 +0000 (20:03 +0000)
server/sonar-webserver-webapi/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java

index 19306b34ea71cdce567899312dfc9222f013c13f..ed824818842ff283aa9ca5bd4c54b07680ebef38 100644 (file)
@@ -35,12 +35,14 @@ import org.sonar.api.server.ws.WebService;
 import org.sonar.core.platform.PluginInfo;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
+import org.sonar.db.permission.GlobalPermission;
 import org.sonar.db.plugin.PluginDto;
 import org.sonar.db.plugin.PluginDto.Type;
 import org.sonar.core.plugin.PluginType;
 import org.sonar.server.plugins.ServerPlugin;
 import org.sonar.server.plugins.ServerPluginRepository;
 import org.sonar.server.plugins.UpdateCenterMatrixFactory;
+import org.sonar.server.user.UserSession;
 import org.sonar.updatecenter.common.Plugin;
 import org.sonarqube.ws.Plugins.InstalledPluginsWsResponse;
 import org.sonarqube.ws.Plugins.PluginDetails;
@@ -53,6 +55,7 @@ import static java.util.stream.Collectors.toMap;
 import static org.sonar.server.plugins.ws.PluginWSCommons.NAME_KEY_COMPARATOR;
 import static org.sonar.server.plugins.ws.PluginWSCommons.buildPluginDetails;
 import static org.sonar.server.plugins.ws.PluginWSCommons.compatiblePluginsByKey;
+import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 
 /**
@@ -62,11 +65,13 @@ public class InstalledAction implements PluginsWsAction {
   private static final String FIELD_CATEGORY = "category";
   private static final String PARAM_TYPE = "type";
 
+  private final UserSession userSession;
   private final ServerPluginRepository serverPluginRepository;
   private final UpdateCenterMatrixFactory updateCenterMatrixFactory;
   private final DbClient dbClient;
 
-  public InstalledAction(ServerPluginRepository serverPluginRepository, UpdateCenterMatrixFactory updateCenterMatrixFactory, DbClient dbClient) {
+  public InstalledAction(ServerPluginRepository serverPluginRepository, UserSession userSession, UpdateCenterMatrixFactory updateCenterMatrixFactory, DbClient dbClient) {
+    this.userSession = userSession;
     this.serverPluginRepository = serverPluginRepository;
     this.updateCenterMatrixFactory = updateCenterMatrixFactory;
     this.dbClient = dbClient;
@@ -75,9 +80,11 @@ public class InstalledAction implements PluginsWsAction {
   @Override
   public void define(WebService.NewController controller) {
     WebService.NewAction action = controller.createAction("installed")
-      .setDescription("Get the list of all the plugins installed on the SonarQube instance, sorted by plugin name.")
+      .setDescription("Get the list of all the plugins installed on the SonarQube instance, sorted by plugin name.<br/>" +
+        "Requires authentication.")
       .setSince("5.2")
       .setChangelog(
+        new Change("9.7", "Authentication check added"),
         new Change("8.0", "The 'documentationPath' field is added"),
         new Change("7.0", "The fields 'compressedHash' and 'compressedFilename' are added"),
         new Change("6.6", "The 'filename' field is added"),
@@ -91,7 +98,7 @@ public class InstalledAction implements PluginsWsAction {
       .setDescription(format("Comma-separated list of the additional fields to be returned in response. No additional field is returned by default. Possible values are:" +
         "<ul>" +
         "<li>%s - category as defined in the Update Center. A connection to the Update Center is needed</li>" +
-        "</lu>", FIELD_CATEGORY))
+        "</ul>", FIELD_CATEGORY))
       .setSince("5.6");
 
     action.createParam(PARAM_TYPE)
@@ -103,6 +110,10 @@ public class InstalledAction implements PluginsWsAction {
 
   @Override
   public void handle(Request request, Response response) throws Exception {
+    if (!userSession.isLoggedIn() && !userSession.hasPermission(GlobalPermission.SCAN)) {
+      throw insufficientPrivilegesException();
+    }
+
     String typeParam = request.param(PARAM_TYPE);
     SortedSet<ServerPlugin> installedPlugins = loadInstalledPlugins(typeParam);
     Map<String, PluginDto> dtosByKey;
index 423fb7658cacab06aee08464d413bd989d91fd87..208032a9a7ee7e0083c19a947b7657918c8660ed 100644 (file)
@@ -41,11 +41,14 @@ import org.sonar.api.utils.System2;
 import org.sonar.core.platform.PluginInfo;
 import org.sonar.db.DbTester;
 import org.sonar.db.plugin.PluginDto.Type;
+import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.plugins.PluginFilesAndMd5.FileAndMd5;
 import org.sonar.core.plugin.PluginType;
 import org.sonar.server.plugins.ServerPlugin;
 import org.sonar.server.plugins.ServerPluginRepository;
 import org.sonar.server.plugins.UpdateCenterMatrixFactory;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.WsActionTester;
 import org.sonar.updatecenter.common.Plugin;
 import org.sonar.updatecenter.common.UpdateCenter;
@@ -54,10 +57,11 @@ import org.sonar.updatecenter.common.Version;
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 import static org.sonar.test.JsonAssert.assertJson;
 
@@ -71,10 +75,12 @@ public class InstalledActionTest {
   public TemporaryFolder temp = new TemporaryFolder();
   @Rule
   public DbTester db = DbTester.create(System2.INSTANCE);
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone().logIn();
 
   private UpdateCenterMatrixFactory updateCenterMatrixFactory = mock(UpdateCenterMatrixFactory.class, RETURNS_DEEP_STUBS);
   private ServerPluginRepository serverPluginRepository = mock(ServerPluginRepository.class);
-  private InstalledAction underTest = new InstalledAction(serverPluginRepository, updateCenterMatrixFactory, db.getDbClient());
+  private InstalledAction underTest = new InstalledAction(serverPluginRepository, userSession, updateCenterMatrixFactory, db.getDbClient());
   private WsActionTester tester = new WsActionTester(underTest);
 
   @DataProvider
@@ -486,6 +492,14 @@ public class InstalledActionTest {
     assertThat(response).containsOnlyOnce("name2");
   }
 
+  @Test
+  public void fail_if_not_logged_in() {
+    userSession.anonymous();
+    TestRequest testRequest = tester.newRequest();
+    assertThatThrownBy(testRequest::execute)
+      .isInstanceOf(ForbiddenException.class);
+  }
+
   private ServerPlugin plugin(String key, String name) throws IOException {
     File file = temp.newFile();
     PluginInfo info = new PluginInfo(key)