global_role.profileadmin.desc=Ability to perform any action on the quality profiles.
global_role.sharedashboard=Dashboard Sharing
global_role.sharedashboard.desc=Ability to share dashboards that any user will be able to follow.
-
+global_role.scan=Ability to execute some Sonar analysis
+global_role.scan.desc=Permission required to execute a Sonar analysis. This permission allows to get all settings (even the secured ones like scm account password, jira account password, ...) required to execute all Sonar plugins.
+global_role.dryrun=Ability to execute some local (dry run) Sonar analysis
+global_role.dryrun.desc=Permission required to execute a local (dry run) Sonar analysis without pushing the results to the Sonar server. This permission allows to get all settings required to execute all Sonar plugins except the secured one like scm account password, jira account password... This permission is required for instance to execute a local Sonar analysis in Sonar Eclipse.
#------------------------------------------------------------------------------
#
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.Settings;
+import org.sonar.api.utils.SonarException;
import javax.annotation.Nullable;
+
import java.util.List;
import java.util.Map;
public class BatchSettings extends Settings {
private Configuration deprecatedConfiguration;
+ private boolean dryRun;
// Keep module settings for initialization of ProjectSettings
// module key -> <key,val>
private Map<String, String> savedProperties;
public BatchSettings(BootstrapSettings bootstrapSettings, PropertyDefinitions propertyDefinitions,
- ServerClient client, Configuration deprecatedConfiguration) {
+ ServerClient client, Configuration deprecatedConfiguration) {
super(propertyDefinitions);
this.bootstrapSettings = bootstrapSettings;
this.client = client;
public void init(@Nullable ProjectReactor reactor) {
savedProperties = this.getProperties();
+ // Do not use getBoolean to avoid recursion
+ this.dryRun = "true".equals(bootstrapSettings.property(CoreProperties.DRY_RUN));
if (reactor != null) {
LoggerFactory.getLogger(BatchSettings.class).info("Load project settings");
String branch = bootstrapSettings.property(CoreProperties.PROJECT_BRANCH_PROPERTY);
private void downloadSettings(ServerClient client, @Nullable String projectKey) {
String url;
if (StringUtils.isNotBlank(projectKey)) {
- url = "/batch_bootstrap/properties?project=" + projectKey;
+ url = "/batch_bootstrap/properties?project=" + projectKey + "&dryRun=" + dryRun;
} else {
- url = "/batch_bootstrap/properties";
+ url = "/batch_bootstrap/properties?dryRun=" + dryRun;
}
String jsonText = client.request(url);
List<Map<String, String>> json = (List<Map<String, String>>) JSONValue.parse(jsonText);
protected void doOnClearProperties() {
deprecatedConfiguration.clear();
}
+
+ @Override
+ protected void doOnGetProperties(String key) {
+ if (dryRun && key.endsWith(".secured") && !key.contains(".license")) {
+ throw new SonarException("Access to the secured property '" + key
+ + "' is not possible in local (dry run) SonarQube analysis. The SonarQube plugin accessing to this property must be deactivated in dry run mode.");
+ }
+ }
}
if (he.getResponseCode() == 401) {
return new SonarException(String.format(getMessageWhenNotAuthorized(), CoreProperties.LOGIN, CoreProperties.PASSWORD));
}
+ if (he.getResponseCode() == 403) {
+ // SONAR-4397 Details are in response content
+ return new SonarException(he.getResponseContent());
+ }
return new SonarException(String.format("Fail to execute request [code=%s, url=%s]", he.getResponseCode(), he.getUri()), he);
}
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.config.Settings;
+import org.sonar.api.utils.SonarException;
import org.sonar.batch.bootstrap.BatchSettings;
import javax.annotation.Nullable;
public class ModuleSettings extends Settings {
private final Configuration deprecatedCommonsConf;
+ private boolean dryRun;
public ModuleSettings(BatchSettings batchSettings, ProjectDefinition project, Configuration deprecatedCommonsConf) {
super(batchSettings.getDefinitions());
+ this.dryRun = "true".equals(batchSettings.getString(CoreProperties.DRY_RUN));
LoggerFactory.getLogger(ModuleSettings.class).info("Load module settings");
this.deprecatedCommonsConf = deprecatedCommonsConf;
protected void doOnClearProperties() {
deprecatedCommonsConf.clear();
}
+
+ @Override
+ protected void doOnGetProperties(String key) {
+ if (this.dryRun && key.endsWith(".secured") && !key.contains(".license")) {
+ throw new SonarException("Access to the secured property '" + key
+ + "' is not possible in local (dry run) SonarQube analysis. The SonarQube plugin accessing to this property must be deactivated in dry run mode.");
+ }
+ }
}
import org.apache.commons.configuration.BaseConfiguration;
import org.apache.commons.configuration.Configuration;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.utils.SonarException;
import java.util.Collections;
import java.util.Map;
public class BatchSettingsTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
private static final String JSON_RESPONSE = "[{\"k\":\"sonar.cpd.cross\",\"v\":\"true\"}]";
+ private static final String JSON_RESPONSE_WITH_SECURED = "[{\"k\":\"sonar.foo.secured\",\"v\":\"bar\"},{\"k\":\"sonar.foo.license.secured\",\"v\":\"bar2\"}]";
private static final String REACTOR_JSON_RESPONSE = "[{\"k\":\"sonar.cpd.cross\",\"v\":\"true\"}," +
"{\"k\":\"sonar.java.coveragePlugin\",\"v\":\"jacoco\",\"p\":\"struts\"}," +
"{\"k\":\"sonar.java.coveragePlugin\",\"v\":\"cobertura\",\"p\":\"struts-core\"}]";
+ private static final String BRANCH_REACTOR_JSON_RESPONSE = "[{\"k\":\"sonar.cpd.cross\",\"v\":\"true\"}," +
+ "{\"k\":\"sonar.java.coveragePlugin\",\"v\":\"jacoco\",\"p\":\"struts:mybranch\"}," +
+ "{\"k\":\"sonar.java.coveragePlugin\",\"v\":\"cobertura\",\"p\":\"struts-core:mybranch\"}]";
+
ServerClient client = mock(ServerClient.class);
ProjectDefinition project = ProjectDefinition.create().setKey("struts");
Configuration deprecatedConf = new BaseConfiguration();
- BootstrapSettings bootstrapSettings = new BootstrapSettings(new BootstrapProperties(Collections.<String, String> emptyMap()));
+ BootstrapSettings bootstrapSettings;
+
+ @Before
+ public void prepare() {
+ bootstrapSettings = new BootstrapSettings(new BootstrapProperties(Collections.<String, String> emptyMap()));
+ }
@Test
public void should_load_system_props() {
- when(client.request("/batch_bootstrap/properties")).thenReturn(JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?dryRun=false")).thenReturn(JSON_RESPONSE);
System.setProperty("BatchSettingsTest.testSystemProp", "system");
// Reconstruct bootstrap settings to get system property
bootstrapSettings = new BootstrapSettings(new BootstrapProperties(Collections.<String, String> emptyMap()));
@Test
public void should_load_project_props() {
- when(client.request("/batch_bootstrap/properties")).thenReturn(JSON_RESPONSE);
- when(client.request("/batch_bootstrap/properties?project=struts")).thenReturn(REACTOR_JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?dryRun=false")).thenReturn(JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?project=struts&dryRun=false")).thenReturn(REACTOR_JSON_RESPONSE);
project.setProperty("project.prop", "project");
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf);
@Test
public void should_load_global_settings() {
- when(client.request("/batch_bootstrap/properties")).thenReturn(JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?dryRun=false")).thenReturn(JSON_RESPONSE);
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf);
@Test
public void should_load_project_root_settings() {
- when(client.request("/batch_bootstrap/properties")).thenReturn(JSON_RESPONSE);
- when(client.request("/batch_bootstrap/properties?project=struts")).thenReturn(REACTOR_JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?dryRun=false")).thenReturn(JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?project=struts&dryRun=false")).thenReturn(REACTOR_JSON_RESPONSE);
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf);
batchSettings.init(new ProjectReactor(project));
assertThat(batchSettings.getString("sonar.java.coveragePlugin")).isEqualTo("jacoco");
}
+ @Test
+ public void should_load_project_root_settings_on_branch() {
+ when(client.request("/batch_bootstrap/properties?dryRun=false")).thenReturn(JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?project=struts:mybranch&dryRun=false")).thenReturn(BRANCH_REACTOR_JSON_RESPONSE);
+
+ bootstrapSettings.properties().put(CoreProperties.PROJECT_BRANCH_PROPERTY, "mybranch");
+
+ BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf);
+ batchSettings.init(new ProjectReactor(project));
+
+ assertThat(batchSettings.getString("sonar.java.coveragePlugin")).isEqualTo("jacoco");
+ }
+
+ @Test
+ public void should_not_fail_when_accessing_secured_properties() {
+ when(client.request("/batch_bootstrap/properties?dryRun=false")).thenReturn(JSON_RESPONSE_WITH_SECURED);
+ when(client.request("/batch_bootstrap/properties?project=struts&dryRun=false")).thenReturn(REACTOR_JSON_RESPONSE);
+
+ BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf);
+ batchSettings.init(new ProjectReactor(project));
+
+ assertThat(batchSettings.getString("sonar.foo.license.secured")).isEqualTo("bar2");
+ assertThat(batchSettings.getString("sonar.foo.secured")).isEqualTo("bar");
+ }
+
+ @Test
+ public void should_fail_when_accessing_secured_properties_in_dryrun() {
+ when(client.request("/batch_bootstrap/properties?dryRun=true")).thenReturn(JSON_RESPONSE_WITH_SECURED);
+ when(client.request("/batch_bootstrap/properties?project=struts&dryRun=true")).thenReturn(REACTOR_JSON_RESPONSE);
+
+ bootstrapSettings.properties().put(CoreProperties.DRY_RUN, "true");
+
+ BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf);
+ batchSettings.init(new ProjectReactor(project));
+
+ assertThat(batchSettings.getString("sonar.foo.license.secured")).isEqualTo("bar2");
+ thrown.expect(SonarException.class);
+ thrown
+ .expectMessage("Access to the secured property 'sonar.foo.secured' is not possible in local (dry run) SonarQube analysis. The SonarQube plugin accessing to this property must be deactivated in dry run mode.");
+ batchSettings.getString("sonar.foo.secured");
+ }
+
@Test
public void should_keep_module_settings_for_later() {
- when(client.request("/batch_bootstrap/properties")).thenReturn(JSON_RESPONSE);
- when(client.request("/batch_bootstrap/properties?project=struts")).thenReturn(REACTOR_JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?dryRun=false")).thenReturn(JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?project=struts&dryRun=false")).thenReturn(REACTOR_JSON_RESPONSE);
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf);
batchSettings.init(new ProjectReactor(project));
@Test
public void system_props_should_override_build_props() {
- when(client.request("/batch_bootstrap/properties")).thenReturn(JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?dryRun=false")).thenReturn(JSON_RESPONSE);
System.setProperty("BatchSettingsTest.testSystemProp", "system");
project.setProperty("BatchSettingsTest.testSystemProp", "build");
@Test
public void should_forward_to_deprecated_commons_configuration() {
- when(client.request("/batch_bootstrap/properties")).thenReturn(JSON_RESPONSE);
- when(client.request("/batch_bootstrap/properties?project=struts")).thenReturn(REACTOR_JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?dryRun=false")).thenReturn(JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?project=struts&dryRun=false")).thenReturn(REACTOR_JSON_RESPONSE);
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf);
batchSettings.init(new ProjectReactor(project));
@Test
public void project_should_be_optional() {
- when(client.request("/batch_bootstrap/properties")).thenReturn(JSON_RESPONSE);
+ when(client.request("/batch_bootstrap/properties?dryRun=false")).thenReturn(JSON_RESPONSE);
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf);
assertThat(batchSettings.getProperties()).isNotEmpty();
}
import com.google.common.collect.ImmutableMap;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.utils.SonarException;
import org.sonar.batch.bootstrap.BatchSettings;
import java.util.List;
public class ModuleSettingsTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
@Test
public void testOrderedProjects() {
ProjectDefinition grandParent = ProjectDefinition.create();
BatchSettings batchSettings = mock(BatchSettings.class);
when(batchSettings.getDefinitions()).thenReturn(new PropertyDefinitions());
when(batchSettings.getProperties()).thenReturn(ImmutableMap.of(
- "overridding", "batch",
- "on-batch", "true"
- ));
+ "overridding", "batch",
+ "on-batch", "true"
+ ));
when(batchSettings.getModuleProperties("struts-core")).thenReturn(ImmutableMap.of(
- "on-module", "true",
- "overridding", "module"
- ));
+ "on-module", "true",
+ "overridding", "module"
+ ));
ProjectDefinition module = ProjectDefinition.create().setKey("struts-core");
Configuration deprecatedConf = new PropertiesConfiguration();
assertThat(deprecatedConf.getString("on-batch")).isEqualTo("true");
assertThat(deprecatedConf.getString("on-module")).isEqualTo("true");
}
+
+ @Test
+ public void should_not_fail_when_accessing_secured_properties() {
+ BatchSettings batchSettings = mock(BatchSettings.class);
+ when(batchSettings.getDefinitions()).thenReturn(new PropertyDefinitions());
+ when(batchSettings.getProperties()).thenReturn(ImmutableMap.of(
+ "sonar.foo.secured", "bar"
+ ));
+ when(batchSettings.getModuleProperties("struts-core")).thenReturn(ImmutableMap.of(
+ "sonar.foo.license.secured", "bar2"
+ ));
+
+ ProjectDefinition module = ProjectDefinition.create().setKey("struts-core");
+ Configuration deprecatedConf = new PropertiesConfiguration();
+
+ ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, deprecatedConf);
+
+ assertThat(moduleSettings.getString("sonar.foo.license.secured")).isEqualTo("bar2");
+ assertThat(moduleSettings.getString("sonar.foo.secured")).isEqualTo("bar");
+ }
+
+ @Test
+ public void should_fail_when_accessing_secured_properties_in_dryrun() {
+ BatchSettings batchSettings = mock(BatchSettings.class);
+ when(batchSettings.getDefinitions()).thenReturn(new PropertyDefinitions());
+ when(batchSettings.getString(CoreProperties.DRY_RUN)).thenReturn("true");
+ when(batchSettings.getProperties()).thenReturn(ImmutableMap.of(
+ "sonar.foo.secured", "bar"
+ ));
+ when(batchSettings.getModuleProperties("struts-core")).thenReturn(ImmutableMap.of(
+ "sonar.foo.license.secured", "bar2"
+ ));
+
+ ProjectDefinition module = ProjectDefinition.create().setKey("struts-core");
+ Configuration deprecatedConf = new PropertiesConfiguration();
+
+ ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, deprecatedConf);
+
+ assertThat(moduleSettings.getString("sonar.foo.license.secured")).isEqualTo("bar2");
+
+ thrown.expect(SonarException.class);
+ thrown
+ .expectMessage("Access to the secured property 'sonar.foo.secured' is not possible in local (dry run) SonarQube analysis. The SonarQube plugin accessing to this property must be deactivated in dry run mode.");
+ moduleSettings.getString("sonar.foo.secured");
+ }
}
*/
public class DatabaseVersion implements BatchComponent, ServerComponent {
- public static final int LAST_VERSION = 413;
+ public static final int LAST_VERSION = 414;
public static enum Status {
UP_TO_DATE, REQUIRES_UPGRADE, REQUIRES_DOWNGRADE, FRESH_INSTALL
INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (1, 1, null, 'admin');
INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (2, 1, null, 'profileadmin');
INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (3, 1, null, 'sharedashboard');
-ALTER TABLE GROUP_ROLES ALTER COLUMN ID RESTART WITH 4;
+INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (4, 1, null, 'scan');
+INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (5, null, null, 'scan');
+INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (6, 1, null, 'dryrun');
+INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (7, 2, null, 'dryrun');
+INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (8, null, null, 'dryrun');
+ALTER TABLE GROUP_ROLES ALTER COLUMN ID RESTART WITH 9;
INSERT INTO GROUPS_USERS(USER_ID, GROUP_ID) VALUES (1, 1);
INSERT INTO GROUPS_USERS(USER_ID, GROUP_ID) VALUES (1, 2);
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('411');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('412');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('413');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('414');
INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '2011-09-26 22:27:48.0', '2011-09-26 22:27:48.0', null, null);
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
* Does not decrypt value.
*/
protected String getClearString(String key) {
+ doOnGetProperties(key);
String validKey = definitions.validKey(key);
String value = properties.get(validKey);
if (value == null) {
protected void doOnClearProperties() {
}
+
+ protected void doOnGetProperties(String key) {
+ }
}
import com.google.common.io.InputSupplier;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
import org.sonar.api.ServerComponent;
@Override
String[] getSupportedSchemes() {
- return new String[]{"http", "https"};
+ return new String[] {"http", "https"};
}
@Override
public static class BaseHttpDownloader {
private static final List<String> PROXY_SETTINGS = ImmutableList.of(
- "http.proxyHost", "http.proxyPort", "http.nonProxyHosts",
- "http.auth.ntlm.domain", "socksProxyHost", "socksProxyPort");
+ "http.proxyHost", "http.proxyPort", "http.nonProxyHosts",
+ "http.auth.ntlm.domain", "socksProxyHost", "socksProxyPort");
private String userAgent;
private void registerProxyCredentials(Map<String, String> settings) {
Authenticator.setDefault(new ProxyAuthenticator(
- settings.get("http.proxyUser"),
- settings.get("http.proxyPassword")));
+ settings.get("http.proxyUser"),
+ settings.get("http.proxyPassword")));
}
private boolean requiresProxyAuthentication(Map<String, String> settings) {
int responseCode = connection.getResponseCode();
if (responseCode >= 400) {
- throw new HttpException(uri, responseCode);
+ InputStream errorResponse = null;
+ try {
+ errorResponse = connection.getErrorStream();
+ if (errorResponse != null) {
+ String errorResponseContent = IOUtils.toString(errorResponse);
+ throw new HttpException(uri, responseCode, errorResponseContent);
+ }
+ else {
+ throw new HttpException(uri, responseCode);
+ }
+ } finally {
+ IOUtils.closeQuietly(errorResponse);
+ }
}
return connection.getInputStream();
public static class HttpException extends RuntimeException {
private final URI uri;
private final int responseCode;
+ private final String responseContent;
- public HttpException(URI uri, int responseCode) {
+ public HttpException(URI uri, int responseContent) {
+ this(uri, responseContent, null);
+ }
+
+ public HttpException(URI uri, int responseCode, String responseContent) {
super("Fail to download [" + uri + "]. Response code: " + responseCode);
this.uri = uri;
this.responseCode = responseCode;
+ this.responseContent = responseContent;
}
public int getResponseCode() {
public URI getUri() {
return uri;
}
+
+ public String getResponseContent() {
+ return responseContent;
+ }
}
}
# GET /batch_bootstrap/db?project=<key or id>
def db
+ has_dryrun_role = has_role?(:dryrun)
+ return render_unauthorized("You're not authorized to execute a dry run analysis. Please contact your Sonar administrator.") if !has_dryrun_role
project = load_project()
+ return render_unauthorized("You're not authorized to access to project '" + project.name + "', please contact your Sonar administrator") if project && !has_role?(:user, project)
db_content = java_facade.createDatabaseForDryRun(project ? project.id : nil)
send_data String.from_java_bytes(db_content)
end
-
- # GET /batch_bootstrap/properties?[project=<key or id>]
+
+ # GET /batch_bootstrap/properties?[project=<key or id>][&dryRun=true|false]
def properties
+ dryRun = params[:dryRun].present? && params[:dryRun] == "true"
+ has_dryrun_role = has_role?(:dryrun)
+ has_scan_role = has_role?(:scan)
+
+ return render_unauthorized("You're not authorized to execute any SonarQube analysis. Please contact your SonarQube administrator.") if (!has_dryrun_role && !has_scan_role)
+ return render_unauthorized("You're only authorized to execute a local (dry run) SonarQube analysis without pushing the results to the SonarQube server. Please contact your SonarQube administrator.") if (!dryRun && !has_scan_role)
+
keys=Set.new
properties=[]
# project properties
root_project = load_project()
+ return render_unauthorized("You're not authorized to access to project '" + root_project.name + "', please contact your Sonar administrator") if root_project && !has_role?(:scan) && !has_role?(:user, root_project)
+
if root_project
# bottom-up projects
projects=[root_project].concat(root_project.ancestor_projects)
# apply security
has_user_role=has_role?(:user, root_project)
has_admin_role=has_role?(:admin, root_project)
- properties = properties.select{|prop| allowed?(prop.key, has_user_role, has_admin_role)}
+ properties = properties.select{|prop| allowed?(prop.key, dryRun, has_scan_role)}
json_properties=properties.map { |property| to_json_property(property) }
end
private
+
+ def render_unauthorized(message, status=403)
+ respond_to do |format|
+ format.json { render :text => message, :status => status }
+ format.xml { render :text => message, :status => status }
+ format.text { render :text => message, :status => status }
+ end
+ end
def load_project
if params[:project].present?
- project = Project.by_key(params[:project])
- return access_denied if project && !has_role?(:user, project)
- project
+ Project.by_key(params[:project])
else
nil
end
hash
end
- def allowed?(property_key, has_user_role, has_admin_role)
+ def allowed?(property_key, dryRun, has_scan_role)
if property_key.end_with?('.secured')
- property_key.include?('.license') ? has_user_role : has_admin_role
+ property_key.include?('.license') ? true : (!dryRun && has_scan_role)
else
true
end
</tr>
</thead>
<tbody>
- <% ['admin', 'profileadmin', 'sharedashboard'].each do |globalRole| %>
+ <% ['admin', 'profileadmin', 'sharedashboard', 'scan', 'dryrun'].each do |globalRole| %>
<tr class="<%= cycle('even', 'odd', :name => 'globalRole') -%>" >
<td valign="top">
<b><%= message('global_role.' + globalRole) -%></b><br/>
--- /dev/null
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2013 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.
+#
+
+#
+# Sonar 3.7
+# SONAR-4397
+#
+
+class AddScanAndDryrunPermissions < ActiveRecord::Migration
+
+ def self.up
+ # -- Role scan --
+ group_roles=GroupRole.find(:all, :conditions => {:role => 'admin', :resource_id => nil})
+ groups = group_roles.map { |ur| ur.group_id }
+ # Anyone
+ unless groups.include?(nil)
+ groups << nil
+ end
+ groups.each do |group_id|
+ GroupRole.create(:group_id => group_id, :role => 'scan', :resource_id => nil)
+ end
+
+ user_roles=UserRole.find(:all, :conditions => {:role => 'admin', :resource_id => nil})
+ users = user_roles.map { |ur| ur.user_id }
+ users.each do |user_id|
+ UserRole.create(:user_id => user_id, :role=> 'scan', :resource_id => nil)
+ end
+
+ # -- Role dryrun --
+ group_roles=GroupRole.find(:all, :conditions => {:role => 'admin', :resource_id => nil})
+ groups = group_roles.map { |ur| ur.group_id }
+ # Anyone
+ unless groups.include?(nil)
+ groups << nil
+ end
+ # sonar-users
+ userGroupName = Property.by_key('sonar.defaultGroup')
+ userGroupName = 'sonar-users' if userGroupName.nil?
+ userGroup = Group.find(:all, :conditions => {:name => userGroupName}).first
+ unless userGroup.nil? || groups.include?(userGroup.id)
+ groups << userGroup.id
+ end
+
+ groups.each do |group_id|
+ GroupRole.create(:group_id => group_id, :role => 'dryrun', :resource_id => nil)
+ end
+
+ user_roles=UserRole.find(:all, :conditions => {:role => 'admin', :resource_id => nil})
+ users = user_roles.map { |ur| ur.user_id }
+ users.each do |user_id|
+ UserRole.create(:user_id => user_id, :role=> 'dryrun', :resource_id => nil)
+ end
+
+ end
+
+end
def has_role?(role, objects=nil)
if objects.nil?
role_symbol=role.to_sym
- if role_symbol==:admin || role_symbol==:profileadmin || role_symbol==:sharedashboard
+ if role_symbol==:admin || role_symbol==:profileadmin || role_symbol==:sharedashboard || role_symbol==:scan || role_symbol==:dryrun
AuthorizerFactory.authorizer.has_role?(self, role_symbol)
else
# There's no concept of global users or global codeviewers.