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;
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;
/**
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;
@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"),
.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)
@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;
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;
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;
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
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)