aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--it/it-tests/src/test/java/it/plugins/PluginsTest.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ws/AvailableAction.java12
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java10
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java14
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdatesAction.java15
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/startup/FeedUsersLocalStartupTask.java34
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/ws/SearchAction.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java18
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/SearchAction.java11
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AvailableActionTest.java48
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java48
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingActionTest.java59
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginsWsMediumTest.java12
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UpdatesActionTest.java31
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/startup/FeedUsersLocalStartupTaskTest.java60
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java63
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/SearchActionTest.java34
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsWsTest.java4
-rw-r--r--server/sonar-web/src/main/js/apps/groups/list-view.js10
-rw-r--r--server/sonar-web/src/main/js/apps/groups/templates/groups-list.hbs18
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1153_update_users_external_identity_when_empty.rb31
-rw-r--r--sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java2
-rw-r--r--sonar-db/src/main/java/org/sonar/db/version/v56/UpdateUsersExternalIdentityWhenEmpty.java69
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql1
-rw-r--r--sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java2
-rw-r--r--sonar-db/src/test/java/org/sonar/db/version/v56/UpdateUsersExternalIdentityWhenEmptyTest.java104
-rw-r--r--sonar-db/src/test/resources/org/sonar/db/version/v56/UpdateUsersExternalIdentityWhenEmptyTest/schema.sql17
27 files changed, 627 insertions, 110 deletions
diff --git a/it/it-tests/src/test/java/it/plugins/PluginsTest.java b/it/it-tests/src/test/java/it/plugins/PluginsTest.java
index d9a42ec41c7..8203f31b473 100644
--- a/it/it-tests/src/test/java/it/plugins/PluginsTest.java
+++ b/it/it-tests/src/test/java/it/plugins/PluginsTest.java
@@ -48,6 +48,7 @@ import org.junit.Test;
import org.junit.rules.ErrorCollector;
import org.sonar.updatecenter.common.Plugin;
import org.sonar.updatecenter.common.Release;
+import org.sonar.updatecenter.common.Version;
import static org.assertj.core.api.Assertions.fail;
@@ -98,10 +99,11 @@ public class PluginsTest {
// install latest compatible releases of plugins
org.sonar.updatecenter.common.Version sonarVersion = org.sonar.updatecenter.common.Version.create(builder.getSonarVersion());
- builder.getUpdateCenter().setInstalledSonarVersion(sonarVersion);
+ Version sonarVersionWithoutPatch = Version.create(sonarVersion.getMajor() + "." + sonarVersion.getMinor());
+ builder.getUpdateCenter().setInstalledSonarVersion(sonarVersionWithoutPatch);
for (Plugin plugin : builder.getUpdateCenter().findAllCompatiblePlugins()) {
if (!DISABLED_PLUGINS.contains(plugin.getKey())) {
- Release release = plugin.getLastCompatibleRelease(sonarVersion);
+ Release release = plugin.getLastCompatibleRelease(sonarVersionWithoutPatch);
if (release != null) {
builder.setOrchestratorProperty(plugin.getKey() + "Version", release.getVersion().toString());
builder.addPlugin(plugin.getKey());
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/AvailableAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/AvailableAction.java
index 1fada70fc31..47d03fab07b 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/AvailableAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/AvailableAction.java
@@ -28,9 +28,11 @@ import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.server.plugins.UpdateCenterMatrixFactory;
+import org.sonar.server.user.UserSession;
import org.sonar.updatecenter.common.PluginUpdate;
import org.sonar.updatecenter.common.UpdateCenter;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.server.plugins.ws.PluginWSCommons.NAME_KEY_PLUGIN_UPDATE_ORDERING;
public class AvailableAction implements PluginsWsAction {
@@ -38,10 +40,12 @@ public class AvailableAction implements PluginsWsAction {
private static final boolean DO_NOT_FORCE_REFRESH = false;
private static final String ARRAY_PLUGINS = "plugins";
+ private final UserSession userSession;
private final UpdateCenterMatrixFactory updateCenterFactory;
private final PluginWSCommons pluginWSCommons;
- public AvailableAction(UpdateCenterMatrixFactory updateCenterFactory, PluginWSCommons pluginWSCommons) {
+ public AvailableAction(UserSession userSession, UpdateCenterMatrixFactory updateCenterFactory, PluginWSCommons pluginWSCommons) {
+ this.userSession = userSession;
this.updateCenterFactory = updateCenterFactory;
this.pluginWSCommons = pluginWSCommons;
}
@@ -59,7 +63,8 @@ public class AvailableAction implements PluginsWsAction {
"<li>INCOMPATIBLE: plugin is not compatible with current SonarQube instance.</li>" +
"<li>REQUIRES_SYSTEM_UPGRADE: plugin requires SonarQube to be upgraded before being installed.</li>" +
"<li>DEPS_REQUIRE_SYSTEM_UPGRADE: at least one plugin on which the plugin is dependent requires SonarQube to be upgraded.</li>" +
- "</ul>")
+ "</ul>.<br/>" +
+ "Require 'Administer System' permission.")
.setSince("5.2")
.setHandler(this)
.setResponseExample(Resources.getResource(this.getClass(), "example-available_plugins.json"));
@@ -67,6 +72,7 @@ public class AvailableAction implements PluginsWsAction {
@Override
public void handle(Request request, Response response) throws Exception {
+ userSession.checkPermission(SYSTEM_ADMIN);
JsonWriter jsonWriter = response.newJsonWriter();
jsonWriter.beginObject();
@@ -93,7 +99,7 @@ public class AvailableAction implements PluginsWsAction {
return ImmutableSortedSet.copyOf(
NAME_KEY_PLUGIN_UPDATE_ORDERING,
updateCenter.findAvailablePlugins()
- );
+ );
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java
index 4c1034713b6..bd81e9dd6d4 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java
@@ -32,11 +32,13 @@ import org.sonar.api.utils.text.JsonWriter;
import org.sonar.core.platform.PluginInfo;
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 static com.google.common.collect.ImmutableSortedSet.copyOf;
import static java.lang.String.format;
import static java.util.Collections.singleton;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.server.plugins.ws.PluginWSCommons.NAME_KEY_PLUGIN_METADATA_COMPARATOR;
import static org.sonar.server.plugins.ws.PluginWSCommons.compatiblePluginsByKey;
@@ -47,11 +49,13 @@ public class InstalledAction implements PluginsWsAction {
private static final String ARRAY_PLUGINS = "plugins";
private static final String FIELD_CATEGORY = "category";
+ private final UserSession userSession;
private final ServerPluginRepository pluginRepository;
private final PluginWSCommons pluginWSCommons;
private final UpdateCenterMatrixFactory updateCenterMatrixFactory;
- public InstalledAction(ServerPluginRepository pluginRepository, PluginWSCommons pluginWSCommons, UpdateCenterMatrixFactory updateCenterMatrixFactory) {
+ public InstalledAction(UserSession userSession, ServerPluginRepository pluginRepository, PluginWSCommons pluginWSCommons, UpdateCenterMatrixFactory updateCenterMatrixFactory) {
+ this.userSession = userSession;
this.pluginRepository = pluginRepository;
this.pluginWSCommons = pluginWSCommons;
this.updateCenterMatrixFactory = updateCenterMatrixFactory;
@@ -60,7 +64,8 @@ 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/>" +
+ "Require 'Administer System' permission.")
.setSince("5.2")
.setHandler(this)
.setResponseExample(Resources.getResource(this.getClass(), "example-installed_plugins.json"));
@@ -75,6 +80,7 @@ public class InstalledAction implements PluginsWsAction {
@Override
public void handle(Request request, Response response) throws Exception {
+ userSession.checkPermission(SYSTEM_ADMIN);
Collection<PluginInfo> pluginInfoList = searchPluginInfoList();
JsonWriter jsonWriter = response.newJsonWriter();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java
index 8a79908e9aa..5ee8a989ce8 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java
@@ -35,11 +35,13 @@ import org.sonar.core.platform.PluginInfo;
import org.sonar.server.plugins.PluginDownloader;
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 static com.google.common.collect.FluentIterable.from;
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.io.Resources.getResource;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.server.plugins.ws.PluginWSCommons.compatiblePluginsByKey;
/**
@@ -51,14 +53,16 @@ public class PendingAction implements PluginsWsAction {
private static final String ARRAY_REMOVING = "removing";
private static final String ARRAY_UPDATING = "updating";
+ private final UserSession userSession;
private final PluginDownloader pluginDownloader;
private final ServerPluginRepository installer;
private final PluginWSCommons pluginWSCommons;
private final UpdateCenterMatrixFactory updateCenterMatrixFactory;
- public PendingAction(PluginDownloader pluginDownloader,
- ServerPluginRepository installer,
- PluginWSCommons pluginWSCommons, UpdateCenterMatrixFactory updateCenterMatrixFactory) {
+ public PendingAction(UserSession userSession, PluginDownloader pluginDownloader,
+ ServerPluginRepository installer,
+ PluginWSCommons pluginWSCommons, UpdateCenterMatrixFactory updateCenterMatrixFactory) {
+ this.userSession = userSession;
this.pluginDownloader = pluginDownloader;
this.installer = installer;
this.pluginWSCommons = pluginWSCommons;
@@ -68,7 +72,8 @@ public class PendingAction implements PluginsWsAction {
@Override
public void define(WebService.NewController controller) {
controller.createAction("pending")
- .setDescription("Get the list of plugins which will either be installed or removed at the next startup of the SonarQube instance, sorted by plugin name")
+ .setDescription("Get the list of plugins which will either be installed or removed at the next startup of the SonarQube instance, sorted by plugin name.<br/>" +
+ "Require 'Administer System' permission.")
.setSince("5.2")
.setHandler(this)
.setResponseExample(getResource(this.getClass(), "example-pending_plugins.json"));
@@ -76,6 +81,7 @@ public class PendingAction implements PluginsWsAction {
@Override
public void handle(Request request, Response response) throws Exception {
+ userSession.checkPermission(SYSTEM_ADMIN);
ImmutableMap<String, Plugin> compatiblePluginsByKey = compatiblePluginsByKey(updateCenterMatrixFactory);
JsonWriter jsonWriter = response.newJsonWriter();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdatesAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdatesAction.java
index 152c564ac02..d4834033145 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdatesAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdatesAction.java
@@ -33,10 +33,13 @@ import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.server.plugins.UpdateCenterMatrixFactory;
import org.sonar.server.plugins.ws.PluginUpdateAggregator.PluginUpdateAggregate;
+import org.sonar.server.user.UserSession;
import org.sonar.updatecenter.common.Plugin;
import org.sonar.updatecenter.common.PluginUpdate;
import org.sonar.updatecenter.common.UpdateCenter;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+
/**
* Implementation of the {@code updates} action for the Plugins WebService.
*/
@@ -51,13 +54,15 @@ public class UpdatesAction implements PluginsWsAction {
private static final Ordering<PluginUpdate> PLUGIN_UPDATE_BY_VERSION_ORDERING = Ordering.natural()
.onResultOf(input -> input.getRelease().getVersion().toString());
+ private final UserSession userSession;
private final UpdateCenterMatrixFactory updateCenterMatrixFactory;
private final PluginWSCommons pluginWSCommons;
private final PluginUpdateAggregator aggregator;
- public UpdatesAction(UpdateCenterMatrixFactory updateCenterMatrixFactory,
- PluginWSCommons pluginWSCommons,
- PluginUpdateAggregator aggregator) {
+ public UpdatesAction(UserSession userSession, UpdateCenterMatrixFactory updateCenterMatrixFactory,
+ PluginWSCommons pluginWSCommons,
+ PluginUpdateAggregator aggregator) {
+ this.userSession = userSession;
this.updateCenterMatrixFactory = updateCenterMatrixFactory;
this.pluginWSCommons = pluginWSCommons;
this.aggregator = aggregator;
@@ -72,7 +77,8 @@ public class UpdatesAction implements PluginsWsAction {
"<br/>" +
"Plugin information is retrieved from Update Center. Date and time at which Update Center was last refreshed is provided in the response." +
"<br/>" +
- "Update status values are: [COMPATIBLE, INCOMPATIBLE, REQUIRES_UPGRADE, DEPS_REQUIRE_UPGRADE]")
+ "Update status values are: [COMPATIBLE, INCOMPATIBLE, REQUIRES_UPGRADE, DEPS_REQUIRE_UPGRADE]<br/>." +
+ "Require 'Administer System' permission.")
.setSince("5.2")
.setHandler(this)
.setResponseExample(Resources.getResource(this.getClass(), "example-updates_plugins.json"));
@@ -80,6 +86,7 @@ public class UpdatesAction implements PluginsWsAction {
@Override
public void handle(Request request, Response response) throws Exception {
+ userSession.checkPermission(SYSTEM_ADMIN);
JsonWriter jsonWriter = response.newJsonWriter();
jsonWriter.beginObject();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/startup/FeedUsersLocalStartupTask.java b/server/sonar-server/src/main/java/org/sonar/server/startup/FeedUsersLocalStartupTask.java
index 5be1fdc2cc5..a5316f9b383 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/startup/FeedUsersLocalStartupTask.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/startup/FeedUsersLocalStartupTask.java
@@ -19,11 +19,16 @@
*/
package org.sonar.server.startup;
+import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import org.picocontainer.Startable;
import org.sonar.api.config.Settings;
+import org.sonar.api.security.SecurityRealm;
import org.sonar.api.user.UserQuery;
+import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
@@ -41,9 +46,9 @@ import static org.sonar.db.loadedtemplate.LoadedTemplateDto.ONE_SHOT_TASK_TYPE;
* Feed users local property.
* If a realm is defined, then users are set as local only if their login are found in the property "sonar.security.localUsers",
* otherwise user are all set as local.
- *
+ * <p>
* See <a href="https://jira.sonarsource.com/browse/SONAR-7254">SONAR-7254</a>.
- *
+ * <p>
* Should be removed after LTS 5.X
*
* @since 5.5
@@ -59,11 +64,23 @@ public class FeedUsersLocalStartupTask implements Startable {
private final DbClient dbClient;
private final Settings settings;
+ private final SecurityRealm[] realms;
+ /**
+ * Used when no realm plugin
+ */
public FeedUsersLocalStartupTask(System2 system2, DbClient dbClient, Settings settings) {
this.system2 = system2;
this.dbClient = dbClient;
this.settings = settings;
+ this.realms = new SecurityRealm[]{};
+ }
+
+ public FeedUsersLocalStartupTask(System2 system2, DbClient dbClient, Settings settings, SecurityRealm[] realms) {
+ this.system2 = system2;
+ this.dbClient = dbClient;
+ this.settings = settings;
+ this.realms = realms;
}
@Override
@@ -86,12 +103,13 @@ public class FeedUsersLocalStartupTask implements Startable {
}
private void updateUsersLocal(DbSession dbSession) {
+ boolean realmConfExists = settings.getString(CORE_AUTHENTICATOR_REALM) != null;
+ checkConfigurationIfRealmExists(realmConfExists);
long now = system2.now();
Set<String> localUsers = new HashSet<>(asList(settings.getStringArray(LOCAL_USERS_PROPERTY)));
- boolean isRealmExist = settings.getString(CORE_AUTHENTICATOR_REALM) != null;
for (UserDto user : dbClient.userDao().selectUsers(dbSession, UserQuery.ALL_ACTIVES)) {
if (user.getExternalIdentityProvider().equals(UserUpdater.SQ_AUTHORITY)) {
- user.setLocal(!isRealmExist || localUsers.contains(user.getLogin()));
+ user.setLocal(!realmConfExists || localUsers.contains(user.getLogin()));
} else {
user.setLocal(false);
}
@@ -100,6 +118,14 @@ public class FeedUsersLocalStartupTask implements Startable {
}
}
+ private void checkConfigurationIfRealmExists(boolean realmConfExists) {
+ List<String> realmNames = Arrays.stream(realms).map(SecurityRealm::getName).collect(Collectors.toList());
+ if (!realmNames.isEmpty() && !realmConfExists) {
+ throw MessageException.of(String.format("External authentication plugin %s has been found, but no related configuration has been set. " +
+ "Either update your configuration or remove the plugin", realmNames));
+ }
+ }
+
private boolean hasAlreadyBeenExecuted(DbSession dbSession) {
return dbClient.loadedTemplateDao().countByTypeAndKey(ONE_SHOT_TASK_TYPE, TEMPLATE_KEY, dbSession) > 0;
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/SearchAction.java
index 7f9d97d310b..b09e04e5d42 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/SearchAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/SearchAction.java
@@ -58,7 +58,9 @@ public class SearchAction implements UsersWsAction {
@Override
public void define(WebService.NewController controller) {
WebService.NewAction action = controller.createAction("search")
- .setDescription("Get a list of active users. Administer System permission is required to show the 'groups' field.")
+ .setDescription("Get a list of active users. <br/>" +
+ "Administer System permission is required to show the 'groups' field.<br/>" +
+ "When accessed anonymously, only logins and names are returned.")
.setSince("3.6")
.setHandler(this)
.setResponseExample(getClass().getResource("search-example.json"));
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java
index f77a2fb985f..990d4db28ff 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java
@@ -69,14 +69,16 @@ public class UserJsonWriter {
json.beginObject();
json.prop(FIELD_LOGIN, user.getLogin());
writeIfNeeded(json, user.getName(), FIELD_NAME, fields);
- writeIfNeeded(json, user.getEmail(), FIELD_EMAIL, fields);
- writeIfNeeded(json, user.isActive(), FIELD_ACTIVE, fields);
- writeIfNeeded(json, user.isLocal(), FIELD_LOCAL, fields);
- writeIfNeeded(json, user.getExternalIdentity(), FIELD_EXTERNAL_IDENTITY, fields);
- writeIfNeeded(json, user.getExternalIdentityProvider(), FIELD_EXTERNAL_PROVIDER, fields);
- writeGroupsIfNeeded(json, groups, fields);
- writeScmAccountsIfNeeded(json, fields, user);
- writeTokensCount(json, tokensCount);
+ if (userSession.isLoggedIn()) {
+ writeIfNeeded(json, user.getEmail(), FIELD_EMAIL, fields);
+ writeIfNeeded(json, user.isActive(), FIELD_ACTIVE, fields);
+ writeIfNeeded(json, user.isLocal(), FIELD_LOCAL, fields);
+ writeIfNeeded(json, user.getExternalIdentity(), FIELD_EXTERNAL_IDENTITY, fields);
+ writeIfNeeded(json, user.getExternalIdentityProvider(), FIELD_EXTERNAL_PROVIDER, fields);
+ writeGroupsIfNeeded(json, groups, fields);
+ writeScmAccountsIfNeeded(json, fields, user);
+ writeTokensCount(json, tokensCount);
+ }
json.endObject();
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/SearchAction.java
index 1519c60cf7c..8c2df2adf86 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/SearchAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/SearchAction.java
@@ -38,6 +38,7 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.user.GroupDto;
import org.sonar.server.es.SearchOptions;
+import org.sonar.server.user.UserSession;
import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
@@ -49,16 +50,19 @@ public class SearchAction implements UserGroupsWsAction {
private static final String FIELD_MEMBERS_COUNT = "membersCount";
private static final List<String> ALL_FIELDS = Arrays.asList(FIELD_NAME, FIELD_DESCRIPTION, FIELD_MEMBERS_COUNT);
- private DbClient dbClient;
+ private final DbClient dbClient;
+ private final UserSession userSession;
- public SearchAction(DbClient dbClient) {
+ public SearchAction(DbClient dbClient, UserSession userSession) {
this.dbClient = dbClient;
+ this.userSession = userSession;
}
@Override
public void define(NewController context) {
context.createAction("search")
- .setDescription("Search for user groups")
+ .setDescription("Search for user groups <br>." +
+ "Require to be logged.")
.setHandler(this)
.setResponseExample(getClass().getResource("example-search.json"))
.setSince("5.2")
@@ -69,6 +73,7 @@ public class SearchAction implements UserGroupsWsAction {
@Override
public void handle(Request request, Response response) throws Exception {
+ userSession.checkLoggedIn();
int page = request.mandatoryParamAsInt(Param.PAGE);
int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
SearchOptions options = new SearchOptions()
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AvailableActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AvailableActionTest.java
index f5d10cec26f..2371af692d5 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AvailableActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AvailableActionTest.java
@@ -20,9 +20,13 @@
package org.sonar.server.plugins.ws;
import com.google.common.base.Optional;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.DateUtils;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;
import org.sonar.updatecenter.common.Plugin;
import org.sonar.updatecenter.common.PluginUpdate;
@@ -33,6 +37,8 @@ import static com.google.common.collect.ImmutableList.of;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Mockito.when;
+import static org.sonar.core.permission.GlobalPermissions.DASHBOARD_SHARING;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonar.updatecenter.common.PluginUpdate.Status.COMPATIBLE;
import static org.sonar.updatecenter.common.PluginUpdate.Status.DEPENDENCIES_REQUIRE_SONAR_UPGRADE;
@@ -57,10 +63,17 @@ public class AvailableActionTest extends AbstractUpdateCenterBasedPluginsWsActio
.addOutgoingDependency(release(PLUGIN_1, "0.3.6"))
.addOutgoingDependency(release(PLUGIN_2, "1.0.0"));
- private AvailableAction underTest = new AvailableAction(updateCenterFactory, new PluginWSCommons());
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private AvailableAction underTest = new AvailableAction(userSession, updateCenterFactory, new PluginWSCommons());
@Test
public void action_available_is_defined() {
+ loggedAsAdmin();
WsTester wsTester = new WsTester();
WebService.NewController newController = wsTester.context().createController(DUMMY_CONTROLLER_KEY);
@@ -78,6 +91,7 @@ public class AvailableActionTest extends AbstractUpdateCenterBasedPluginsWsActio
@Test
public void empty_array_is_returned_when_there_is_no_plugin_available() throws Exception {
+ loggedAsAdmin();
underTest.handle(request, response);
assertJson(response.outputAsString()).withStrictArrayOrder().isSimilarTo(JSON_EMPTY_PLUGIN_LIST);
@@ -85,6 +99,7 @@ public class AvailableActionTest extends AbstractUpdateCenterBasedPluginsWsActio
@Test
public void empty_array_is_returned_when_update_center_is_not_accessible() throws Exception {
+ loggedAsAdmin();
when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.<UpdateCenter>absent());
underTest.handle(request, response);
@@ -94,9 +109,10 @@ public class AvailableActionTest extends AbstractUpdateCenterBasedPluginsWsActio
@Test
public void verify_properties_displayed_in_json_per_plugin() throws Exception {
+ loggedAsAdmin();
when(updateCenter.findAvailablePlugins()).thenReturn(of(
pluginUpdate(FULL_PROPERTIES_PLUGIN_RELEASE, COMPATIBLE)
- ));
+ ));
underTest.handle(request, response);
@@ -105,28 +121,40 @@ public class AvailableActionTest extends AbstractUpdateCenterBasedPluginsWsActio
@Test
public void status_COMPATIBLE_is_displayed_COMPATIBLE_in_JSON() throws Exception {
+ loggedAsAdmin();
checkStatusDisplayedInJson(COMPATIBLE, "COMPATIBLE");
}
@Test
public void status_INCOMPATIBLE_is_displayed_INCOMPATIBLE_in_JSON() throws Exception {
+ loggedAsAdmin();
checkStatusDisplayedInJson(INCOMPATIBLE, "INCOMPATIBLE");
}
@Test
public void status_REQUIRE_SONAR_UPGRADE_is_displayed_REQUIRES_SYSTEM_UPGRADE_in_JSON() throws Exception {
+ loggedAsAdmin();
checkStatusDisplayedInJson(REQUIRE_SONAR_UPGRADE, "REQUIRES_SYSTEM_UPGRADE");
}
@Test
public void status_DEPENDENCIES_REQUIRE_SONAR_UPGRADE_is_displayed_DEPS_REQUIRE_SYSTEM_UPGRADE_in_JSON() throws Exception {
+ loggedAsAdmin();
checkStatusDisplayedInJson(DEPENDENCIES_REQUIRE_SONAR_UPGRADE, "DEPS_REQUIRE_SYSTEM_UPGRADE");
}
+ @Test
+ public void fail_when_user_is_not_admin() throws Exception {
+ userSession.login("user").setGlobalPermissions(DASHBOARD_SHARING);
+
+ expectedException.expect(ForbiddenException.class);
+ underTest.handle(request, response);
+ }
+
private void checkStatusDisplayedInJson(PluginUpdate.Status status, String expectedValue) throws Exception {
when(updateCenter.findAvailablePlugins()).thenReturn(of(
pluginUpdate(release(PLUGIN_1, "1.0.0"), status)
- ));
+ ));
underTest.handle(request, response);
@@ -140,17 +168,11 @@ public class AvailableActionTest extends AbstractUpdateCenterBasedPluginsWsActio
" }" +
" ]" +
"}"
- );
+ );
}
- @Test
- public void plugins_are_sorted_by_name_then_key_and_made_unique() {
- when(updateCenter.findAvailablePlugins()).thenReturn(of(
- pluginUpdate("key2", "name2"),
- pluginUpdate("key1", "name2"),
- pluginUpdate("key2", "name2"),
- pluginUpdate("key0", "name0"),
- pluginUpdate("key1", "name1")
- ));
+ private void loggedAsAdmin() {
+ userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
}
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java
index 58c1dd49a57..96d8c30655c 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java
@@ -24,13 +24,16 @@ import java.io.File;
import java.util.Arrays;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.core.platform.PluginInfo;
+import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.plugins.UpdateCenterMatrixFactory;
+import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;
import org.sonar.updatecenter.common.Plugin;
import org.sonar.updatecenter.common.UpdateCenter;
@@ -43,6 +46,8 @@ import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import static org.sonar.core.permission.GlobalPermissions.DASHBOARD_SHARING;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.test.JsonAssert.assertJson;
public class InstalledActionTest {
@@ -55,16 +60,25 @@ public class InstalledActionTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
ServerPluginRepository pluginRepository = mock(ServerPluginRepository.class);
UpdateCenterMatrixFactory updateCenterMatrixFactory = mock(UpdateCenterMatrixFactory.class, RETURNS_DEEP_STUBS);
- InstalledAction underTest = new InstalledAction(pluginRepository, new PluginWSCommons(), updateCenterMatrixFactory);
+ InstalledAction underTest = new InstalledAction(userSession, pluginRepository, new PluginWSCommons(), updateCenterMatrixFactory);
Request request = mock(Request.class);
WsTester.TestResponse response = new WsTester.TestResponse();
+
+
@Test
public void action_installed_is_defined() {
+ loggedAsSystemAdmin();
WsTester wsTester = new WsTester();
WebService.NewController newController = wsTester.context().createController(DUMMY_CONTROLLER_KEY);
@@ -82,6 +96,7 @@ public class InstalledActionTest {
@Test
public void empty_array_is_returned_when_there_is_not_plugin_installed() throws Exception {
+ loggedAsSystemAdmin();
underTest.handle(request, response);
assertJson(response.outputAsString()).withStrictArrayOrder().isSimilarTo(JSON_EMPTY_PLUGIN_LIST);
@@ -89,6 +104,7 @@ public class InstalledActionTest {
@Test
public void empty_array_when_update_center_is_unavailable() throws Exception {
+ loggedAsSystemAdmin();
when(updateCenterMatrixFactory.getUpdateCenter(false)).thenReturn(Optional.<UpdateCenter>absent());
underTest.handle(request, response);
@@ -98,6 +114,7 @@ public class InstalledActionTest {
@Test
public void empty_fields_are_not_serialized_to_json() throws Exception {
+ loggedAsSystemAdmin();
when(pluginRepository.getPluginInfos()).thenReturn(
of(new PluginInfo("").setName("")));
@@ -108,6 +125,7 @@ public class InstalledActionTest {
@Test
public void verify_properties_displayed_in_json_per_plugin() throws Exception {
+ loggedAsSystemAdmin();
String jarFilename = getClass().getSimpleName() + "/" + "some.jar";
when(pluginRepository.getPluginInfos()).thenReturn(of(
new PluginInfo("plugKey")
@@ -122,7 +140,7 @@ public class InstalledActionTest {
.setImplementationBuild("sou_rev_sha1")
.setJarFile(new File(getClass().getResource(jarFilename).toURI()))
)
- );
+ );
underTest.handle(request, response);
@@ -145,11 +163,12 @@ public class InstalledActionTest {
" }" +
" ]" +
"}"
- );
+ );
}
@Test
public void category_is_returned_when_in_additional_fields() throws Exception {
+ loggedAsSystemAdmin();
String jarFilename = getClass().getSimpleName() + "/" + "some.jar";
when(pluginRepository.getPluginInfos()).thenReturn(of(
new PluginInfo("plugKey")
@@ -201,6 +220,7 @@ public class InstalledActionTest {
@Test
public void plugins_are_sorted_by_name_then_key_and_only_one_plugin_can_have_a_specific_name() throws Exception {
+ loggedAsSystemAdmin();
when(pluginRepository.getPluginInfos()).thenReturn(
of(
plugin("A", "name2"),
@@ -208,7 +228,7 @@ public class InstalledActionTest {
plugin("C", "name0"),
plugin("D", "name0")
)
- );
+ );
underTest.handle(request, response);
@@ -222,17 +242,18 @@ public class InstalledActionTest {
" {\"key\": \"A\"}" +
" ]" +
"}"
- );
+ );
}
@Test
public void only_one_plugin_can_have_a_specific_name_and_key() throws Exception {
+ loggedAsSystemAdmin();
when(pluginRepository.getPluginInfos()).thenReturn(
of(
plugin("A", "name2"),
plugin("A", "name2")
)
- );
+ );
underTest.handle(request, response);
@@ -243,11 +264,24 @@ public class InstalledActionTest {
" {\"key\": \"A\"}" +
" ]" +
"}"
- );
+ );
assertThat(response.outputAsString()).containsOnlyOnce("name2");
}
+ @Test
+ public void fail_when_user_is_not_sys_admin() throws Exception {
+ userSession.login("user").setGlobalPermissions(DASHBOARD_SHARING);
+
+ expectedException.expect(ForbiddenException.class);
+ underTest.handle(request, response);
+ }
+
private PluginInfo plugin(String key, String name) {
return new PluginInfo(key).setName(name).setVersion(Version.create("1.0"));
}
+
+ private void loggedAsSystemAdmin() {
+ userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
+ }
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingActionTest.java
index 6a2cf6d56fd..233af975e3f 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingActionTest.java
@@ -22,13 +22,17 @@ package org.sonar.server.plugins.ws;
import com.google.common.base.Optional;
import java.util.ArrayList;
import java.util.List;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.WebService;
import org.sonar.core.platform.PluginInfo;
+import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.plugins.PluginDownloader;
import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.plugins.UpdateCenterMatrixFactory;
+import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;
import org.sonar.updatecenter.common.Plugin;
import org.sonar.updatecenter.common.UpdateCenter;
@@ -39,21 +43,30 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.sonar.core.permission.GlobalPermissions.DASHBOARD_SHARING;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.test.JsonAssert.assertJson;
public class PendingActionTest {
private static final String DUMMY_CONTROLLER_KEY = "dummy";
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
PluginDownloader pluginDownloader = mock(PluginDownloader.class);
ServerPluginRepository serverPluginRepository = mock(ServerPluginRepository.class);
UpdateCenterMatrixFactory updateCenterMatrixFactory = mock(UpdateCenterMatrixFactory.class, RETURNS_DEEP_STUBS);
- PendingAction underTest = new PendingAction(pluginDownloader, serverPluginRepository, new PluginWSCommons(), updateCenterMatrixFactory);
+ PendingAction underTest = new PendingAction(userSession, pluginDownloader, serverPluginRepository, new PluginWSCommons(), updateCenterMatrixFactory);
Request request = mock(Request.class);
WsTester.TestResponse response = new WsTester.TestResponse();
@Test
public void action_pending_is_defined() {
+ loggedAsSystemAdmin();
WsTester wsTester = new WsTester();
WebService.NewController newController = wsTester.context().createController(DUMMY_CONTROLLER_KEY);
@@ -71,6 +84,7 @@ public class PendingActionTest {
@Test
public void empty_arrays_are_returned_when_there_nothing_pending() throws Exception {
+ loggedAsSystemAdmin();
underTest.handle(request, response);
assertJson(response.outputAsString()).withStrictArrayOrder().isSimilarTo(
@@ -79,11 +93,12 @@ public class PendingActionTest {
" \"removing\": []," +
" \"updating\": []" +
"}"
- );
+ );
}
@Test
public void empty_arrays_are_returned_when_update_center_is_unavailable() throws Exception {
+ loggedAsSystemAdmin();
when(updateCenterMatrixFactory.getUpdateCenter(false)).thenReturn(Optional.<UpdateCenter>absent());
underTest.handle(request, response);
@@ -94,11 +109,12 @@ public class PendingActionTest {
" \"removing\": []," +
" \"updating\": []" +
"}"
- );
+ );
}
@Test
public void verify_properties_displayed_in_json_per_installing_plugin() throws Exception {
+ loggedAsSystemAdmin();
newUpdateCenter("scmgit");
when(pluginDownloader.getDownloadedPlugins()).thenReturn(of(newScmGitPluginInfo()));
@@ -125,11 +141,12 @@ public class PendingActionTest {
" \"removing\": []," +
" \"updating\": []" +
"}"
- );
+ );
}
@Test
public void verify_properties_displayed_in_json_per_removing_plugin() throws Exception {
+ loggedAsSystemAdmin();
when(serverPluginRepository.getUninstalledPlugins()).thenReturn(of(newScmGitPluginInfo()));
underTest.handle(request, response);
@@ -154,11 +171,12 @@ public class PendingActionTest {
" }" +
" ]" +
"}"
- );
+ );
}
@Test
public void verify_properties_displayed_in_json_per_updating_plugin() throws Exception {
+ loggedAsSystemAdmin();
newUpdateCenter("scmgit");
when(serverPluginRepository.getPluginInfos()).thenReturn(of(newScmGitPluginInfo()));
when(pluginDownloader.getDownloadedPlugins()).thenReturn(of(newScmGitPluginInfo()));
@@ -181,6 +199,7 @@ public class PendingActionTest {
@Test
public void verify_properties_displayed_in_json_per_installing_removing_and_updating_plugins() throws Exception {
+ loggedAsSystemAdmin();
PluginInfo installed = newPluginInfo("java");
PluginInfo removedPlugin = newPluginInfo("js");
PluginInfo newPlugin = newPluginInfo("php");
@@ -218,11 +237,12 @@ public class PendingActionTest {
@Test
public void installing_plugins_are_sorted_by_name_then_key_and_are_unique() throws Exception {
+ loggedAsSystemAdmin();
when(pluginDownloader.getDownloadedPlugins()).thenReturn(of(
newPluginInfo(0).setName("Foo"),
newPluginInfo(3).setName("Bar"),
newPluginInfo(2).setName("Bar")
- ));
+ ));
underTest.handle(request, response);
@@ -246,16 +266,17 @@ public class PendingActionTest {
" \"removing\": []," +
" \"updating\": []" +
"}"
- );
+ );
}
@Test
public void removing_plugins_are_sorted_and_unique() throws Exception {
+ loggedAsSystemAdmin();
when(serverPluginRepository.getUninstalledPlugins()).thenReturn(of(
newPluginInfo(0).setName("Foo"),
newPluginInfo(3).setName("Bar"),
newPluginInfo(2).setName("Bar")
- ));
+ ));
underTest.handle(request, response);
@@ -279,10 +300,18 @@ public class PendingActionTest {
" }" +
" ]" +
"}"
- );
+ );
}
- public PluginInfo newScmGitPluginInfo() {
+ @Test
+ public void fail_when_user_is_not_sys_admin() throws Exception {
+ userSession.login("user").setGlobalPermissions(DASHBOARD_SHARING);
+
+ expectedException.expect(ForbiddenException.class);
+ underTest.handle(request, response);
+ }
+
+ private PluginInfo newScmGitPluginInfo() {
return new PluginInfo("scmgit")
.setName("Git")
.setDescription("Git SCM Provider.")
@@ -295,11 +324,11 @@ public class PendingActionTest {
.setImplementationBuild("9ce9d330c313c296fab051317cc5ad4b26319e07");
}
- public PluginInfo newPluginInfo(String key){
+ private PluginInfo newPluginInfo(String key) {
return new PluginInfo(key);
}
- private UpdateCenter newUpdateCenter(String... pluginKeys){
+ private UpdateCenter newUpdateCenter(String... pluginKeys) {
UpdateCenter updateCenter = mock(UpdateCenter.class);
when(updateCenterMatrixFactory.getUpdateCenter(false)).thenReturn(Optional.of(updateCenter));
List<Plugin> plugins = new ArrayList<>();
@@ -310,7 +339,11 @@ public class PendingActionTest {
return updateCenter;
}
- public PluginInfo newPluginInfo(int id) {
+ private PluginInfo newPluginInfo(int id) {
return new PluginInfo("key" + id).setName("name" + id);
}
+
+ private void loggedAsSystemAdmin() {
+ userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
+ }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginsWsMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginsWsMediumTest.java
index b0ba63bf886..da84e11fd59 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginsWsMediumTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginsWsMediumTest.java
@@ -28,11 +28,12 @@ import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.core.permission.GlobalPermissions;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+
public class PluginsWsMediumTest {
private static final String ENCODING = "UTF-8";
@@ -52,6 +53,7 @@ public class PluginsWsMediumTest {
WsTester wsTester = new WsTester(serverTester.get(PluginsWs.class));
// 1 - check what's installed, available and pending
+ userSessionRule.login().setGlobalPermissions(SYSTEM_ADMIN);
wsTester.newGetRequest("api/plugins", "installed").execute().assertJson("{" +
" \"plugins\": [" +
" {" +
@@ -79,8 +81,7 @@ public class PluginsWsMediumTest {
wsTester.newGetRequest("api/plugins", "pending").execute().assertJson("{\"installing\":[],\"removing\":[],\"updating\":[]}");
- // 2 - login as admin and install one plugin, update another, verify pending status in the process
- userSessionRule.login().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+ // 2 - install one plugin, update another, verify pending status in the process
wsTester.newPostRequest("api/plugins", "update").setParam("key", "decoy").execute().assertNoContent();
wsTester.newGetRequest("api/plugins", "pending").execute().assertJson("{" +
@@ -116,6 +117,7 @@ public class PluginsWsMediumTest {
wsTester = restartServerTester();
// 4 - make sure plugin is installed
+ userSessionRule.login().setGlobalPermissions(SYSTEM_ADMIN);
wsTester.newGetRequest("api/plugins", "installed").execute().assertJson("{" +
" \"plugins\": [" +
" {" +
@@ -130,8 +132,7 @@ public class PluginsWsMediumTest {
"}"
);
- // 5 - login as admin again and uninstall a plugin, verify pending status in the process
- userSessionRule.login().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+ // 5 - uninstall a plugin, verify pending status in the process
wsTester.newPostRequest("api/plugins", "uninstall").setParam("key", "foo").execute().assertNoContent();
wsTester.newGetRequest("api/plugins", "pending").execute().assertJson("{" +
@@ -149,6 +150,7 @@ public class PluginsWsMediumTest {
wsTester = restartServerTester();
// 7 - make sure plugin has been uninstalled
+ userSessionRule.login().setGlobalPermissions(SYSTEM_ADMIN);
wsTester.newGetRequest("api/plugins", "installed").execute().assertJson("{" +
" \"plugins\": [" +
" {" +
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UpdatesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UpdatesActionTest.java
index 64589dbe2cb..8fc66f8ac1d 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UpdatesActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UpdatesActionTest.java
@@ -19,9 +19,13 @@
*/
package org.sonar.server.plugins.ws;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.DateUtils;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;
import org.sonar.updatecenter.common.Plugin;
import org.sonar.updatecenter.common.Release;
@@ -29,6 +33,8 @@ import org.sonar.updatecenter.common.Release;
import static com.google.common.collect.ImmutableList.of;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
+import static org.sonar.core.permission.GlobalPermissions.DASHBOARD_SHARING;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonar.updatecenter.common.PluginUpdate.Status.COMPATIBLE;
import static org.sonar.updatecenter.common.PluginUpdate.Status.INCOMPATIBLE;
@@ -70,12 +76,19 @@ public class UpdatesActionTest extends AbstractUpdateCenterBasedPluginsWsActionT
.addOutgoingDependency(release(JAVA_PLUGIN, "1.0"));
- private UpdatesAction underTest = new UpdatesAction(updateCenterFactory,
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private UpdatesAction underTest = new UpdatesAction(userSession, updateCenterFactory,
new PluginWSCommons(), new PluginUpdateAggregator()
);
@Test
public void action_updatable_is_defined() {
+ loggedAsSystemAdmin();
WsTester wsTester = new WsTester();
WebService.NewController newController = wsTester.context().createController(DUMMY_CONTROLLER_KEY);
@@ -93,6 +106,7 @@ public class UpdatesActionTest extends AbstractUpdateCenterBasedPluginsWsActionT
@Test
public void empty_array_is_returned_when_there_is_no_plugin_available() throws Exception {
+ loggedAsSystemAdmin();
underTest.handle(request, response);
assertJson(response.outputAsString()).withStrictArrayOrder().isSimilarTo(JSON_EMPTY_PLUGIN_LIST);
@@ -100,6 +114,7 @@ public class UpdatesActionTest extends AbstractUpdateCenterBasedPluginsWsActionT
@Test
public void verify_response_against_example() throws Exception {
+ loggedAsSystemAdmin();
when(updateCenter.findPluginUpdates()).thenReturn(of(
pluginUpdate(ABAP_32, COMPATIBLE),
pluginUpdate(ABAP_31, INCOMPATIBLE),
@@ -113,6 +128,7 @@ public class UpdatesActionTest extends AbstractUpdateCenterBasedPluginsWsActionT
@Test
public void status_COMPATIBLE_is_displayed_COMPATIBLE_in_JSON() throws Exception {
+ loggedAsSystemAdmin();
when(updateCenter.findPluginUpdates()).thenReturn(of(
pluginUpdate(release(PLUGIN_1, "1.0.0"), COMPATIBLE)
));
@@ -136,6 +152,7 @@ public class UpdatesActionTest extends AbstractUpdateCenterBasedPluginsWsActionT
@Test
public void plugins_are_sorted_by_name_and_made_unique() throws Exception {
+ loggedAsSystemAdmin();
when(updateCenter.findPluginUpdates()).thenReturn(of(
pluginUpdate("key2", "name2"),
pluginUpdate("key2", "name2"),
@@ -164,4 +181,16 @@ public class UpdatesActionTest extends AbstractUpdateCenterBasedPluginsWsActionT
"}"
);
}
+
+ @Test
+ public void fail_when_user_is_not_sys_admin() throws Exception {
+ userSession.login("user").setGlobalPermissions(DASHBOARD_SHARING);
+
+ expectedException.expect(ForbiddenException.class);
+ underTest.handle(request, response);
+ }
+
+ private void loggedAsSystemAdmin() {
+ userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
+ }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/startup/FeedUsersLocalStartupTaskTest.java b/server/sonar-server/src/test/java/org/sonar/server/startup/FeedUsersLocalStartupTaskTest.java
index 7b0531cfe37..3de4c5f72e5 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/startup/FeedUsersLocalStartupTaskTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/startup/FeedUsersLocalStartupTaskTest.java
@@ -22,7 +22,10 @@ package org.sonar.server.startup;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.sonar.api.config.Settings;
+import org.sonar.api.security.SecurityRealm;
+import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
@@ -46,6 +49,11 @@ public class FeedUsersLocalStartupTaskTest {
static final String USER1_LOGIN = "USER1";
static final String USER2_LOGIN = "USER2";
+ static final String REALM_NAME = "LDAP";
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
System2 system2 = mock(System2.class);
@Rule
@@ -62,7 +70,7 @@ public class FeedUsersLocalStartupTaskTest {
Settings settings = new Settings();
- FeedUsersLocalStartupTask underTest = new FeedUsersLocalStartupTask(system2, dbTester.getDbClient(), settings);
+ FeedUsersLocalStartupTask underTest;
@Before
public void setUp() throws Exception {
@@ -71,7 +79,8 @@ public class FeedUsersLocalStartupTaskTest {
@Test
public void set_user_local_when_id_provider_is_sonarqube_and_realm_exists_and_local_users_property_contains_user_login() throws Exception {
- settings.setProperty("sonar.security.realm", "LDAP");
+ initTaskWithRealm();
+ settings.setProperty("sonar.security.realm", REALM_NAME);
settings.setProperty("sonar.security.localUsers", USER1_LOGIN);
UserDto user = addUser(USER1_LOGIN, false, "sonarqube");
@@ -83,7 +92,8 @@ public class FeedUsersLocalStartupTaskTest {
@Test
public void set_user_as_not_local_when_id_provider_is_sonarqube_and_ream_exists_and_no_local_users_property() throws Exception {
- settings.setProperty("sonar.security.realm", "LDAP");
+ initTaskWithRealm();
+ settings.setProperty("sonar.security.realm", REALM_NAME);
UserDto user = addUser(USER1_LOGIN, false, "sonarqube");
underTest.start();
@@ -94,7 +104,8 @@ public class FeedUsersLocalStartupTaskTest {
@Test
public void set_user_as_not_local_when_id_provider_is_sonarqube_and_ream_exists_and_local_users_property_does_not_contain_user_login() throws Exception {
- settings.setProperty("sonar.security.realm", "LDAP");
+ initTaskWithRealm();
+ settings.setProperty("sonar.security.realm", REALM_NAME);
settings.setProperty("sonar.security.localUsers", USER2_LOGIN);
UserDto user = addUser(USER1_LOGIN, true, "sonarqube");
@@ -106,6 +117,7 @@ public class FeedUsersLocalStartupTaskTest {
@Test
public void set_user_as_local_when_id_provider_is_sonarqube_and_no_realm() throws Exception {
+ initTaskWithNoRealm();
settings.setProperty("sonar.security.realm", (String) null);
UserDto user = addUser(USER1_LOGIN, false, "sonarqube");
@@ -116,7 +128,8 @@ public class FeedUsersLocalStartupTaskTest {
}
@Test
- public void set_user_as_not_local_when_external_identiy_is_not_sonarqube() throws Exception {
+ public void set_user_as_not_local_when_external_identity_is_not_sonarqube() throws Exception {
+ initTaskWithNoRealm();
UserDto user = addUser(USER1_LOGIN, false, "github");
underTest.start();
@@ -127,7 +140,8 @@ public class FeedUsersLocalStartupTaskTest {
@Test
public void does_not_update_removed_user() throws Exception {
- settings.setProperty("sonar.security.realm", "LDAP");
+ initTaskWithRealm();
+ settings.setProperty("sonar.security.realm", REALM_NAME);
UserDto user = UserTesting.newUserDto()
.setLogin(USER1_LOGIN)
@@ -148,7 +162,8 @@ public class FeedUsersLocalStartupTaskTest {
@Test
public void does_nothing_when_task_has_already_been_executed() throws Exception {
- settings.setProperty("sonar.security.realm", "LDAP");
+ initTaskWithRealm();
+ settings.setProperty("sonar.security.realm", REALM_NAME);
settings.setProperty("sonar.security.localUsers", USER1_LOGIN);
UserDto user = addUser(USER1_LOGIN, false, "github");
@@ -168,6 +183,16 @@ public class FeedUsersLocalStartupTaskTest {
verifyEmptyLog();
}
+ @Test
+ public void fail_when_realm_found_but_no_configuration() throws Exception {
+ initTask(createRealm("REALM1"), createRealm("REALM2"));
+
+ expectedException.expect(MessageException.class);
+ expectedException.expectMessage("External authentication plugin [REALM1, REALM2] has been found, but no related configuration has been set. " +
+ "Either update your configuration or remove the plugin");
+ underTest.start();
+ }
+
private UserDto addUser(String login, boolean local, String externalIdentityProvider) {
UserDto user = UserTesting.newUserDto()
.setLogin(login)
@@ -202,4 +227,25 @@ public class FeedUsersLocalStartupTaskTest {
assertThat(logTester.logs(LoggerLevel.INFO)).isEmpty();
}
+ private void initTask(SecurityRealm... realms) {
+ if (realms.length == 0) {
+ underTest = new FeedUsersLocalStartupTask(system2, dbTester.getDbClient(), settings);
+ } else {
+ underTest = new FeedUsersLocalStartupTask(system2, dbTester.getDbClient(), settings, realms);
+ }
+ }
+
+ private void initTaskWithRealm() {
+ initTask(createRealm(REALM_NAME));
+ }
+
+ private void initTaskWithNoRealm() {
+ initTask();
+ }
+
+ private static SecurityRealm createRealm(String name) {
+ SecurityRealm realm = mock(SecurityRealm.class);
+ when(realm.getName()).thenReturn(name);
+ return realm;
+ }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java
index bbd00030f9c..bb72587def8 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java
@@ -22,6 +22,7 @@ package org.sonar.server.user.ws;
import com.google.common.collect.Lists;
import java.util.List;
import org.junit.Before;
+import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.Settings;
@@ -36,11 +37,13 @@ import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDbTester;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDto;
+import org.sonar.db.user.UserTesting;
import org.sonar.server.es.EsTester;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.user.index.UserDoc;
import org.sonar.server.user.index.UserIndex;
import org.sonar.server.user.index.UserIndexDefinition;
+import org.sonar.server.user.index.UserIndexer;
import org.sonar.server.ws.WsTester;
import static com.google.common.collect.Lists.newArrayList;
@@ -68,14 +71,9 @@ public class SearchActionTest {
DbClient dbClient = db.getDbClient();
DbSession dbSession = db.getSession();
- WsTester ws;
- UserIndex index;
-
- @Before
- public void setUp() {
- index = new UserIndex(esTester.client());
- ws = new WsTester(new UsersWs(new SearchAction(index, dbClient, new UserJsonWriter(userSession))));
- }
+ UserIndex index = new UserIndex(esTester.client());
+ UserIndexer userIndexer = (UserIndexer) new UserIndexer(dbClient, esTester.client()).setEnabled(true);
+ WsTester ws = new WsTester(new UsersWs(new SearchAction(index, dbClient, new UserJsonWriter(userSession))));
@Test
public void search_json_example() throws Exception {
@@ -100,7 +98,7 @@ public class SearchActionTest {
}
dbClient.userTokenDao().insert(dbSession, newUserToken().setLogin(fmallet.getLogin()));
db.commit();
- esTester.putDocuments(UserIndexDefinition.INDEX, UserIndexDefinition.TYPE_USER, toUserDoc(fmallet), toUserDoc(simon));
+ userIndexer.index();
loginAsAdmin();
String response = ws.newGetRequest("api/users", "search").execute().outputAsString();
@@ -110,11 +108,13 @@ public class SearchActionTest {
@Test
public void search_empty() throws Exception {
+ loginAsSimpleUser();
ws.newGetRequest("api/users", "search").execute().assertJson(getClass(), "empty.json");
}
@Test
public void search_without_parameters() throws Exception {
+ loginAsSimpleUser();
injectUsers(5);
ws.newGetRequest("api/users", "search").execute().assertJson(getClass(), "five_users.json");
@@ -122,6 +122,7 @@ public class SearchActionTest {
@Test
public void search_with_query() throws Exception {
+ loginAsSimpleUser();
injectUsers(5);
UserDto user = userDb.insertUser(
newUserDto("user-%_%-login", "user-name", "user@mail.com")
@@ -141,6 +142,7 @@ public class SearchActionTest {
@Test
public void search_with_paging() throws Exception {
+ loginAsSimpleUser();
injectUsers(10);
ws.newGetRequest("api/users", "search").setParam(Param.PAGE_SIZE, "5").execute().assertJson(getClass(), "page_one.json");
@@ -149,6 +151,7 @@ public class SearchActionTest {
@Test
public void search_with_fields() throws Exception {
+ loginAsSimpleUser();
injectUsers(1);
assertThat(ws.newGetRequest("api/users", "search").execute().outputAsString())
@@ -198,6 +201,7 @@ public class SearchActionTest {
@Test
public void search_with_groups() throws Exception {
+ loginAsAdmin();
List<UserDto> users = injectUsers(1);
GroupDto group1 = dbClient.groupDao().insert(dbSession, new GroupDto().setName("sonar-users"));
@@ -206,14 +210,31 @@ public class SearchActionTest {
dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setGroupId(group2.getId()).setUserId(users.get(0).getId()));
dbSession.commit();
- loginAsAdmin();
ws.newGetRequest("api/users", "search").execute().assertJson(getClass(), "user_with_groups.json");
}
+ @Test
+ public void only_return_login_and_name_when_not_logged() throws Exception {
+ userSession.anonymous();
+
+ dbClient.userDao().insert(dbSession, UserTesting.newUserDto("john", "John", "john@email.com"));
+ dbSession.commit();
+ userIndexer.index();
+
+ ws.newGetRequest("api/users", "search").execute().assertJson(
+ "{" +
+ " \"users\": [" +
+ " {" +
+ " \"login\": \"john\"," +
+ " \"name\": \"John\"" +
+ " }" +
+ " ]" +
+ "}");
+ }
+
private List<UserDto> injectUsers(int numberOfUsers) throws Exception {
List<UserDto> userDtos = Lists.newArrayList();
long createdAt = System.currentTimeMillis();
- UserDoc[] users = new UserDoc[numberOfUsers];
for (int index = 0; index < numberOfUsers; index++) {
String email = String.format("user-%d@mail.com", index);
String login = String.format("user-%d", index);
@@ -233,8 +254,6 @@ public class SearchActionTest {
.setUpdatedAt(createdAt));
userDtos.add(userDto);
- users[index] = toUserDoc(userDto);
-
for (int tokenIndex = 0; tokenIndex < index; tokenIndex++) {
dbClient.userTokenDao().insert(dbSession, newUserToken()
.setLogin(login)
@@ -242,22 +261,16 @@ public class SearchActionTest {
}
}
dbSession.commit();
- esTester.putDocuments(UserIndexDefinition.INDEX, UserIndexDefinition.TYPE_USER, users);
+ userIndexer.index();
return userDtos;
}
- private static UserDoc toUserDoc(UserDto dto) {
- return new UserDoc()
- .setActive(dto.isActive())
- .setCreatedAt(dto.getCreatedAt())
- .setEmail(dto.getEmail())
- .setLogin(dto.getLogin())
- .setName(dto.getName())
- .setScmAccounts(dto.getScmAccountsAsList())
- .setUpdatedAt(dto.getUpdatedAt());
- }
-
private void loginAsAdmin() {
userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
}
+
+ private void loginAsSimpleUser() {
+ userSession.login("user");
+ }
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/SearchActionTest.java
index 605db91747d..b8c65d582db 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/SearchActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/SearchActionTest.java
@@ -23,15 +23,17 @@ import org.apache.commons.lang.StringUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.user.GroupDao;
-import org.sonar.db.user.GroupMembershipDao;
import org.sonar.db.user.UserGroupDao;
import org.sonar.db.user.UserGroupDto;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;
import static org.assertj.core.api.Assertions.assertThat;
@@ -42,10 +44,16 @@ public class SearchActionTest {
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
+
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
private WsTester ws;
private GroupDao groupDao;
- private GroupMembershipDao groupMembershipDao;
private UserGroupDao userGroupDao;
private DbSession dbSession;
@@ -53,21 +61,22 @@ public class SearchActionTest {
public void setUp() {
DbClient dbClient = db.getDbClient();
groupDao = dbClient.groupDao();
- groupMembershipDao = dbClient.groupMembershipDao();
userGroupDao = dbClient.userGroupDao();
- ws = new WsTester(new UserGroupsWs(new SearchAction(dbClient)));
+ ws = new WsTester(new UserGroupsWs(new SearchAction(dbClient, userSession)));
dbSession = dbClient.openSession(false);
}
@Test
public void search_empty() throws Exception {
+ loginAsSimpleUser();
newRequest().execute().assertJson(getClass(), "empty.json");
}
@Test
public void search_without_parameters() throws Exception {
+ loginAsSimpleUser();
insertGroups("users", "admins", "customer1", "customer2", "customer3");
dbSession.commit();
@@ -76,6 +85,7 @@ public class SearchActionTest {
@Test
public void search_with_members() throws Exception {
+ loginAsSimpleUser();
insertGroups("users", "admins", "customer1", "customer2", "customer3");
insertMembers("users", 5);
insertMembers("admins", 1);
@@ -87,6 +97,7 @@ public class SearchActionTest {
@Test
public void search_with_query() throws Exception {
+ loginAsSimpleUser();
insertGroups("users", "admins", "customer%_%/1", "customer%_%/2", "customer%_%/3");
dbSession.commit();
@@ -95,6 +106,7 @@ public class SearchActionTest {
@Test
public void search_with_paging() throws Exception {
+ loginAsSimpleUser();
insertGroups("users", "admins", "customer1", "customer2", "customer3");
dbSession.commit();
@@ -108,6 +120,7 @@ public class SearchActionTest {
@Test
public void search_with_fields() throws Exception {
+ loginAsSimpleUser();
insertGroups("sonar-users");
dbSession.commit();
@@ -142,6 +155,14 @@ public class SearchActionTest {
.contains("membersCount");
}
+ @Test
+ public void fail_when_not_logged() throws Exception {
+ userSession.anonymous();
+
+ expectedException.expect(UnauthorizedException.class);
+ newRequest().execute();
+ }
+
private WsTester.TestRequest newRequest() {
return ws.newGetRequest("api/user_groups", "search");
}
@@ -160,4 +181,9 @@ public class SearchActionTest {
userGroupDao.insert(dbSession, new UserGroupDto().setGroupId(groupId).setUserId((long) i + 1));
}
}
+
+ private void loginAsSimpleUser() {
+ userSession.login("user");
+ }
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsWsTest.java
index ba1a32bacd7..2e8b7a6755e 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsWsTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsWsTest.java
@@ -32,14 +32,16 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
public class UserGroupsWsTest {
+
@Rule
public UserSessionRule userSessionRule = UserSessionRule.standalone();
+
WebService.Controller controller;
@Before
public void setUp() {
WsTester tester = new WsTester(new UserGroupsWs(
- new SearchAction(mock(DbClient.class)),
+ new SearchAction(mock(DbClient.class), mock(UserSession.class)),
new CreateAction(mock(DbClient.class), mock(UserSession.class), mock(UserGroupUpdater.class))));
controller = tester.controller("api/user_groups");
}
diff --git a/server/sonar-web/src/main/js/apps/groups/list-view.js b/server/sonar-web/src/main/js/apps/groups/list-view.js
index 20280b7c7c4..cca2de036ae 100644
--- a/server/sonar-web/src/main/js/apps/groups/list-view.js
+++ b/server/sonar-web/src/main/js/apps/groups/list-view.js
@@ -19,10 +19,12 @@
*/
import Marionette from 'backbone.marionette';
import ListItemView from './list-item-view';
+import Template from './templates/groups-list.hbs';
-export default Marionette.CollectionView.extend({
- tagName: 'ul',
+export default Marionette.CompositeView.extend({
childView: ListItemView,
+ childViewContainer: '.js-list',
+ template: Template,
collectionEvents: {
'request': 'showLoading',
@@ -35,6 +37,10 @@ export default Marionette.CollectionView.extend({
hideLoading () {
this.$el.removeClass('new-loading');
+
+ const query = this.collection.q || '';
+ const shouldHideAnyone = !'anyone'.includes(query.toLowerCase());
+ this.$('.js-anyone').toggleClass('hidden', shouldHideAnyone);
}
});
diff --git a/server/sonar-web/src/main/js/apps/groups/templates/groups-list.hbs b/server/sonar-web/src/main/js/apps/groups/templates/groups-list.hbs
new file mode 100644
index 00000000000..71820036560
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/templates/groups-list.hbs
@@ -0,0 +1,18 @@
+<div>
+ <div class="panel panel-vertical js-anyone">
+ <div class="display-inline-block text-top width-20">
+ <strong class="js-group-name">Anyone</strong>
+ </div>
+
+ <div class="display-inline-block text-top big-spacer-left width-25">
+
+ </div>
+
+ <div class="display-inline-block text-top big-spacer-left width-40">
+ <span class="js-group-description">{{t 'user_groups.anyone.description'}}</span>
+ </div>
+
+ </div>
+
+ <ul class="js-list"></ul>
+</div>
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1153_update_users_external_identity_when_empty.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1153_update_users_external_identity_when_empty.rb
new file mode 100644
index 00000000000..fdfe843b69a
--- /dev/null
+++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1153_update_users_external_identity_when_empty.rb
@@ -0,0 +1,31 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube 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.
+#
+# SonarQube 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.
+#
+
+#
+# SonarQube 5.6.1
+# SONAR-7686
+#
+class UpdateUsersExternalIdentityWhenEmpty < ActiveRecord::Migration
+
+ def self.up
+ execute_java_migration('org.sonar.db.version.v56.UpdateUsersExternalIdentityWhenEmpty')
+ end
+
+end
diff --git a/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java b/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
index 2c3be5b7f11..2e3b5f8bfcb 100644
--- a/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
+++ b/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
@@ -83,6 +83,7 @@ import org.sonar.db.version.v55.FeedRulesLongDateColumns;
import org.sonar.db.version.v55.FeedRulesTypes;
import org.sonar.db.version.v56.FixLengthOfIssuesMessageOnOracle;
import org.sonar.db.version.v56.FixTypeOfRuleTypeOnMysql;
+import org.sonar.db.version.v56.UpdateUsersExternalIdentityWhenEmpty;
import org.sonar.db.version.v60.AddAnalysisUuidColumnToCeActivity;
import org.sonar.db.version.v60.AddAnalysisUuidColumnToEvents;
import org.sonar.db.version.v60.AddAnalysisUuidColumnToMeasures;
@@ -226,6 +227,7 @@ public class MigrationStepModule extends Module {
// 5.6
FixTypeOfRuleTypeOnMysql.class,
FixLengthOfIssuesMessageOnOracle.class,
+ UpdateUsersExternalIdentityWhenEmpty.class,
// 6.0
AddUuidColumnsToResourceIndex.class,
diff --git a/sonar-db/src/main/java/org/sonar/db/version/v56/UpdateUsersExternalIdentityWhenEmpty.java b/sonar-db/src/main/java/org/sonar/db/version/v56/UpdateUsersExternalIdentityWhenEmpty.java
new file mode 100644
index 00000000000..68d5a5046d9
--- /dev/null
+++ b/sonar-db/src/main/java/org/sonar/db/version/v56/UpdateUsersExternalIdentityWhenEmpty.java
@@ -0,0 +1,69 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.db.version.v56;
+
+import java.sql.SQLException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.Database;
+import org.sonar.db.version.BaseDataChange;
+import org.sonar.db.version.MassUpdate;
+import org.sonar.db.version.Select;
+import org.sonar.db.version.SqlStatement;
+
+/**
+ * Update USERS.EXTERNAL_IDENTITY_PROVIDER to 'sonarqube' and USERS.EXTERNAL_IDENTITY to user's login when one of this 2 columns is null
+ */
+public class UpdateUsersExternalIdentityWhenEmpty extends BaseDataChange {
+
+ private final System2 system2;
+
+ public UpdateUsersExternalIdentityWhenEmpty(Database db, System2 system2) {
+ super(db);
+ this.system2 = system2;
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ MassUpdate massUpdate = context.prepareMassUpdate();
+ massUpdate.select("SELECT u.id, u.login FROM users u WHERE external_identity_provider IS NULL OR external_identity IS NULL");
+ massUpdate.update("UPDATE users SET external_identity_provider=?, external_identity=?, updated_at=? WHERE id=?");
+ massUpdate.rowPluralName("users");
+ massUpdate.execute(new MigrationHandler(system2.now()));
+ }
+
+ private static class MigrationHandler implements MassUpdate.Handler {
+
+ private final long now;
+
+ public MigrationHandler(long now) {
+ this.now = now;
+ }
+
+ @Override
+ public boolean handle(Select.Row row, SqlStatement update) throws SQLException {
+ update.setString(1, "sonarqube");
+ update.setString(2, row.getString(2));
+ update.setLong(3, now);
+ update.setLong(4, row.getLong(1));
+ return true;
+ }
+ }
+
+}
diff --git a/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql b/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
index 5e0c15f1de8..fff413c49dd 100644
--- a/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
+++ b/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
@@ -405,6 +405,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1125');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1150');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1151');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1152');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1153');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1200');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1201');
diff --git a/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java b/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
index b10eba51a6f..579506d38b1 100644
--- a/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
+++ b/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
@@ -29,6 +29,6 @@ public class MigrationStepModuleTest {
public void verify_count_of_added_MigrationStep_types() {
ComponentContainer container = new ComponentContainer();
new MigrationStepModule().configure(container);
- assertThat(container.size()).isEqualTo(125);
+ assertThat(container.size()).isEqualTo(126);
}
}
diff --git a/sonar-db/src/test/java/org/sonar/db/version/v56/UpdateUsersExternalIdentityWhenEmptyTest.java b/sonar-db/src/test/java/org/sonar/db/version/v56/UpdateUsersExternalIdentityWhenEmptyTest.java
new file mode 100644
index 00000000000..7f0abdcc7db
--- /dev/null
+++ b/sonar-db/src/test/java/org/sonar/db/version/v56/UpdateUsersExternalIdentityWhenEmptyTest.java
@@ -0,0 +1,104 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.db.version.v56;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.db.version.MigrationStep;
+
+import static com.google.common.collect.Maps.newHashMap;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class UpdateUsersExternalIdentityWhenEmptyTest {
+
+ @Rule
+ public DbTester db = DbTester.createForSchema(System2.INSTANCE, UpdateUsersExternalIdentityWhenEmptyTest.class, "schema.sql");
+
+ static final long PAST = 1_000_000_000_000L;
+ static final long NOW = 1_500_000_000_000L;
+
+ System2 system = mock(System2.class);
+
+ MigrationStep underTest = new UpdateUsersExternalIdentityWhenEmpty(db.database(), system);
+
+ @Before
+ public void setUp() throws Exception {
+ when(system.now()).thenReturn(NOW);
+ }
+
+ @Test
+ public void migrate_users() throws Exception {
+ insertUser("user-without-eternal-identity", null, null, PAST);
+ insertUser("user-with-only-eternal-identity-provider", "github", null, PAST);
+ insertUser("user-with-only-eternal-identity", null, "login1", PAST);
+ insertUser("user-with-both-eternal-identity", "github", "login2", PAST);
+
+ underTest.execute();
+
+ checkUserIsUpdated("user-without-eternal-identity");
+ checkUserIsUpdated("user-with-only-eternal-identity-provider");
+ checkUserIsUpdated("user-with-only-eternal-identity");
+
+ checkUserIsNotUpdated("user-with-both-eternal-identity");
+ }
+
+ @Test
+ public void doest_not_fail_when_no_user() throws Exception {
+ underTest.execute();
+ }
+
+ private void insertUser(String login, @Nullable String externalIdentity, @Nullable String externalIdentityProvider, long updatedAt) {
+ Map<String, String> params = newHashMap(ImmutableMap.of(
+ "LOGIN", login,
+ "CREATED_AT", Long.toString(PAST),
+ "UPDATED_AT", Long.toString(updatedAt)));
+ if (externalIdentity != null) {
+ params.put("EXTERNAL_IDENTITY", externalIdentity);
+ }
+ if (externalIdentityProvider != null) {
+ params.put("EXTERNAL_IDENTITY_PROVIDER", externalIdentityProvider);
+ }
+
+ db.executeInsert("users", params);
+ }
+
+ private void checkUserIsUpdated(String login) {
+ Map<String, Object> row = db.selectFirst("select EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, UPDATED_AT from users where LOGIN='" + login + "'");
+ assertThat((String) row.get("EXTERNAL_IDENTITY_PROVIDER")).isEqualTo("sonarqube");
+ assertThat((String) row.get("EXTERNAL_IDENTITY")).isEqualTo(login);
+ assertThat(row.get("UPDATED_AT")).isEqualTo(NOW);
+ }
+
+ private void checkUserIsNotUpdated(String login) {
+ Map<String, Object> row = db.selectFirst("select EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, UPDATED_AT from users where LOGIN='" + login + "'");
+ assertThat((String) row.get("EXTERNAL_IDENTITY_PROVIDER")).isNotEmpty();
+ assertThat((String) row.get("EXTERNAL_IDENTITY")).isNotEmpty();
+ assertThat(row.get("UPDATED_AT")).isEqualTo(PAST);
+ }
+
+}
diff --git a/sonar-db/src/test/resources/org/sonar/db/version/v56/UpdateUsersExternalIdentityWhenEmptyTest/schema.sql b/sonar-db/src/test/resources/org/sonar/db/version/v56/UpdateUsersExternalIdentityWhenEmptyTest/schema.sql
new file mode 100644
index 00000000000..127fc346a9f
--- /dev/null
+++ b/sonar-db/src/test/resources/org/sonar/db/version/v56/UpdateUsersExternalIdentityWhenEmptyTest/schema.sql
@@ -0,0 +1,17 @@
+CREATE TABLE "USERS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "LOGIN" VARCHAR(255),
+ "NAME" VARCHAR(200),
+ "EMAIL" VARCHAR(100),
+ "CRYPTED_PASSWORD" VARCHAR(40),
+ "SALT" VARCHAR(40),
+ "REMEMBER_TOKEN" VARCHAR(500),
+ "REMEMBER_TOKEN_EXPIRES_AT" TIMESTAMP,
+ "ACTIVE" BOOLEAN DEFAULT TRUE,
+ "SCM_ACCOUNTS" VARCHAR(4000),
+ "EXTERNAL_IDENTITY" VARCHAR(255),
+ "EXTERNAL_IDENTITY_PROVIDER" VARCHAR(100),
+ "USER_LOCAL" BOOLEAN,
+ "CREATED_AT" BIGINT,
+ "UPDATED_AT" BIGINT
+);