@@ -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; |
@@ -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); | |||
} | |||
} |
@@ -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(); |
@@ -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(); |