diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-10-19 11:48:35 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-10-20 13:16:50 +0200 |
commit | 384c1aa3aefde97b78413d621cfc9fa60a0484c9 (patch) | |
tree | d1a45fc37cec5deafcdc9895d76c64c9e1668058 /server/sonar-server | |
parent | 19199a9f6db636fc2ed5316de290eb45d601f8e3 (diff) | |
download | sonarqube-384c1aa3aefde97b78413d621cfc9fa60a0484c9.tar.gz sonarqube-384c1aa3aefde97b78413d621cfc9fa60a0484c9.zip |
SONAR-8227 Use authorization index when searching project measures
Diffstat (limited to 'server/sonar-server')
3 files changed, 115 insertions, 6 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java b/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java index df2269ab79e..f9865f7684f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/es/ProjectMeasuresIndex.java @@ -19,17 +19,21 @@ */ package org.sonar.server.component.es; +import java.util.Set; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.sort.SortOrder; import org.sonar.server.component.es.ProjectMeasuresQuery.MetricCriterion; import org.sonar.server.es.BaseIndex; import org.sonar.server.es.EsClient; import org.sonar.server.es.SearchIdResult; import org.sonar.server.es.SearchOptions; +import org.sonar.server.user.UserSession; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; +import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.nestedQuery; import static org.elasticsearch.index.query.QueryBuilders.rangeQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; @@ -39,15 +43,18 @@ import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_NAME; import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.FIELD_QUALITY_GATE; import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES; -import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES; +import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.*; public class ProjectMeasuresIndex extends BaseIndex { private static final String FIELD_KEY = FIELD_MEASURES + "." + FIELD_MEASURES_KEY; private static final String FIELD_VALUE = FIELD_MEASURES + "." + FIELD_MEASURES_VALUE; - public ProjectMeasuresIndex(EsClient client) { + private final UserSession userSession; + + public ProjectMeasuresIndex(EsClient client, UserSession userSession) { super(client); + this.userSession = userSession; } public SearchIdResult<String> search(ProjectMeasuresQuery query, SearchOptions searchOptions) { @@ -65,8 +72,9 @@ public class ProjectMeasuresIndex extends BaseIndex { return new SearchIdResult<>(request.get(), id -> id); } - private static QueryBuilder createEsQuery(ProjectMeasuresQuery query) { - BoolQueryBuilder filters = boolQuery(); + private QueryBuilder createEsQuery(ProjectMeasuresQuery query) { + BoolQueryBuilder filters = boolQuery() + .must(createAuthorizationFilter()); query.getMetricCriteria().stream() .map(criterion -> nestedQuery(FIELD_MEASURES, boolQuery() .filter(termQuery(FIELD_KEY, criterion.getMetricKey())) @@ -91,6 +99,19 @@ public class ProjectMeasuresIndex extends BaseIndex { default: throw new IllegalStateException("Metric criteria non supported: " + criterion.getOperator().name()); } + } + private QueryBuilder createAuthorizationFilter() { + String userLogin = userSession.getLogin(); + Set<String> userGroupNames = userSession.getUserGroups(); + BoolQueryBuilder groupsAndUser = boolQuery(); + if (userLogin != null) { + groupsAndUser.should(termQuery(FIELD_AUTHORIZATION_USERS, userLogin)); + } + for (String group : userGroupNames) { + groupsAndUser.should(termQuery(FIELD_AUTHORIZATION_GROUPS, group)); + } + return QueryBuilders.hasParentQuery(TYPE_AUTHORIZATION, + QueryBuilders.boolQuery().must(matchAllQuery()).filter(groupsAndUser)); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java index eaa0344eb1f..5462e3c59de 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/es/ProjectMeasuresIndexTest.java @@ -21,9 +21,11 @@ package org.sonar.server.component.es; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.IntStream; +import javax.annotation.Nullable; import org.junit.Rule; import org.junit.Test; import org.sonar.api.config.MapSettings; @@ -32,10 +34,14 @@ import org.sonar.server.component.es.ProjectMeasuresQuery.Operator; import org.sonar.server.es.EsTester; import org.sonar.server.es.SearchIdResult; import org.sonar.server.es.SearchOptions; +import org.sonar.server.permission.index.AuthorizationIndexerTester; +import org.sonar.server.tester.UserSessionRule; import static com.google.common.collect.Lists.newArrayList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.api.measures.Metric.Level.OK; +import static org.sonar.api.security.DefaultGroups.ANYONE; import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES; import static org.sonar.server.component.es.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURES; @@ -43,10 +49,16 @@ public class ProjectMeasuresIndexTest { private static final String COVERAGE = "coverage"; private static final String NCLOC = "ncloc"; + @Rule public EsTester es = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings())); - private ProjectMeasuresIndex underTest = new ProjectMeasuresIndex(es.client()); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + + private AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(es); + + private ProjectMeasuresIndex underTest = new ProjectMeasuresIndex(es.client(), userSession); @Test public void empty_search() { @@ -146,9 +158,70 @@ public class ProjectMeasuresIndexTest { assertThat(result).containsExactly("P1", "P2"); } + @Test + public void return_only_projects_authorized_for_user() throws Exception { + userSession.login("john"); + addDocs("john", null, newDoc("P1", "K1", "Windows")); + addDocs("john", "dev", newDoc("P2", "K2", "apachee")); + addDocs("another user", null, newDoc("P10", "K10", "N10")); + + List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds(); + + assertThat(result).containsOnly("P1", "P2"); + } + + @Test + public void return_only_projects_authorized_for_user_groups() throws Exception { + userSession.setUserGroups("dev"); + addDocs("john", "dev", newDoc("P1", "K1", "apachee")); + addDocs(null, ANYONE, newDoc("P2", "K2", "N2")); + addDocs(null, "admin", newDoc("P10", "K10", "N10")); + + List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds(); + + assertThat(result).containsOnly("P1", "P2"); + } + + @Test + public void return_only_projects_authorized_for_user_and_groups() throws Exception { + userSession.login("john").setUserGroups("dev"); + addDocs("john", null, newDoc("P1", "K1", "Windows")); + addDocs(null, "dev", newDoc("P2", "K2", "Apache")); + addDocs("john", "dev", newDoc("P3", "K3", "apachee")); + // Current user is not able to see following projects + addDocs(null, "another group", newDoc("P5", "K5", "N5")); + addDocs("another user", null, newDoc("P6", "K6", "N6")); + addDocs((String) null, null, newDoc("P7", "K7", "N7")); + + List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds(); + + assertThat(result).containsOnly("P1", "P2", "P3"); + } + + @Test + public void anyone_user_can_only_access_projects_authorized_for_anyone() throws Exception { + userSession.anonymous(); + addDocs(null, ANYONE, newDoc("P1", "K1", "N1")); + addDocs("john", null, newDoc("P2", "K2", "Windows")); + addDocs(null, "admin", newDoc("P3", "K3", "N3")); + + List<String> result = underTest.search(new ProjectMeasuresQuery(), new SearchOptions()).getIds(); + + assertThat(result).containsOnly("P1"); + } + private void addDocs(ProjectMeasuresDoc... docs) { + addDocs(null, ANYONE, docs); + } + + private void addDocs(@Nullable String authorizeUser, @Nullable String authorizedGroup, ProjectMeasuresDoc... docs) { try { es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, docs); + for (ProjectMeasuresDoc doc : docs) { + authorizationIndexerTester.insertProjectAuthorization(doc.getId(), + authorizedGroup != null ? singletonList(authorizedGroup) : Collections.emptyList(), + authorizeUser != null ? singletonList(authorizeUser) : Collections.emptyList()); + } } catch (Exception e) { Throwables.propagate(e); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java index bfb5533b214..d0930e213bc 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java @@ -23,6 +23,7 @@ package org.sonar.server.component.ws; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; import java.io.IOException; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.IntStream; @@ -31,6 +32,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.config.MapSettings; import org.sonar.api.measures.Metric; +import org.sonar.api.security.DefaultGroups; import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService.Param; import org.sonar.api.utils.System2; @@ -44,6 +46,8 @@ import org.sonar.server.component.es.ProjectMeasuresDoc; import org.sonar.server.component.es.ProjectMeasuresIndex; import org.sonar.server.component.es.ProjectMeasuresIndexDefinition; import org.sonar.server.es.EsTester; +import org.sonar.server.permission.index.AuthorizationIndexerTester; +import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.KeyExamples; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; @@ -55,6 +59,7 @@ import org.sonarqube.ws.client.component.SearchProjectsRequest; import static com.google.common.collect.Lists.newArrayList; import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.db.component.ComponentTesting.newDeveloper; import static org.sonar.db.component.ComponentTesting.newDirectory; @@ -71,15 +76,24 @@ import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_FIL public class SearchProjectsActionTest { @Rule public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule public EsTester es = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings())); + @Rule public DbTester db = DbTester.create(System2.INSTANCE); + private ComponentDbTester componentDb = new ComponentDbTester(db); private DbClient dbClient = db.getDbClient(); private DbSession dbSession = db.getSession(); - private WsActionTester ws = new WsActionTester(new SearchProjectsAction(dbClient, new ProjectMeasuresIndex(es.client()), new ProjectMeasuresQueryValidator(dbClient))); + private AuthorizationIndexerTester authorizationIndexerTester = new AuthorizationIndexerTester(es); + + private WsActionTester ws = new WsActionTester( + new SearchProjectsAction(dbClient, new ProjectMeasuresIndex(es.client(), userSession), new ProjectMeasuresQueryValidator(dbClient))); private SearchProjectsRequest.Builder request = SearchProjectsRequest.builder(); @@ -223,6 +237,7 @@ public class SearchProjectsActionTest { try { es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURES, new ProjectMeasuresDoc().setId(project.uuid()).setKey(project.key()).setName(project.name()).setMeasures(measures)); + authorizationIndexerTester.insertProjectAuthorization(project.uuid(), singletonList(DefaultGroups.ANYONE), Collections.emptyList()); } catch (Exception e) { Throwables.propagate(e); } |