aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorPierre <pierre.guillot@sonarsource.com>2021-11-17 16:11:26 +0100
committersonartech <sonartech@sonarsource.com>2021-11-18 20:03:32 +0000
commit8ec44b87f3f3bd2450009775abd65d2a75c4e791 (patch)
tree3c2bc1a9a22544e763755b202fefdab08931439c /server
parentf0adb953f003e974de835114c9e5c4391719cd2c (diff)
downloadsonarqube-8ec44b87f3f3bd2450009775abd65d2a75c4e791.tar.gz
sonarqube-8ec44b87f3f3bd2450009775abd65d2a75c4e791.zip
SONAR-13426 Validate token for public project when auth is forced
Diffstat (limited to 'server')
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java1
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/badge/ws/ProjectBadgesSupport.java12
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/badge/ws/MeasureActionTest.java70
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/badge/ws/QualityGateActionTest.java75
4 files changed, 147 insertions, 11 deletions
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java
index 5582633876a..fd82dca2318 100644
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java
+++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java
@@ -19,7 +19,6 @@
*/
package org.sonar.server.authentication;
-import com.google.common.collect.ImmutableSet;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/badge/ws/ProjectBadgesSupport.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/badge/ws/ProjectBadgesSupport.java
index 405cdef4dca..b803c2ab4a0 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/badge/ws/ProjectBadgesSupport.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/badge/ws/ProjectBadgesSupport.java
@@ -20,6 +20,7 @@
package org.sonar.server.badge.ws;
import javax.annotation.Nullable;
+import org.sonar.api.config.Configuration;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbClient;
@@ -30,6 +31,8 @@ import org.sonar.db.project.ProjectDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.NotFoundException;
+import static org.sonar.api.CoreProperties.CORE_FORCE_AUTHENTICATION_DEFAULT_VALUE;
+import static org.sonar.api.CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY;
import static org.sonar.db.component.BranchType.BRANCH;
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
@@ -44,10 +47,12 @@ public class ProjectBadgesSupport {
private final ComponentFinder componentFinder;
private final DbClient dbClient;
+ private final Configuration config;
- public ProjectBadgesSupport(ComponentFinder componentFinder, DbClient dbClient) {
+ public ProjectBadgesSupport(ComponentFinder componentFinder, DbClient dbClient, Configuration config) {
this.componentFinder = componentFinder;
this.dbClient = dbClient;
+ this.config = config;
}
void addProjectAndBranchParams(WebService.NewAction action) {
@@ -101,8 +106,9 @@ public class ProjectBadgesSupport {
} catch (NotFoundException e) {
throw new NotFoundException(PROJECT_HAS_NOT_BEEN_FOUND);
}
- String token = request.param(PARAM_TOKEN);
- if (projectDto.isPrivate() && !isTokenValid(dbSession, projectDto, token)) {
+ boolean tokenInvalid = !isTokenValid(dbSession, projectDto, request.param(PARAM_TOKEN));
+ boolean forceAuthEnabled = config.getBoolean(CORE_FORCE_AUTHENTICATION_PROPERTY).orElse(CORE_FORCE_AUTHENTICATION_DEFAULT_VALUE);
+ if ((projectDto.isPrivate() || forceAuthEnabled) && tokenInvalid) {
throw new NotFoundException(PROJECT_HAS_NOT_BEEN_FOUND);
}
}
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/badge/ws/MeasureActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/badge/ws/MeasureActionTest.java
index e319a912e71..c94cc4258cc 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/badge/ws/MeasureActionTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/badge/ws/MeasureActionTest.java
@@ -26,20 +26,25 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Configuration;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric.Level;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.DbTester;
import org.sonar.db.component.BranchType;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.metric.MetricDto;
+import org.sonar.db.project.ProjectDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.badge.ws.SvgGenerator.Color;
import org.sonar.server.component.ComponentFinder;
@@ -79,14 +84,20 @@ public class MeasureActionTest {
@Rule
public DbTester db = DbTester.create();
- private MapSettings mapSettings = new MapSettings().setProperty("sonar.sonarcloud.enabled", false);
+ private final MapSettings mapSettings = new MapSettings().setProperty("sonar.sonarcloud.enabled", false);
+ private final Configuration config = mapSettings.asConfig();
- private WsActionTester ws = new WsActionTester(
+ private final WsActionTester ws = new WsActionTester(
new MeasureAction(
db.getDbClient(),
- new ProjectBadgesSupport(new ComponentFinder(db.getDbClient(), null), db.getDbClient()),
+ new ProjectBadgesSupport(new ComponentFinder(db.getDbClient(), null), db.getDbClient(), config),
new SvgGenerator(mapSettings.asConfig())));
+ @Before
+ public void before(){
+ mapSettings.setProperty(CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY, false);
+ }
+
@Test
public void int_measure() {
ComponentDto project = db.components().insertPublicProject();
@@ -318,7 +329,7 @@ public class MeasureActionTest {
}
@Test
- public void return_error_on_private_project() throws ParseException {
+ public void return_error_on_private_project_without_token() throws ParseException {
ComponentDto project = db.components().insertPrivateProject();
UserDto user = db.users().insertUser();
userSession.logIn(user).addProjectPermission(USER, project);
@@ -332,6 +343,57 @@ public class MeasureActionTest {
checkError(response, "Project has not been found");
}
+ @DataProvider
+ public static Object[][] publicProject_forceAuth_accessGranted(){
+ return new Object[][] {
+ // public project, force auth : works depending on token's validity
+ {true, true, true, true},
+ {true, true, false, false},
+
+ // public project, no force auth : access always granted
+ {true, false, true, true},
+ {true, false, false, true},
+
+ // private project, regardless of force auth, access granted depending on token's validity:
+ {false, true, true, true},
+ {false, true, false, false},
+ {false, false, true, true},
+ {false, false, false, false},
+ };
+ }
+
+ @Test
+ @UseDataProvider("publicProject_forceAuth_accessGranted")
+ public void badge_accessible_on_private_project_with_token(boolean publicProject, boolean forceAuth,
+ boolean validToken, boolean accessGranted) throws ParseException {
+ ComponentDto projectAsComponent = publicProject ? db.components().insertPublicProject() : db.components().insertPrivateProject();
+ userSession.registerComponents(projectAsComponent);
+ MetricDto metric = db.measures().insertMetric(m -> m.setKey(BUGS_KEY).setValueType(INT.name()));
+
+ db.measures().insertLiveMeasure(projectAsComponent, metric, m -> m.setValue(10_000d));
+ ProjectDto project = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), projectAsComponent.getKey())
+ .orElseThrow(() -> new IllegalStateException("project not found"));
+
+ String token = db.getDbClient().projectBadgeTokenDao()
+ .insert(db.getSession(), UuidFactoryFast.getInstance().create(), project, "user-uuid", "user-login")
+ .getToken();
+ db.commit();
+
+ mapSettings.setProperty(CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY, forceAuth);
+
+ TestResponse response = ws.newRequest()
+ .setParam("project", projectAsComponent.getKey())
+ .setParam("metric", metric.getKey())
+ .setParam("token", validToken ? token : "invalid-token")
+ .execute();
+
+ if(accessGranted){
+ checkSvg(response, "bugs", "10k", DEFAULT);
+ }else{
+ checkError(response, "Project has not been found");
+ }
+ }
+
@Test
public void return_error_on_provisioned_project() throws ParseException {
ComponentDto project = db.components().insertPublicProject();
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/badge/ws/QualityGateActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/badge/ws/QualityGateActionTest.java
index 29fc9c9d4d2..de3c268b23a 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/badge/ws/QualityGateActionTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/badge/ws/QualityGateActionTest.java
@@ -19,23 +19,32 @@
*/
package org.sonar.server.badge.ws;
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Configuration;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.measures.Metric.Level;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.measure.LiveMeasureDto;
import org.sonar.db.metric.MetricDto;
+import org.sonar.db.project.ProjectDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.tester.UserSessionRule;
@@ -51,6 +60,7 @@ import static org.sonar.api.measures.Metric.ValueType.LEVEL;
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.db.component.BranchType.BRANCH;
+@RunWith(DataProviderRunner.class)
public class QualityGateActionTest {
@Rule
@@ -60,13 +70,20 @@ public class QualityGateActionTest {
@Rule
public DbTester db = DbTester.create();
- private final MapSettings mapSettings = new MapSettings().setProperty("sonar.sonarcloud.enabled", false);
+ private final MapSettings mapSettings = new MapSettings().setProperty("sonar.sonarcloud.enabled", false).setProperty(CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY, false);
+ private final Configuration config = mapSettings.asConfig();
- private WsActionTester ws = new WsActionTester(
+ private final WsActionTester ws = new WsActionTester(
new QualityGateAction(db.getDbClient(),
- new ProjectBadgesSupport(new ComponentFinder(db.getDbClient(), null), db.getDbClient()),
+ new ProjectBadgesSupport(new ComponentFinder(db.getDbClient(), null), db.getDbClient(), config),
new SvgGenerator(mapSettings.asConfig())));
+
+ @Before
+ public void before(){
+ mapSettings.setProperty(CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY, false);
+ }
+
@Test
public void quality_gate_passed() {
ComponentDto project = db.components().insertPublicProject();
@@ -95,6 +112,58 @@ public class QualityGateActionTest {
checkResponse(response, ERROR);
}
+
+ @DataProvider
+ public static Object[][] publicProject_forceAuth_validToken_accessGranted(){
+ return new Object[][] {
+ // public project, force auth : access granted depending on token's validity
+ {true, true, true, true},
+ {true, true, false, false},
+
+ // public project, no force auth : access always granted
+ {true, false, true, true},
+ {true, false, false, true},
+
+ // private project, regardless of force auth, access granted depending on token's validity:
+ {false, true, true, true},
+ {false, true, false, false},
+ {false, false, true, true},
+ {false, false, false, false},
+ };
+ }
+
+ @Test
+ @UseDataProvider("publicProject_forceAuth_validToken_accessGranted")
+ public void badge_accessible_on_private_project_with_token(boolean publicProject, boolean forceAuth,
+ boolean validToken, boolean accessGranted) throws ParseException {
+ ComponentDto projectAsComponent = publicProject ? db.components().insertPublicProject() : db.components().insertPrivateProject();
+ userSession.registerComponents(projectAsComponent);
+ MetricDto metric = createQualityGateMetric();
+
+ db.measures().insertLiveMeasure(projectAsComponent, metric, m -> m.setData(OK.name()));
+ ProjectDto project = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), projectAsComponent.getKey())
+ .orElseThrow(() -> new IllegalStateException("project not found"));
+
+ String token = db.getDbClient().projectBadgeTokenDao()
+ .insert(db.getSession(), UuidFactoryFast.getInstance().create(), project, "user-uuid", "user-login")
+ .getToken();
+ db.commit();
+
+ mapSettings.setProperty(CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY, forceAuth);
+
+ TestResponse response = ws.newRequest()
+ .setParam("project", projectAsComponent.getKey())
+ .setParam("token", validToken ? token : "invalid-token")
+ .execute();
+
+ if(accessGranted){
+ checkResponse(response, OK);
+ }else{
+ checkError(response, "Project has not been found");
+ }
+
+ }
+
@Test
public void etag_should_be_different_if_quality_gate_is_different() {
ComponentDto project = db.components().insertPublicProject();