aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-server/src
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2018-11-20 21:30:41 +0100
committerSonarTech <sonartech@sonarsource.com>2018-11-21 20:20:57 +0100
commit5788d993b8417cec4f346e728c575341145b20ad (patch)
treef4a5f1415535ba14979131521a588ed80cd403a9 /server/sonar-server/src
parent4a1aaab8cc4d0db84f06389093b7bfa3d8e70abd (diff)
downloadsonarqube-5788d993b8417cec4f346e728c575341145b20ad.tar.gz
sonarqube-5788d993b8417cec4f346e728c575341145b20ad.zip
SONARCLOUD-172 SONARCLOUD-188 fix access to secured settings
Diffstat (limited to 'server/sonar-server/src')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java11
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/setting/ws/ValuesAction.java16
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/setting/ws/ValuesActionTest.java78
3 files changed, 86 insertions, 19 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java b/server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java
index f3decab26bd..906c0492526 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java
@@ -73,8 +73,12 @@ public class SettingsWsSupport {
return hasPermission(OrganizationPermission.SCAN, SCAN_EXECUTION, component) || (verifySecuredSetting(key, definition, component) && (verifyLicenseSetting(key, definition)));
}
+ static boolean isSecured(String key) {
+ return key.endsWith(DOT_SECURED);
+ }
+
private boolean verifySecuredSetting(String key, @Nullable PropertyDefinition definition, Optional<ComponentDto> component) {
- return isLicense(key, definition) || (!key.endsWith(DOT_SECURED) || hasPermission(OrganizationPermission.ADMINISTER, ADMIN, component));
+ return isLicense(key, definition) || (!isSecured(key) || hasPermission(OrganizationPermission.ADMINISTER, ADMIN, component));
}
private boolean verifyLicenseSetting(String key, @Nullable PropertyDefinition definition) {
@@ -86,11 +90,14 @@ public class SettingsWsSupport {
}
private boolean hasPermission(OrganizationPermission orgPermission, String projectPermission, Optional<ComponentDto> component) {
+ if (userSession.isSystemAdministrator()) {
+ return true;
+ }
if (userSession.hasPermission(orgPermission, defaultOrganizationProvider.get().getUuid())) {
return true;
}
return component
- .map(c -> userSession.hasComponentPermission(projectPermission, c))
+ .map(c -> userSession.hasPermission(orgPermission, c.getOrganizationUuid()) || userSession.hasComponentPermission(projectPermission, c))
.orElse(false);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/setting/ws/ValuesAction.java b/server/sonar-server/src/main/java/org/sonar/server/setting/ws/ValuesAction.java
index 66ad5d203eb..430f3c6e23f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/setting/ws/ValuesAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/setting/ws/ValuesAction.java
@@ -35,6 +35,7 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+import org.sonar.api.config.Configuration;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.server.ws.Change;
@@ -60,11 +61,13 @@ import static org.sonar.api.CoreProperties.SERVER_STARTTIME;
import static org.sonar.api.PropertyType.PROPERTY_SET;
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
+import static org.sonar.process.ProcessProperties.Property.SONARCLOUD_ENABLED;
import static org.sonar.server.setting.ws.PropertySetExtractor.extractPropertySetKeys;
import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_BRANCH;
import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_COMPONENT;
import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_KEYS;
import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_PULL_REQUEST;
+import static org.sonar.server.setting.ws.SettingsWsSupport.isSecured;
import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
@@ -81,14 +84,16 @@ public class ValuesAction implements SettingsWsAction {
private final UserSession userSession;
private final PropertyDefinitions propertyDefinitions;
private final SettingsWsSupport settingsWsSupport;
+ private final boolean isSonarCloud;
public ValuesAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, PropertyDefinitions propertyDefinitions,
- SettingsWsSupport settingsWsSupport) {
+ SettingsWsSupport settingsWsSupport, Configuration configuration) {
this.dbClient = dbClient;
this.componentFinder = componentFinder;
this.userSession = userSession;
this.propertyDefinitions = propertyDefinitions;
this.settingsWsSupport = settingsWsSupport;
+ this.isSonarCloud = configuration.getBoolean(SONARCLOUD_ENABLED.getKey()).orElse(false);
}
@Override
@@ -194,7 +199,14 @@ public class ValuesAction implements SettingsWsAction {
}
private List<Setting> loadGlobalSettings(DbSession dbSession, Set<String> keys) {
- List<PropertyDto> properties = dbClient.propertiesDao().selectGlobalPropertiesByKeys(dbSession, keys);
+ Set<String> allowedKeys;
+ if (isSonarCloud && !userSession.isSystemAdministrator()) {
+ // remove the global settings that require admin permission
+ allowedKeys = keys.stream().filter(k -> !isSecured(k)).collect(Collectors.toSet());
+ } else {
+ allowedKeys = keys;
+ }
+ List<PropertyDto> properties = dbClient.propertiesDao().selectGlobalPropertiesByKeys(dbSession, allowedKeys);
List<PropertyDto> propertySets = dbClient.propertiesDao().selectGlobalPropertiesByKeys(dbSession, getPropertySetKeys(properties));
return properties.stream()
.map(property -> Setting.createFromDto(property, getPropertySets(property.getKey(), propertySets, null), propertyDefinitions.get(property.getKey())))
diff --git a/server/sonar-server/src/test/java/org/sonar/server/setting/ws/ValuesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/setting/ws/ValuesActionTest.java
index 7d23581c158..8b0ec0a4a0a 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/setting/ws/ValuesActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/setting/ws/ValuesActionTest.java
@@ -28,9 +28,11 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.PropertyType;
+import org.sonar.api.config.Configuration;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.PropertyFieldDefinition;
+import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
@@ -40,6 +42,7 @@ import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.permission.OrganizationPermission;
import org.sonar.db.property.PropertyDbTester;
import org.sonar.process.ProcessProperties;
import org.sonar.server.component.TestComponentFinder;
@@ -66,10 +69,10 @@ import static org.sonar.api.web.UserRole.CODEVIEWER;
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
import static org.sonar.db.component.ComponentTesting.newModuleDto;
-import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
import static org.sonar.db.permission.OrganizationPermission.SCAN;
import static org.sonar.db.property.PropertyTesting.newComponentPropertyDto;
import static org.sonar.db.property.PropertyTesting.newGlobalPropertyDto;
+import static org.sonar.process.ProcessProperties.Property.SONARCLOUD_ENABLED;
import static org.sonarqube.ws.MediaTypes.JSON;
import static org.sonarqube.ws.Settings.Setting.ParentValueOneOfCase.PARENTVALUEONEOF_NOT_SET;
@@ -92,9 +95,6 @@ public class ValuesActionTest {
private SettingsWsSupport support = new SettingsWsSupport(defaultOrganizationProvider, userSession);
private ComponentDto project;
- private WsActionTester ws = new WsActionTester(
- new ValuesAction(dbClient, TestComponentFinder.from(db), userSession, definitions, support));
-
@Before
public void setUp() throws Exception {
OrganizationDto organizationDto = db.organizations().insert();
@@ -733,7 +733,7 @@ public class ValuesActionTest {
definitions.addComponent(PropertyDefinition.builder("sonar.leak.period").onQualifiers(PROJECT).build());
propertyDb.insertProperties(newComponentPropertyDto(branch).setKey("sonar.leak.period").setValue("two"));
- ValuesWsResponse result = ws.newRequest()
+ ValuesWsResponse result = newTester().newRequest()
.setParam("keys", "sonar.leak.period")
.setParam("component", branch.getKey())
.setParam("branch", branch.getBranch())
@@ -751,7 +751,7 @@ public class ValuesActionTest {
definitions.addComponent(PropertyDefinition.builder("sonar.leak.period").onQualifiers(PROJECT).build());
propertyDb.insertProperties(newComponentPropertyDto(project).setKey("sonar.leak.period").setValue("two"));
- ValuesWsResponse result = ws.newRequest()
+ ValuesWsResponse result = newTester().newRequest()
.setParam("keys", "sonar.leak.period")
.setParam("component", branch.getKey())
.setParam("branch", branch.getBranch())
@@ -791,7 +791,7 @@ public class ValuesActionTest {
expectedException.expect(NotFoundException.class);
expectedException.expectMessage("Component key 'unknown' not found");
- ws.newRequest()
+ newTester().newRequest()
.setParam("keys", "foo")
.setParam("component", "unknown")
.execute();
@@ -807,7 +807,7 @@ public class ValuesActionTest {
expectedException.expect(NotFoundException.class);
expectedException.expectMessage(format("Component '%s' on branch 'unknown' not found", branch.getKey()));
- ws.newRequest()
+ newTester().newRequest()
.setParam("keys", settingKey)
.setParam("component", branch.getKey())
.setParam("branch", "unknown")
@@ -834,13 +834,13 @@ public class ValuesActionTest {
.build());
propertyDb.insertPropertySet("sonar.demo", null, ImmutableMap.of("text", "foo", "boolean", "true"), ImmutableMap.of("text", "bar", "boolean", "false"));
- String result = ws.newRequest()
+ String result = newTester().newRequest()
.setParam("keys", "sonar.test.jira,sonar.autogenerated,sonar.demo")
.setMediaType(JSON)
.execute()
.getInput();
- JsonAssert.assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(result);
+ JsonAssert.assertJson(newTester().getDef().responseExampleAsString()).isSimilarTo(result);
}
@Test
@@ -853,7 +853,7 @@ public class ValuesActionTest {
expectedException.expect(NotFoundException.class);
expectedException.expectMessage(format("Component key '%s' not found", branch.getDbKey()));
- ws.newRequest()
+ newTester().newRequest()
.setParam("keys", "foo")
.setParam("component", branch.getDbKey())
.execute();
@@ -868,7 +868,7 @@ public class ValuesActionTest {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage(format("Setting '%s' can only be used in sonar.properties", settingKey));
- ws.newRequest()
+ newTester().newRequest()
.setParam("keys", settingKey)
.setParam("component", project.getKey())
.execute();
@@ -876,7 +876,7 @@ public class ValuesActionTest {
@Test
public void test_ws_definition() {
- WebService.Action action = ws.getDef();
+ WebService.Action action = newTester().getDef();
assertThat(action).isNotNull();
assertThat(action.isInternal()).isFalse();
assertThat(action.isPost()).isFalse();
@@ -884,6 +884,38 @@ public class ValuesActionTest {
assertThat(action.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("keys", "component", "branch", "pullRequest");
}
+ @Test
+ public void sonarcloud_global_secured_properties_require_system_admin_permission() {
+ PropertyDefinition securedDef = PropertyDefinition.builder("my.password.secured").build();
+ PropertyDefinition standardDef = PropertyDefinition.builder("my.property").build();
+ definitions.addComponents(asList(securedDef, standardDef));
+ propertyDb.insertProperties(
+ newGlobalPropertyDto().setKey(securedDef.key()).setValue("securedValue"),
+ newGlobalPropertyDto().setKey(standardDef.key()).setValue("standardValue"));
+
+ // anonymous
+ WsActionTester tester = newSonarCloudTester();
+ ValuesWsResponse response = executeRequest(tester, null, securedDef.key(), standardDef.key());
+ assertThat(response.getSettingsList()).extracting(Settings.Setting::getValue).containsExactly("standardValue");
+
+ // organization administrator but not system administrator
+ userSession.logIn()
+ .addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization());
+ response = executeRequest(tester, null, securedDef.key(), standardDef.key());
+ assertThat(response.getSettingsList()).extracting(Settings.Setting::getValue).containsExactly("standardValue");
+
+ // organization administrator
+ userSession.logIn()
+ .addPermission(OrganizationPermission.ADMINISTER, db.getDefaultOrganization());
+ response = executeRequest(tester, null, securedDef.key(), standardDef.key());
+ assertThat(response.getSettingsList()).extracting(Settings.Setting::getValue).containsExactly("standardValue");
+
+ // system administrator
+ userSession.logIn().setSystemAdministrator();
+ response = executeRequest(tester, null, securedDef.key(), standardDef.key());
+ assertThat(response.getSettingsList()).extracting(Settings.Setting::getValue).containsExactlyInAnyOrder("securedValue", "standardValue");
+ }
+
private ValuesWsResponse executeRequestForComponentProperties(ComponentDto componentDto, String... keys) {
return executeRequest(componentDto.getDbKey(), keys);
}
@@ -897,7 +929,11 @@ public class ValuesActionTest {
}
private ValuesWsResponse executeRequest(@Nullable String componentKey, String... keys) {
- TestRequest request = ws.newRequest();
+ return executeRequest(newTester(), componentKey, keys);
+ }
+
+ private ValuesWsResponse executeRequest(WsActionTester tester, @Nullable String componentKey, String... keys) {
+ TestRequest request = tester.newRequest();
if (keys.length > 0) {
request.setParam("keys", COMMA_JOINER.join(keys));
}
@@ -916,7 +952,7 @@ public class ValuesActionTest {
}
private void logInAsAdmin() {
- userSession.logIn().addPermission(ADMINISTER, db.getDefaultOrganization());
+ userSession.logIn().setSystemAdministrator();
}
private void logInAsProjectAdmin() {
@@ -968,4 +1004,16 @@ public class ValuesActionTest {
}
}
}
+
+ private WsActionTester newTester() {
+ MapSettings settings = new MapSettings();
+ Configuration configuration = settings.asConfig();
+ return new WsActionTester(new ValuesAction(dbClient, TestComponentFinder.from(db), userSession, definitions, support, configuration));
+ }
+
+ private WsActionTester newSonarCloudTester() {
+ MapSettings settings = new MapSettings().setProperty(SONARCLOUD_ENABLED.getKey(), "true");
+ Configuration configuration = settings.asConfig();
+ return new WsActionTester(new ValuesAction(dbClient, TestComponentFinder.from(db), userSession, definitions, support, configuration));
+ }
}