소스 검색

SONAR-13426 Validate token for public project when auth is forced

tags/9.2.0.49834
Pierre 2 년 전
부모
커밋
8ec44b87f3

+ 0
- 1
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;

+ 9
- 3
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);
}
}

+ 66
- 4
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();

+ 72
- 3
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();

Loading…
취소
저장