From bd62851006245673ec2f1ba5b46a5d3e3bc7d7e9 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Fri, 8 Jan 2016 16:47:30 +0100 Subject: [PATCH] SONAR-7174 Check scan permission per project in /api/ce/task WS --- .../server/computation/ws/TaskAction.java | 21 +++- .../server/computation/ws/TaskActionTest.java | 112 ++++++++++++++---- 2 files changed, 104 insertions(+), 29 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskAction.java index d7b8987c5f1..d3d76149dd5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskAction.java @@ -20,12 +20,10 @@ package org.sonar.server.computation.ws; import com.google.common.base.Optional; -import com.google.common.collect.ImmutableSet; -import java.util.Set; +import javax.annotation.Nullable; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; -import org.sonar.core.permission.GlobalPermissions; import org.sonar.core.util.Uuids; import org.sonar.db.DbClient; import org.sonar.db.DbSession; @@ -35,13 +33,15 @@ import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.user.UserSession; import org.sonarqube.ws.WsCe; +import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION; +import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN; +import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException; import static org.sonar.server.ws.WsUtils.writeProtobuf; public class TaskAction implements CeWsAction { public static final String ACTION = "task"; public static final String PARAM_TASK_UUID = "id"; - private static final Set AUTHORIZED_PERMISSIONS = ImmutableSet.of(GlobalPermissions.SCAN_EXECUTION, GlobalPermissions.SYSTEM_ADMIN); private final DbClient dbClient; private final TaskFormatter wsTaskFormatter; @@ -71,18 +71,18 @@ public class TaskAction implements CeWsAction { @Override public void handle(Request wsRequest, Response wsResponse) throws Exception { - userSession.checkAnyPermissions(AUTHORIZED_PERMISSIONS); - String taskUuid = wsRequest.mandatoryParam(PARAM_TASK_UUID); DbSession dbSession = dbClient.openSession(false); try { WsCe.TaskResponse.Builder wsTaskResponse = WsCe.TaskResponse.newBuilder(); Optional queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, taskUuid); if (queueDto.isPresent()) { + checkPermission(queueDto.get().getComponentUuid()); wsTaskResponse.setTask(wsTaskFormatter.formatQueue(dbSession, queueDto.get())); } else { Optional activityDto = dbClient.ceActivityDao().selectByUuid(dbSession, taskUuid); if (activityDto.isPresent()) { + checkPermission(activityDto.get().getComponentUuid()); wsTaskResponse.setTask(wsTaskFormatter.formatActivity(dbSession, activityDto.get())); } else { throw new NotFoundException(); @@ -94,4 +94,13 @@ public class TaskAction implements CeWsAction { dbClient.closeSession(dbSession); } } + + private void checkPermission(@Nullable String projectUuid) { + if (!userSession.hasPermission(SYSTEM_ADMIN) + && !userSession.hasPermission(SCAN_EXECUTION) + && (projectUuid == null || !userSession.hasComponentUuidPermission(SCAN_EXECUTION, projectUuid)) + ) { + throw insufficientPrivilegesException(); + } + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskActionTest.java index 3f8c274627a..2dd1083029a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskActionTest.java @@ -26,7 +26,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.utils.System2; -import org.sonar.core.permission.GlobalPermissions; import org.sonar.core.util.Protobuf; import org.sonar.db.DbTester; import org.sonar.db.ce.CeActivityDto; @@ -48,13 +47,23 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.sonar.test.JsonAssert.assertJson; +import static org.sonar.core.permission.GlobalPermissions.PREVIEW_EXECUTION; +import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION; +import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN; public class TaskActionTest { + + static final ComponentDto PROJECT = ComponentTesting.newProjectDto() + .setUuid("PROJECT_1") + .setName("Project One") + .setKey("P1"); + @Rule public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule public ExpectedException expectedException = ExpectedException.none(); + @Rule public DbTester dbTester = DbTester.create(System2.INSTANCE); @@ -65,19 +74,18 @@ public class TaskActionTest { @Before public void setUp() { + dbTester.getDbClient().componentDao().insert(dbTester.getSession(), PROJECT); when(ceLogging.getFile(any(LogFileRef.class))).thenReturn(Optional.absent()); - userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); } @Test public void task_is_in_queue() throws Exception { - ComponentDto project = ComponentTesting.newProjectDto().setUuid("PROJECT_1").setName("Project One").setKey("P1"); - dbTester.getDbClient().componentDao().insert(dbTester.getSession(), project); + userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN); CeQueueDto queueDto = new CeQueueDto(); queueDto.setTaskType(CeTaskTypes.REPORT); queueDto.setUuid("TASK_1"); - queueDto.setComponentUuid(project.uuid()); + queueDto.setComponentUuid(PROJECT.uuid()); queueDto.setStatus(CeQueueDto.Status.PENDING); queueDto.setSubmitterLogin("john"); dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto); @@ -92,22 +100,21 @@ public class TaskActionTest { assertThat(taskResponse.getTask().getId()).isEqualTo("TASK_1"); assertThat(taskResponse.getTask().getStatus()).isEqualTo(WsCe.TaskStatus.PENDING); assertThat(taskResponse.getTask().getSubmitterLogin()).isEqualTo("john"); - assertThat(taskResponse.getTask().getComponentId()).isEqualTo(project.uuid()); - assertThat(taskResponse.getTask().getComponentKey()).isEqualTo(project.key()); - assertThat(taskResponse.getTask().getComponentName()).isEqualTo(project.name()); + assertThat(taskResponse.getTask().getComponentId()).isEqualTo(PROJECT.uuid()); + assertThat(taskResponse.getTask().getComponentKey()).isEqualTo(PROJECT.key()); + assertThat(taskResponse.getTask().getComponentName()).isEqualTo(PROJECT.name()); assertThat(taskResponse.getTask().hasExecutionTimeMs()).isFalse(); assertThat(taskResponse.getTask().getLogs()).isFalse(); } @Test public void task_is_archived() throws Exception { - ComponentDto project = ComponentTesting.newProjectDto().setUuid("PROJECT_1").setName("Project One").setKey("P1"); - dbTester.getDbClient().componentDao().insert(dbTester.getSession(), project); + userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN); CeQueueDto queueDto = new CeQueueDto(); queueDto.setTaskType(CeTaskTypes.REPORT); queueDto.setUuid("TASK_1"); - queueDto.setComponentUuid(project.uuid()); + queueDto.setComponentUuid(PROJECT.uuid()); CeActivityDto activityDto = new CeActivityDto(queueDto); activityDto.setStatus(CeActivityDto.Status.FAILED); activityDto.setExecutionTimeMs(500L); @@ -124,9 +131,9 @@ public class TaskActionTest { WsCe.Task task = taskResponse.getTask(); assertThat(task.getId()).isEqualTo("TASK_1"); assertThat(task.getStatus()).isEqualTo(WsCe.TaskStatus.FAILED); - assertThat(task.getComponentId()).isEqualTo(project.uuid()); - assertThat(task.getComponentKey()).isEqualTo(project.key()); - assertThat(task.getComponentName()).isEqualTo(project.name()); + assertThat(task.getComponentId()).isEqualTo(PROJECT.uuid()); + assertThat(task.getComponentKey()).isEqualTo(PROJECT.key()); + assertThat(task.getComponentName()).isEqualTo(PROJECT.name()); assertThat(task.getAnalysisId()).isEqualTo("123456"); assertThat(task.getExecutionTimeMs()).isEqualTo(500L); assertThat(task.getLogs()).isFalse(); @@ -134,17 +141,52 @@ public class TaskActionTest { @Test public void task_not_found() throws Exception { - expectedException.expect(NotFoundException.class); + userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN); + expectedException.expect(NotFoundException.class); ws.newRequest() .setParam("id", "DOES_NOT_EXIST") .execute(); } @Test - public void fail_if_not_admin_nor_scan_permission() { - expectedException.expect(ForbiddenException.class); - userSession.setGlobalPermissions(GlobalPermissions.PREVIEW_EXECUTION); + public void not_fail_on_queue_task_not_linked_on_project_with_system_admin_permissions() { + userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN); + + CeQueueDto queueDto = new CeQueueDto(); + queueDto.setTaskType("fake"); + queueDto.setUuid("TASK_1"); + queueDto.setStatus(CeQueueDto.Status.PENDING); + dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto); + dbTester.commit(); + + ws.newRequest() + .setMediaType(MediaTypes.JSON) + .setParam("id", "TASK_1") + .execute(); + } + + @Test + public void not_fail_on_queue_task_not_linked_on_project_with_global_scan_permissions() { + userSession.login("john").setGlobalPermissions(SCAN_EXECUTION); + + CeQueueDto queueDto = new CeQueueDto(); + queueDto.setTaskType("fake"); + queueDto.setUuid("TASK_1"); + queueDto.setStatus(CeQueueDto.Status.PENDING); + dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto); + dbTester.commit(); + + ws.newRequest() + .setMediaType(MediaTypes.JSON) + .setParam("id", "TASK_1") + .execute(); + } + + @Test + public void fail_on_queue_task_not_linked_on_project_if_not_admin_nor_scan_permission() { + userSession.login("john").setGlobalPermissions(PREVIEW_EXECUTION); + CeQueueDto queueDto = new CeQueueDto(); queueDto.setTaskType("fake"); queueDto.setUuid("TASK_1"); @@ -152,6 +194,7 @@ public class TaskActionTest { dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto); dbTester.commit(); + expectedException.expect(ForbiddenException.class); ws.newRequest() .setMediaType(MediaTypes.PROTOBUF) .setParam("id", "TASK_1") @@ -159,20 +202,43 @@ public class TaskActionTest { } @Test - public void support_json_response_with_scan_permissions() { - userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); + public void not_fail_on_queue_task_linked_on_project_with_project_scan_permission() { + userSession.login("john").addProjectUuidPermissions(SCAN_EXECUTION, PROJECT.uuid()); + CeQueueDto queueDto = new CeQueueDto(); queueDto.setTaskType("fake"); queueDto.setUuid("TASK_1"); queueDto.setStatus(CeQueueDto.Status.PENDING); + queueDto.setComponentUuid(PROJECT.uuid()); dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto); dbTester.commit(); - TestResponse wsResponse = ws.newRequest() + ws.newRequest() .setMediaType(MediaTypes.JSON) .setParam("id", "TASK_1") .execute(); + } + + @Test + public void not_fail_on_archived_task_linked_on_project_with_project_scan_permission() throws Exception { + userSession.login("john").addProjectUuidPermissions(SCAN_EXECUTION, PROJECT.uuid()); - assertJson(wsResponse.getInput()).isSimilarTo("{\"task\":{}}"); + CeQueueDto queueDto = new CeQueueDto(); + queueDto.setTaskType(CeTaskTypes.REPORT); + queueDto.setUuid("TASK_1"); + queueDto.setComponentUuid(PROJECT.uuid()); + CeActivityDto activityDto = new CeActivityDto(queueDto); + activityDto.setStatus(CeActivityDto.Status.FAILED); + activityDto.setExecutionTimeMs(500L); + activityDto.setSnapshotId(123_456L); + activityDto.setComponentUuid(PROJECT.uuid()); + dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto); + dbTester.commit(); + + ws.newRequest() + .setMediaType(MediaTypes.PROTOBUF) + .setParam("id", "TASK_1") + .execute(); } + } -- 2.39.5