]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6612 ws custom_measures/metrics requires 'Administer System' permission or...
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Fri, 26 Jun 2015 12:46:12 +0000 (14:46 +0200)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Fri, 26 Jun 2015 12:47:29 +0000 (14:47 +0200)
server/sonar-server/src/main/java/org/sonar/server/measure/custom/ws/MetricsAction.java
server/sonar-server/src/test/java/org/sonar/server/measure/custom/ws/MetricsActionTest.java

index 791dc5e1a04f13538a89fd0df1110127594188a0..858020602da5a92ac8389f31424f237e4702864e 100644 (file)
@@ -26,11 +26,16 @@ import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
 import org.sonar.core.metric.db.MetricDto;
+import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.metric.ws.MetricJsonWriter;
+import org.sonar.server.user.UserSession;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
@@ -40,9 +45,11 @@ public class MetricsAction implements CustomMeasuresWsAction {
   public static final String PARAM_PROJECT_KEY = "projectKey";
 
   private final DbClient dbClient;
+  private final UserSession userSession;
 
-  public MetricsAction(DbClient dbClient) {
+  public MetricsAction(DbClient dbClient, UserSession userSession) {
     this.dbClient = dbClient;
+    this.userSession = userSession;
   }
 
   @Override
@@ -53,7 +60,8 @@ public class MetricsAction implements CustomMeasuresWsAction {
       .setHandler(this)
       .setResponseExample(Resources.getResource(getClass(), "example-metrics.json"))
       .setDescription("List all custom metrics for which no custom measure already exists on a given project.<br /> " +
-        "The project id or project key must be provided.");
+        "The project id or project key must be provided.<br />" +
+        "Requires 'Administer System' permission or 'Administer' permission on the project.");
 
     action.createParam(PARAM_PROJECT_ID)
       .setDescription("Project id")
@@ -67,32 +75,56 @@ public class MetricsAction implements CustomMeasuresWsAction {
   @Override
   public void handle(Request request, Response response) throws Exception {
     DbSession dbSession = dbClient.openSession(false);
+
     try {
-      List<MetricDto> metrics = searchMetrics(dbSession, request);
+      ComponentDto project = searchProject(dbSession, request);
+      checkPermissions(project);
+      List<MetricDto> metrics = searchMetrics(dbSession, project);
 
-      JsonWriter json = response.newJsonWriter();
-      json.beginObject();
-      MetricJsonWriter.write(json, metrics, MetricJsonWriter.ALL_FIELDS);
-      json.endObject();
-      json.close();
+      writeResponse(response.newJsonWriter(), metrics);
     } finally {
       MyBatis.closeQuietly(dbSession);
     }
   }
 
-  private List<MetricDto> searchMetrics(DbSession dbSession, Request request) {
-    String projectUuidParam = request.param(PARAM_PROJECT_ID);
-    String projectKeyParam = request.param(PARAM_PROJECT_KEY);
-    String projectUuid;
+  private void writeResponse(JsonWriter json, List<MetricDto> metrics) {
+    json.beginObject();
+    MetricJsonWriter.write(json, metrics, MetricJsonWriter.ALL_FIELDS);
+    json.endObject();
+    json.close();
+  }
+
+  private List<MetricDto> searchMetrics(DbSession dbSession, ComponentDto project) {
+    return dbClient.metricDao().selectAvailableCustomMetricsByComponentUuid(dbSession, project.uuid());
+  }
+
+  private ComponentDto searchProject(DbSession dbSession, Request request) {
+    String projectUuid = request.param(PARAM_PROJECT_ID);
+    String projectKey = request.param(PARAM_PROJECT_KEY);
+    checkArgument(projectUuid != null ^ projectKey != null, "The project key or the project id must be provided, not both.");
+
+    if (projectUuid != null) {
+      ComponentDto project = dbClient.componentDao().selectNullableByUuid(dbSession, projectUuid);
+      if (project == null) {
+        throw new NotFoundException(String.format("Project id '%s' not found", projectUuid));
+      }
 
-    checkArgument(projectUuidParam != null ^ projectKeyParam != null, "The project uuid or the project key must be provided, not both.");
+      return project;
+    }
+
+    ComponentDto project = dbClient.componentDao().selectNullableByKey(dbSession, projectKey);
+    if (project == null) {
+      throw new NotFoundException(String.format("Project key '%s' not found", projectKey));
+    }
+
+    return project;
+  }
 
-    if (projectUuidParam == null) {
-      projectUuid = dbClient.componentDao().selectByKey(dbSession, projectKeyParam).uuid();
-    } else {
-      projectUuid = projectUuidParam;
+  private void checkPermissions(ComponentDto component) {
+    if (userSession.hasGlobalPermission(GlobalPermissions.SYSTEM_ADMIN)) {
+      return;
     }
 
-    return dbClient.metricDao().selectAvailableCustomMetricsByComponentUuid(dbSession, projectUuid);
+    userSession.checkLoggedIn().checkProjectUuidPermission(UserRole.ADMIN, component.projectUuid());
   }
 }
index 5dfafb50df04819f93862001359faf916199b0ec..e48f2d7614209078b465fa5a4b91fa5a8737497d 100644 (file)
@@ -30,17 +30,21 @@ import org.junit.experimental.categories.Category;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.config.Settings;
 import org.sonar.api.measures.Metric;
+import org.sonar.api.web.UserRole;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.measure.custom.db.CustomMeasureDto;
 import org.sonar.core.metric.db.MetricDto;
+import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.DbTester;
 import org.sonar.server.component.ComponentTesting;
 import org.sonar.server.component.db.ComponentDao;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.es.EsTester;
+import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.measure.custom.persistence.CustomMeasureDao;
 import org.sonar.server.metric.persistence.MetricDao;
+import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.user.index.UserDoc;
 import org.sonar.server.user.index.UserIndexDefinition;
 import org.sonar.server.ws.WsTester;
@@ -59,6 +63,8 @@ public class MetricsActionTest {
 
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
   @ClassRule
   public static EsTester es = new EsTester().addDefinitions(new UserIndexDefinition(new Settings()));
   @ClassRule
@@ -66,6 +72,7 @@ public class MetricsActionTest {
   DbClient dbClient;
   DbSession dbSession;
   WsTester ws;
+  ComponentDto defaultProject;
 
   @BeforeClass
   public static void setUpClass() throws Exception {
@@ -81,7 +88,9 @@ public class MetricsActionTest {
     dbClient = new DbClient(db.database(), db.myBatis(), new MetricDao(), new ComponentDao(), new CustomMeasureDao());
     dbSession = dbClient.openSession(false);
     db.truncateTables();
-    ws = new WsTester(new CustomMeasuresWs(new MetricsAction(dbClient)));
+    ws = new WsTester(new CustomMeasuresWs(new MetricsAction(dbClient, userSession)));
+    userSession.login("login").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+    defaultProject = insertDefaultProject();
   }
 
   @After
@@ -118,11 +127,10 @@ public class MetricsActionTest {
   public void list_metrics_where_no_existing_custom_measure() throws Exception {
     MetricDto metric = insertCustomMetric("metric-key-1");
     insertCustomMetric("metric-key-2");
-    ComponentDto project = insertDefaultProject();
     insertProject("project-uuid-2", "project-key-2");
 
     CustomMeasureDto customMeasure = newCustomMeasureDto()
-      .setComponentUuid(project.uuid())
+      .setComponentUuid(defaultProject.uuid())
       .setMetricId(metric.getId());
     dbClient.customMeasureDao().insert(dbSession, customMeasure);
     dbSession.commit();
@@ -137,11 +145,10 @@ public class MetricsActionTest {
   public void list_metrics_based_on_project_key() throws Exception {
     MetricDto metric = insertCustomMetric("metric-key-1");
     insertCustomMetric("metric-key-2");
-    ComponentDto project = insertDefaultProject();
     insertProject("project-uuid-2", "project-key-2");
 
     CustomMeasureDto customMeasure = newCustomMeasureDto()
-      .setComponentUuid(project.uuid())
+      .setComponentUuid(defaultProject.uuid())
       .setMetricId(metric.getId());
     dbClient.customMeasureDao().insert(dbSession, customMeasure);
     dbSession.commit();
@@ -154,6 +161,16 @@ public class MetricsActionTest {
       .doesNotContain("metric-key-1");
   }
 
+  @Test
+  public void list_metrics_as_a_project_admin() throws Exception {
+    insertCustomMetric("metric-key-1");
+    userSession.login("login").addProjectUuidPermissions(UserRole.ADMIN, defaultProject.uuid());
+
+    String response = newRequest().outputAsString();
+
+    assertThat(response).contains("metric-key-1");
+  }
+
   @Test
   public void response_with_correct_formatting() throws Exception {
     dbClient.metricDao().insert(dbSession, newCustomMetric("custom-key-1")
@@ -196,6 +213,16 @@ public class MetricsActionTest {
     ws.newGetRequest(ENDPOINT, ACTION).execute();
   }
 
+  @Test
+  public void fail_if_insufficient_privilege() throws Exception {
+    expectedException.expect(ForbiddenException.class);
+    userSession.login("login");
+
+    insertCustomMetric("metric-key-1");
+
+    newRequest();
+  }
+
   private WsTester.Result newRequest() throws Exception {
     return ws.newGetRequest(ENDPOINT, ACTION)
       .setParam(MetricsAction.PARAM_PROJECT_ID, DEFAULT_PROJECT_UUID)