From aea96d6051bde3098916139d1957d3c49526b326 Mon Sep 17 00:00:00 2001 From: Darshit Chanpura Date: Thu, 20 Jul 2023 10:49:11 -0400 Subject: [PATCH] Removed Integration Tests Signed-off-by: Darshit Chanpura --- scripts/integtest.sh | 2 +- .../security/CrossClusterSearchTests.java | 455 --- .../security/DoNotFailOnForbiddenTests.java | 411 --- .../security/PointInTimeOperationTest.java | 426 --- .../security/SearchOperationTest.java | 2719 ----------------- .../security/http/JwtAuthenticationTests.java | 270 -- .../http/LdapTlsAuthenticationTest.java | 414 --- .../test/framework/TestSecurityConfig.java | 717 ----- .../matcher/OpenSearchExceptionMatchers.java | 37 - .../OpenSearchStatusExceptionMatcher.java | 52 - .../matcher/SearchResponseMatchers.java | 87 - .../SearchResponseWithStatusCodeMatcher.java | 39 - .../matcher/SuccessBulkResponseMatcher.java | 47 - ...ssfulClearIndicesCacheResponseMatcher.java | 37 - .../SuccessfulCreatePitResponseMatcher.java | 37 - .../SuccessfulDeletePitResponseMatcher.java | 42 - .../SuccessfulDeleteResponseMatcher.java | 39 - .../SuccessfulSearchResponseMatcher.java | 37 - .../SuccessfulUpdateResponseMatcher.java | 39 - 19 files changed, 1 insertion(+), 5906 deletions(-) delete mode 100644 src/integrationTest/java/org/opensearch/security/CrossClusterSearchTests.java delete mode 100644 src/integrationTest/java/org/opensearch/security/DoNotFailOnForbiddenTests.java delete mode 100644 src/integrationTest/java/org/opensearch/security/PointInTimeOperationTest.java delete mode 100644 src/integrationTest/java/org/opensearch/security/SearchOperationTest.java delete mode 100644 src/integrationTest/java/org/opensearch/security/http/JwtAuthenticationTests.java delete mode 100644 src/integrationTest/java/org/opensearch/security/http/LdapTlsAuthenticationTest.java delete mode 100644 src/integrationTest/java/org/opensearch/test/framework/TestSecurityConfig.java delete mode 100644 src/integrationTest/java/org/opensearch/test/framework/matcher/OpenSearchExceptionMatchers.java delete mode 100644 src/integrationTest/java/org/opensearch/test/framework/matcher/OpenSearchStatusExceptionMatcher.java delete mode 100644 src/integrationTest/java/org/opensearch/test/framework/matcher/SearchResponseMatchers.java delete mode 100644 src/integrationTest/java/org/opensearch/test/framework/matcher/SearchResponseWithStatusCodeMatcher.java delete mode 100644 src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessBulkResponseMatcher.java delete mode 100644 src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulClearIndicesCacheResponseMatcher.java delete mode 100644 src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulCreatePitResponseMatcher.java delete mode 100644 src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulDeletePitResponseMatcher.java delete mode 100644 src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulDeleteResponseMatcher.java delete mode 100644 src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulSearchResponseMatcher.java delete mode 100644 src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulUpdateResponseMatcher.java diff --git a/scripts/integtest.sh b/scripts/integtest.sh index 0983d160b4..6d4c1dbedd 100755 --- a/scripts/integtest.sh +++ b/scripts/integtest.sh @@ -101,7 +101,7 @@ then fi if [ -z "$COMMON_UTILS_VERSION" ] then - COMMON_UTILS_VERSION="2.9x.0.0-SNAPSHOT" + COMMON_UTILS_VERSION="2.9.0.0-SNAPSHOT" fi USERNAME=`echo $CREDENTIAL | awk -F ':' '{print $1}'` diff --git a/src/integrationTest/java/org/opensearch/security/CrossClusterSearchTests.java b/src/integrationTest/java/org/opensearch/security/CrossClusterSearchTests.java deleted file mode 100644 index 86d27efa87..0000000000 --- a/src/integrationTest/java/org/opensearch/security/CrossClusterSearchTests.java +++ /dev/null @@ -1,455 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.security; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; -import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; -import org.apache.commons.lang3.tuple.Pair; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.opensearch.action.search.SearchRequest; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.client.Client; -import org.opensearch.client.RestHighLevelClient; -import org.opensearch.test.framework.TestSecurityConfig.Role; -import org.opensearch.test.framework.TestSecurityConfig.User; -import org.opensearch.test.framework.certificate.TestCertificates; -import org.opensearch.test.framework.cluster.ClusterManager; -import org.opensearch.test.framework.cluster.LocalCluster; -import org.opensearch.test.framework.cluster.SearchRequestFactory; -import org.opensearch.test.framework.cluster.TestRestClient; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.opensearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; -import static org.opensearch.client.RequestOptions.DEFAULT; -import static org.opensearch.core.rest.RestStatus.FORBIDDEN; -import static org.opensearch.security.Song.ARTIST_FIRST; -import static org.opensearch.security.Song.FIELD_ARTIST; -import static org.opensearch.security.Song.FIELD_GENRE; -import static org.opensearch.security.Song.FIELD_LYRICS; -import static org.opensearch.security.Song.FIELD_STARS; -import static org.opensearch.security.Song.FIELD_TITLE; -import static org.opensearch.security.Song.GENRE_JAZZ; -import static org.opensearch.security.Song.GENRE_ROCK; -import static org.opensearch.security.Song.QUERY_TITLE_MAGNUM_OPUS; -import static org.opensearch.security.Song.SONGS; -import static org.opensearch.security.Song.TITLE_MAGNUM_OPUS; -import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL; -import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.queryStringQueryRequest; -import static org.opensearch.test.framework.matcher.ExceptionMatcherAssert.assertThatThrownBy; -import static org.opensearch.test.framework.matcher.OpenSearchExceptionMatchers.statusException; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.isSuccessfulSearchResponse; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.numberOfTotalHitsIsEqualTo; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.searchHitContainsFieldWithValue; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.searchHitDoesNotContainField; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.searchHitsContainDocumentWithId; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.searchHitsContainDocumentsInAnyOrder; - -/** -* This is a parameterized test so that one test class is used to test security plugin behaviour when ccsMinimizeRoundtrips -* option is enabled or disabled. Method {@link #parameters()} is a source of parameters values. -*/ -@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) -@ThreadLeakScope(ThreadLeakScope.Scope.NONE) -public class CrossClusterSearchTests { - - private static final String SONG_INDEX_NAME = "song_lyrics"; - - private static final String PROHIBITED_SONG_INDEX_NAME = "prohibited_song_lyrics"; - - public static final String REMOTE_CLUSTER_NAME = "ccsRemote"; - public static final String REMOTE_SONG_INDEX = REMOTE_CLUSTER_NAME + ":" + SONG_INDEX_NAME; - - public static final String SONG_ID_1R = "remote-00001"; - public static final String SONG_ID_2L = "local-00002"; - public static final String SONG_ID_3R = "remote-00003"; - public static final String SONG_ID_4L = "local-00004"; - public static final String SONG_ID_5R = "remote-00005"; - public static final String SONG_ID_6R = "remote-00006"; - - private static final Role LIMITED_ROLE = new Role("limited_role").indexPermissions( - "indices:data/read/search", - "indices:admin/shards/search_shards" - ).on(SONG_INDEX_NAME, "user-${user.name}-${attr.internal.type}"); - - private static final Role DLS_ROLE_ROCK = new Role("dls_role_rock").indexPermissions( - "indices:data/read/search", - "indices:data/read/get", - "indices:admin/shards/search_shards" - ).dls(String.format("{\"match\":{\"%s\":\"%s\"}}", FIELD_GENRE, GENRE_ROCK)).on(SONG_INDEX_NAME); - - private static final Role DLS_ROLE_JAZZ = new Role("dls_role_jazz").indexPermissions( - "indices:data/read/search", - "indices:data/read/get", - "indices:admin/shards/search_shards" - ).dls(String.format("{\"match\":{\"%s\":\"%s\"}}", FIELD_GENRE, GENRE_JAZZ)).on(SONG_INDEX_NAME); - - private static final Role FLS_EXCLUDE_LYRICS_ROLE = new Role("fls_exclude_lyrics_role").indexPermissions( - "indices:data/read/search", - "indices:data/read/get", - "indices:admin/shards/search_shards" - ).fls("~" + FIELD_LYRICS).on(SONG_INDEX_NAME); - - private static final Role FLS_INCLUDE_TITLE_ROLE = new Role("fls_include_title_role").indexPermissions( - "indices:data/read/search", - "indices:data/read/get", - "indices:admin/shards/search_shards" - ).fls(FIELD_TITLE).on(SONG_INDEX_NAME); - - public static final String TYPE_ATTRIBUTE = "type"; - - private static final User ADMIN_USER = new User("admin").roles(ALL_ACCESS).attr(TYPE_ATTRIBUTE, "administrative"); - private static final User LIMITED_USER = new User("limited_user").attr(TYPE_ATTRIBUTE, "personal"); - - private static final User FLS_INCLUDE_TITLE_USER = new User("fls_include_title_user"); - - private static final User FLS_EXCLUDE_LYRICS_USER = new User("fls_exclude_lyrics_user"); - - private static final User DLS_USER_ROCK = new User("dls-user-rock"); - - private static final User DLS_USER_JAZZ = new User("dls-user-jazz"); - - public static final String LIMITED_USER_INDEX_NAME = "user-" + LIMITED_USER.getName() + "-" + LIMITED_USER.getAttribute(TYPE_ATTRIBUTE); - public static final String ADMIN_USER_INDEX_NAME = "user-" + ADMIN_USER.getName() + "-" + ADMIN_USER.getAttribute(TYPE_ATTRIBUTE); - - private static final TestCertificates TEST_CERTIFICATES = new TestCertificates(); - - private final boolean ccsMinimizeRoundtrips; - - public static final String PLUGINS_SECURITY_RESTAPI_ROLES_ENABLED = "plugins.security.restapi.roles_enabled"; - @ClassRule - public static final LocalCluster remoteCluster = new LocalCluster.Builder().certificates(TEST_CERTIFICATES) - .clusterManager(ClusterManager.SINGLENODE) - .anonymousAuth(false) - .clusterName(REMOTE_CLUSTER_NAME) - .authc(AUTHC_HTTPBASIC_INTERNAL) - .roles(LIMITED_ROLE, DLS_ROLE_ROCK, DLS_ROLE_JAZZ, FLS_EXCLUDE_LYRICS_ROLE, FLS_INCLUDE_TITLE_ROLE) - .users(ADMIN_USER) - .build(); - - @ClassRule - public static final LocalCluster cluster = new LocalCluster.Builder().certificates(TEST_CERTIFICATES) - .clusterManager(ClusterManager.SINGLE_REMOTE_CLIENT) - .anonymousAuth(false) - .clusterName("ccsLocal") - .nodeSettings(Map.of(PLUGINS_SECURITY_RESTAPI_ROLES_ENABLED, List.of("user_" + ADMIN_USER.getName() + "__" + ALL_ACCESS.getName()))) - .remote(REMOTE_CLUSTER_NAME, remoteCluster) - .roles(LIMITED_ROLE, DLS_ROLE_ROCK, DLS_ROLE_JAZZ, FLS_EXCLUDE_LYRICS_ROLE, FLS_INCLUDE_TITLE_ROLE) - .authc(AUTHC_HTTPBASIC_INTERNAL) - .users(ADMIN_USER, LIMITED_USER, DLS_USER_ROCK, DLS_USER_JAZZ, FLS_INCLUDE_TITLE_USER, FLS_EXCLUDE_LYRICS_USER) - .build(); - - @ParametersFactory(shuffle = false) - public static Iterable parameters() { - return List.of(new Object[] { true }, new Object[] { false }); - } - - public CrossClusterSearchTests(Boolean ccsMinimizeRoundtrips) { - this.ccsMinimizeRoundtrips = ccsMinimizeRoundtrips; - } - - @BeforeClass - public static void createTestData() { - try (Client client = remoteCluster.getInternalNodeClient()) { - client.prepareIndex(SONG_INDEX_NAME).setId(SONG_ID_1R).setRefreshPolicy(IMMEDIATE).setSource(SONGS[0].asMap()).get(); - client.prepareIndex(SONG_INDEX_NAME).setId(SONG_ID_6R).setRefreshPolicy(IMMEDIATE).setSource(SONGS[5].asMap()).get(); - client.prepareIndex(PROHIBITED_SONG_INDEX_NAME).setId(SONG_ID_3R).setRefreshPolicy(IMMEDIATE).setSource(SONGS[1].asMap()).get(); - client.prepareIndex(LIMITED_USER_INDEX_NAME).setId(SONG_ID_5R).setRefreshPolicy(IMMEDIATE).setSource(SONGS[4].asMap()).get(); - } - try (Client client = cluster.getInternalNodeClient()) { - client.prepareIndex(SONG_INDEX_NAME).setId(SONG_ID_2L).setRefreshPolicy(IMMEDIATE).setSource(SONGS[2].asMap()).get(); - client.prepareIndex(PROHIBITED_SONG_INDEX_NAME).setId(SONG_ID_4L).setRefreshPolicy(IMMEDIATE).setSource(SONGS[3].asMap()).get(); - } - try (TestRestClient client = cluster.getRestClient(ADMIN_USER)) { - client.assignRoleToUser(LIMITED_USER.getName(), LIMITED_ROLE.getName()).assertStatusCode(200); - client.assignRoleToUser(DLS_USER_ROCK.getName(), DLS_ROLE_ROCK.getName()).assertStatusCode(200); - client.assignRoleToUser(DLS_USER_JAZZ.getName(), DLS_ROLE_JAZZ.getName()).assertStatusCode(200); - client.assignRoleToUser(FLS_INCLUDE_TITLE_USER.getName(), FLS_INCLUDE_TITLE_ROLE.getName()).assertStatusCode(200); - client.assignRoleToUser(FLS_EXCLUDE_LYRICS_USER.getName(), FLS_EXCLUDE_LYRICS_ROLE.getName()).assertStatusCode(200); - } - } - - @Test - public void shouldFindDocumentOnRemoteCluster_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = searchAll(REMOTE_SONG_INDEX); - - SearchResponse response = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(response, isSuccessfulSearchResponse()); - assertThat(response, numberOfTotalHitsIsEqualTo(2)); - assertThat(response, searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, SONG_ID_1R)); - assertThat(response, searchHitsContainDocumentWithId(1, SONG_INDEX_NAME, SONG_ID_6R)); - } - } - - private SearchRequest searchAll(String indexName) { - SearchRequest searchRequest = SearchRequestFactory.searchAll(indexName); - searchRequest.setCcsMinimizeRoundtrips(ccsMinimizeRoundtrips); - return searchRequest; - } - - @Test - public void shouldFindDocumentOnRemoteCluster_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = searchAll(REMOTE_CLUSTER_NAME + ":" + PROHIBITED_SONG_INDEX_NAME); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldSearchForDocumentOnRemoteClustersWhenStarIsUsedAsClusterName_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = searchAll("*" + ":" + SONG_INDEX_NAME); - - SearchResponse response = restHighLevelClient.search(searchRequest, DEFAULT); - - // only remote documents are found - assertThat(response, isSuccessfulSearchResponse()); - assertThat(response, numberOfTotalHitsIsEqualTo(2)); - assertThat(response, searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, SONG_ID_1R)); - assertThat(response, searchHitsContainDocumentWithId(1, SONG_INDEX_NAME, SONG_ID_6R)); - } - } - - @Test - public void shouldSearchForDocumentOnRemoteClustersWhenStarIsUsedAsClusterName_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = searchAll("*" + ":" + PROHIBITED_SONG_INDEX_NAME); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldSearchForDocumentOnBothClustersWhenIndexOnBothClusterArePointedOut_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = SearchRequestFactory.searchAll(REMOTE_SONG_INDEX, SONG_INDEX_NAME); - searchRequest.setCcsMinimizeRoundtrips(ccsMinimizeRoundtrips); - - SearchResponse response = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(response, isSuccessfulSearchResponse()); - assertThat(response, numberOfTotalHitsIsEqualTo(3)); - assertThat( - response, - searchHitsContainDocumentsInAnyOrder( - Pair.of(SONG_INDEX_NAME, SONG_ID_1R), - Pair.of(SONG_INDEX_NAME, SONG_ID_2L), - Pair.of(SONG_INDEX_NAME, SONG_ID_6R) - ) - ); - } - } - - @Test - public void shouldSearchForDocumentOnBothClustersWhenIndexOnBothClusterArePointedOut_negativeLackOfLocalAccess() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - var searchRequest = SearchRequestFactory.searchAll(REMOTE_SONG_INDEX, PROHIBITED_SONG_INDEX_NAME); - searchRequest.setCcsMinimizeRoundtrips(ccsMinimizeRoundtrips); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldSearchForDocumentOnBothClustersWhenIndexOnBothClusterArePointedOut_negativeLackOfRemoteAccess() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - String remoteIndex = REMOTE_CLUSTER_NAME + ":" + PROHIBITED_SONG_INDEX_NAME; - SearchRequest searchRequest = SearchRequestFactory.searchAll(remoteIndex, SONG_INDEX_NAME); - searchRequest.setCcsMinimizeRoundtrips(ccsMinimizeRoundtrips); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldSearchViaAllAliasOnRemoteCluster_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(ADMIN_USER)) { - SearchRequest searchRequest = searchAll(REMOTE_CLUSTER_NAME + ":_all"); - - SearchResponse response = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(response, isSuccessfulSearchResponse()); - assertThat(response, numberOfTotalHitsIsEqualTo(4)); - assertThat( - response, - searchHitsContainDocumentsInAnyOrder( - Pair.of(SONG_INDEX_NAME, SONG_ID_1R), - Pair.of(SONG_INDEX_NAME, SONG_ID_6R), - Pair.of(PROHIBITED_SONG_INDEX_NAME, SONG_ID_3R), - Pair.of(LIMITED_USER_INDEX_NAME, SONG_ID_5R) - ) - ); - } - } - - @Test - public void shouldSearchViaAllAliasOnRemoteCluster_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = searchAll(REMOTE_CLUSTER_NAME + ":_all"); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldSearchAllIndexOnRemoteClusterWhenStarIsUsedAsIndexName_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(ADMIN_USER)) { - SearchRequest searchRequest = searchAll(REMOTE_CLUSTER_NAME + ":*"); - - SearchResponse response = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(response, isSuccessfulSearchResponse()); - assertThat(response, numberOfTotalHitsIsEqualTo(4)); - assertThat( - response, - searchHitsContainDocumentsInAnyOrder( - Pair.of(SONG_INDEX_NAME, SONG_ID_1R), - Pair.of(SONG_INDEX_NAME, SONG_ID_6R), - Pair.of(PROHIBITED_SONG_INDEX_NAME, SONG_ID_3R), - Pair.of(LIMITED_USER_INDEX_NAME, SONG_ID_5R) - ) - ); - } - } - - @Test - public void shouldSearchAllIndexOnRemoteClusterWhenStarIsUsedAsIndexName_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = searchAll(REMOTE_CLUSTER_NAME + ":*"); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldResolveUserNameExpressionInRoleIndexPattern_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = searchAll(REMOTE_CLUSTER_NAME + ":" + LIMITED_USER_INDEX_NAME); - - SearchResponse response = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(response, numberOfTotalHitsIsEqualTo(1)); - } - } - - @Test - public void shouldResolveUserNameExpressionInRoleIndexPattern_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = searchAll(REMOTE_CLUSTER_NAME + ":" + ADMIN_USER_INDEX_NAME); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldSearchInIndexWithPrefix_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = searchAll(REMOTE_CLUSTER_NAME + ":song*"); - - SearchResponse response = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(response, isSuccessfulSearchResponse()); - assertThat(response, numberOfTotalHitsIsEqualTo(2)); - assertThat( - response, - searchHitsContainDocumentsInAnyOrder(Pair.of(SONG_INDEX_NAME, SONG_ID_1R), Pair.of(SONG_INDEX_NAME, SONG_ID_6R)) - ); - } - } - - @Test - public void shouldSearchInIndexWithPrefix_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = searchAll(REMOTE_CLUSTER_NAME + ":prohibited*"); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldEvaluateDocumentLevelSecurityRulesOnRemoteClusterOnSearchRequest_caseRock() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(DLS_USER_ROCK)) { - SearchRequest searchRequest = searchAll(REMOTE_SONG_INDEX); - - SearchResponse response = restHighLevelClient.search(searchRequest, DEFAULT); - - // searching for all documents, so is it important that result contain only one document with id SONG_ID_1 - // and document with SONG_ID_6 is excluded from result set by DLS - assertThat(response, isSuccessfulSearchResponse()); - assertThat(response, numberOfTotalHitsIsEqualTo(1)); - assertThat(response, searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, SONG_ID_1R)); - } - } - - @Test - public void shouldEvaluateDocumentLevelSecurityRulesOnRemoteClusterOnSearchRequest_caseJazz() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(DLS_USER_JAZZ)) { - SearchRequest searchRequest = searchAll(REMOTE_SONG_INDEX); - - SearchResponse response = restHighLevelClient.search(searchRequest, DEFAULT); - - // searching for all documents, so is it important that result contain only one document with id SONG_ID_6 - // and document with SONG_ID_1 is excluded from result set by DLS - assertThat(response, isSuccessfulSearchResponse()); - assertThat(response, numberOfTotalHitsIsEqualTo(1)); - assertThat(response, searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, SONG_ID_6R)); - } - } - - @Test - public void shouldHaveAccessOnlyToSpecificField() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(FLS_INCLUDE_TITLE_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(REMOTE_SONG_INDEX, QUERY_TITLE_MAGNUM_OPUS); - searchRequest.setCcsMinimizeRoundtrips(ccsMinimizeRoundtrips); - - SearchResponse response = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(response, isSuccessfulSearchResponse()); - assertThat(response, numberOfTotalHitsIsEqualTo(1)); - // document should contain only title field - assertThat(response, searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_MAGNUM_OPUS)); - assertThat(response, searchHitDoesNotContainField(0, FIELD_ARTIST)); - assertThat(response, searchHitDoesNotContainField(0, FIELD_LYRICS)); - assertThat(response, searchHitDoesNotContainField(0, FIELD_STARS)); - assertThat(response, searchHitDoesNotContainField(0, FIELD_GENRE)); - } - } - - @Test - public void shouldLackAccessToSpecificField() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(FLS_EXCLUDE_LYRICS_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(REMOTE_SONG_INDEX, QUERY_TITLE_MAGNUM_OPUS); - searchRequest.setCcsMinimizeRoundtrips(ccsMinimizeRoundtrips); - - SearchResponse response = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(response, isSuccessfulSearchResponse()); - assertThat(response, numberOfTotalHitsIsEqualTo(1)); - // document should not contain lyrics field - assertThat(response, searchHitDoesNotContainField(0, FIELD_LYRICS)); - - assertThat(response, searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_MAGNUM_OPUS)); - assertThat(response, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); - assertThat(response, searchHitContainsFieldWithValue(0, FIELD_STARS, 1)); - assertThat(response, searchHitContainsFieldWithValue(0, FIELD_GENRE, GENRE_ROCK)); - } - } -} diff --git a/src/integrationTest/java/org/opensearch/security/DoNotFailOnForbiddenTests.java b/src/integrationTest/java/org/opensearch/security/DoNotFailOnForbiddenTests.java deleted file mode 100644 index fedcf0bbcb..0000000000 --- a/src/integrationTest/java/org/opensearch/security/DoNotFailOnForbiddenTests.java +++ /dev/null @@ -1,411 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.security; - -import java.io.IOException; - -import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; -import org.hamcrest.Matchers; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.opensearch.action.admin.indices.alias.IndicesAliasesRequest; -import org.opensearch.action.fieldcaps.FieldCapabilitiesRequest; -import org.opensearch.action.fieldcaps.FieldCapabilitiesResponse; -import org.opensearch.action.get.MultiGetItemResponse; -import org.opensearch.action.get.MultiGetRequest; -import org.opensearch.action.get.MultiGetResponse; -import org.opensearch.action.index.IndexRequest; -import org.opensearch.action.search.MultiSearchRequest; -import org.opensearch.action.search.MultiSearchResponse; -import org.opensearch.action.search.SearchRequest; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.action.search.SearchScrollRequest; -import org.opensearch.client.Client; -import org.opensearch.client.RestHighLevelClient; -import org.opensearch.test.framework.TestSecurityConfig; -import org.opensearch.test.framework.TestSecurityConfig.User; -import org.opensearch.test.framework.cluster.ClusterManager; -import org.opensearch.test.framework.cluster.LocalCluster; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.aMapWithSize; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.arrayContainingInAnyOrder; -import static org.hamcrest.Matchers.arrayWithSize; -import static org.hamcrest.Matchers.hasKey; -import static org.hamcrest.Matchers.nullValue; -import static org.opensearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions.Type.ADD; -import static org.opensearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; -import static org.opensearch.client.RequestOptions.DEFAULT; -import static org.opensearch.core.rest.RestStatus.FORBIDDEN; -import static org.opensearch.security.Song.FIELD_STARS; -import static org.opensearch.security.Song.FIELD_TITLE; -import static org.opensearch.security.Song.QUERY_TITLE_MAGNUM_OPUS; -import static org.opensearch.security.Song.QUERY_TITLE_NEXT_SONG; -import static org.opensearch.security.Song.QUERY_TITLE_POISON; -import static org.opensearch.security.Song.SONGS; -import static org.opensearch.security.Song.TITLE_MAGNUM_OPUS; -import static org.opensearch.security.Song.TITLE_NEXT_SONG; -import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL; -import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.averageAggregationRequest; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.getSearchScrollRequest; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.queryStringQueryRequest; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.searchRequestWithScroll; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.statsAggregationRequest; -import static org.opensearch.test.framework.matcher.ExceptionMatcherAssert.assertThatThrownBy; -import static org.opensearch.test.framework.matcher.GetResponseMatchers.containDocument; -import static org.opensearch.test.framework.matcher.GetResponseMatchers.containOnlyDocumentId; -import static org.opensearch.test.framework.matcher.GetResponseMatchers.documentContainField; -import static org.opensearch.test.framework.matcher.OpenSearchExceptionMatchers.statusException; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.containAggregationWithNameAndType; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.containNotEmptyScrollingId; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.isSuccessfulSearchResponse; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.numberOfHitsInPageIsEqualTo; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.numberOfTotalHitsIsEqualTo; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.searchHitContainsFieldWithValue; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.searchHitsContainDocumentWithId; - -@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) -@ThreadLeakScope(ThreadLeakScope.Scope.NONE) -public class DoNotFailOnForbiddenTests { - - /** - * Songs accessible for {@link #LIMITED_USER} - */ - private static final String MARVELOUS_SONGS = "marvelous_songs"; - - /** - * Songs inaccessible for {@link #LIMITED_USER} - */ - private static final String HORRIBLE_SONGS = "horrible_songs"; - - private static final String BOTH_INDEX_PATTERN = "*songs"; - - private static final String ID_1 = "1"; - private static final String ID_2 = "2"; - private static final String ID_3 = "3"; - private static final String ID_4 = "4"; - - private static final User ADMIN_USER = new User("admin").roles(ALL_ACCESS); - private static final User LIMITED_USER = new User("limited_user").roles( - new TestSecurityConfig.Role("limited-role").clusterPermissions( - "indices:data/read/mget", - "indices:data/read/msearch", - "indices:data/read/scroll" - ) - .indexPermissions( - "indices:data/read/search", - "indices:data/read/mget*", - "indices:data/read/field_caps", - "indices:data/read/field_caps*", - "indices:data/read/msearch", - "indices:data/read/scroll" - ) - .on(MARVELOUS_SONGS) - ); - - private static final String BOTH_INDEX_ALIAS = "both-indices"; - private static final String FORBIDDEN_INDEX_ALIAS = "forbidden-index"; - - @ClassRule - public static LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS) - .authc(AUTHC_HTTPBASIC_INTERNAL) - .users(ADMIN_USER, LIMITED_USER) - .anonymousAuth(false) - .doNotFailOnForbidden(true) - .build(); - - @BeforeClass - public static void createTestData() { - try (Client client = cluster.getInternalNodeClient()) { - client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(MARVELOUS_SONGS).id(ID_1).source(SONGS[0].asMap())) - .actionGet(); - client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(MARVELOUS_SONGS).id(ID_2).source(SONGS[1].asMap())) - .actionGet(); - client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(MARVELOUS_SONGS).id(ID_3).source(SONGS[2].asMap())) - .actionGet(); - - client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(HORRIBLE_SONGS).id(ID_4).source(SONGS[3].asMap())) - .actionGet(); - - client.admin() - .indices() - .aliases( - new IndicesAliasesRequest().addAliasAction( - new IndicesAliasesRequest.AliasActions(ADD).indices(MARVELOUS_SONGS, HORRIBLE_SONGS).alias(BOTH_INDEX_ALIAS) - ) - ) - .actionGet(); - client.admin() - .indices() - .aliases( - new IndicesAliasesRequest().addAliasAction( - new IndicesAliasesRequest.AliasActions(ADD).indices(HORRIBLE_SONGS).alias(FORBIDDEN_INDEX_ALIAS) - ) - ) - .actionGet(); - - } - } - - @Test - public void shouldPerformSimpleSearch_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = queryStringQueryRequest( - new String[] { MARVELOUS_SONGS, HORRIBLE_SONGS }, - QUERY_TITLE_MAGNUM_OPUS - ); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThatContainOneSong(searchResponse, ID_1, TITLE_MAGNUM_OPUS); - } - } - - private static void assertThatContainOneSong(SearchResponse searchResponse, String documentId, String title) { - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitsContainDocumentWithId(0, MARVELOUS_SONGS, documentId)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_TITLE, title)); - } - - @Test - public void shouldPerformSimpleSearch_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(HORRIBLE_SONGS, QUERY_TITLE_POISON); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldSearchForDocumentsViaIndexPattern_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(BOTH_INDEX_PATTERN, QUERY_TITLE_MAGNUM_OPUS); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThatContainOneSong(searchResponse, ID_1, TITLE_MAGNUM_OPUS); - } - } - - @Test - public void shouldSearchForDocumentsViaIndexPattern_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(HORRIBLE_SONGS, QUERY_TITLE_POISON); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldSearchForDocumentsViaAlias_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(BOTH_INDEX_ALIAS, QUERY_TITLE_MAGNUM_OPUS); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThatContainOneSong(searchResponse, ID_1, TITLE_MAGNUM_OPUS); - } - } - - @Test - public void shouldSearchForDocumentsViaAlias_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(FORBIDDEN_INDEX_ALIAS, QUERY_TITLE_POISON); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldSearchForDocumentsViaAll_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = queryStringQueryRequest("_all", QUERY_TITLE_MAGNUM_OPUS); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThatContainOneSong(searchResponse, ID_1, TITLE_MAGNUM_OPUS); - } - } - - @Test - public void shouldSearchForDocumentsViaAll_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = queryStringQueryRequest("_all", QUERY_TITLE_POISON); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(0)); - } - } - - @Test - public void shouldMGetDocument_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - MultiGetRequest request = new MultiGetRequest().add(BOTH_INDEX_PATTERN, ID_1).add(BOTH_INDEX_PATTERN, ID_4); - - MultiGetResponse response = restHighLevelClient.mget(request, DEFAULT); - - MultiGetItemResponse[] responses = response.getResponses(); - assertThat(responses, arrayWithSize(2)); - MultiGetItemResponse firstResult = responses[0]; - MultiGetItemResponse secondResult = responses[1]; - assertThat(firstResult.getFailure(), nullValue()); - assertThat(secondResult.getFailure(), nullValue()); - assertThat( - firstResult.getResponse(), - allOf(containDocument(MARVELOUS_SONGS, ID_1), documentContainField(FIELD_TITLE, TITLE_MAGNUM_OPUS)) - ); - assertThat(secondResult.getResponse(), containOnlyDocumentId(MARVELOUS_SONGS, ID_4)); - } - } - - @Test - public void shouldMGetDocument_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - MultiGetRequest request = new MultiGetRequest().add(HORRIBLE_SONGS, ID_4); - - assertThatThrownBy(() -> restHighLevelClient.mget(request, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldMSearchDocument_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - MultiSearchRequest request = new MultiSearchRequest(); - request.add(queryStringQueryRequest(BOTH_INDEX_PATTERN, QUERY_TITLE_MAGNUM_OPUS)); - request.add(queryStringQueryRequest(BOTH_INDEX_PATTERN, QUERY_TITLE_NEXT_SONG)); - - MultiSearchResponse response = restHighLevelClient.msearch(request, DEFAULT); - - MultiSearchResponse.Item[] responses = response.getResponses(); - assertThat(responses, Matchers.arrayWithSize(2)); - assertThat(responses[0].getFailure(), nullValue()); - assertThat(responses[1].getFailure(), nullValue()); - - assertThat(responses[0].getResponse(), searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_MAGNUM_OPUS)); - assertThat(responses[0].getResponse(), searchHitsContainDocumentWithId(0, MARVELOUS_SONGS, ID_1)); - assertThat(responses[1].getResponse(), searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_NEXT_SONG)); - assertThat(responses[1].getResponse(), searchHitsContainDocumentWithId(0, MARVELOUS_SONGS, ID_3)); - } - } - - @Test - public void shouldMSearchDocument_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - MultiSearchRequest request = new MultiSearchRequest(); - request.add(queryStringQueryRequest(FORBIDDEN_INDEX_ALIAS, QUERY_TITLE_POISON)); - - assertThatThrownBy(() -> restHighLevelClient.msearch(request, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldGetFieldCapabilities_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - FieldCapabilitiesRequest request = new FieldCapabilitiesRequest().indices(MARVELOUS_SONGS, HORRIBLE_SONGS).fields(FIELD_TITLE); - - FieldCapabilitiesResponse response = restHighLevelClient.fieldCaps(request, DEFAULT); - - assertThat(response.get(), aMapWithSize(1)); - assertThat(response.getIndices(), arrayWithSize(1)); - assertThat(response.getField(FIELD_TITLE), hasKey("text")); - assertThat(response.getIndices(), arrayContainingInAnyOrder(MARVELOUS_SONGS)); - } - } - - @Test - public void shouldGetFieldCapabilities_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - FieldCapabilitiesRequest request = new FieldCapabilitiesRequest().indices(HORRIBLE_SONGS).fields(FIELD_TITLE); - - assertThatThrownBy(() -> restHighLevelClient.fieldCaps(request, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldScrollOverSearchResults_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = searchRequestWithScroll(BOTH_INDEX_PATTERN, 2); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, containNotEmptyScrollingId()); - - SearchScrollRequest scrollRequest = getSearchScrollRequest(searchResponse); - - SearchResponse scrollResponse = restHighLevelClient.scroll(scrollRequest, DEFAULT); - assertThat(scrollResponse, isSuccessfulSearchResponse()); - assertThat(scrollResponse, containNotEmptyScrollingId()); - assertThat(scrollResponse, numberOfTotalHitsIsEqualTo(3)); - assertThat(scrollResponse, numberOfHitsInPageIsEqualTo(1)); - } - } - - @Test - public void shouldScrollOverSearchResults_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - SearchRequest searchRequest = searchRequestWithScroll(HORRIBLE_SONGS, 2); - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldPerformAggregation_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - final String aggregationName = "averageStars"; - SearchRequest searchRequest = averageAggregationRequest(BOTH_INDEX_PATTERN, aggregationName, FIELD_STARS); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, containAggregationWithNameAndType(aggregationName, "avg")); - } - } - - @Test - public void shouldPerformAggregation_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - final String aggregationName = "averageStars"; - SearchRequest searchRequest = averageAggregationRequest(HORRIBLE_SONGS, aggregationName, FIELD_STARS); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldPerformStatAggregation_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - final String aggregationName = "statsStars"; - SearchRequest searchRequest = statsAggregationRequest(BOTH_INDEX_ALIAS, aggregationName, FIELD_STARS); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, containAggregationWithNameAndType(aggregationName, "stats")); - } - } - - @Test - public void shouldPerformStatAggregation_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) { - final String aggregationName = "statsStars"; - SearchRequest searchRequest = statsAggregationRequest(HORRIBLE_SONGS, aggregationName, FIELD_STARS); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - -} diff --git a/src/integrationTest/java/org/opensearch/security/PointInTimeOperationTest.java b/src/integrationTest/java/org/opensearch/security/PointInTimeOperationTest.java deleted file mode 100644 index 3b01ca69bf..0000000000 --- a/src/integrationTest/java/org/opensearch/security/PointInTimeOperationTest.java +++ /dev/null @@ -1,426 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.security; - -import java.io.IOException; - -import com.carrotsearch.randomizedtesting.RandomizedRunner; -import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; -import org.apache.commons.lang3.tuple.Pair; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.opensearch.OpenSearchStatusException; -import org.opensearch.action.admin.indices.alias.IndicesAliasesRequest; -import org.opensearch.action.index.IndexRequest; -import org.opensearch.action.search.CreatePitRequest; -import org.opensearch.action.search.CreatePitResponse; -import org.opensearch.action.search.DeletePitRequest; -import org.opensearch.action.search.DeletePitResponse; -import org.opensearch.action.search.GetAllPitNodesResponse; -import org.opensearch.action.search.SearchRequest; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.client.Client; -import org.opensearch.client.RestHighLevelClient; -import org.opensearch.common.unit.TimeValue; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.search.builder.PointInTimeBuilder; -import org.opensearch.search.builder.SearchSourceBuilder; -import org.opensearch.test.framework.TestSecurityConfig; -import org.opensearch.test.framework.cluster.ClusterManager; -import org.opensearch.test.framework.cluster.LocalCluster; -import org.opensearch.test.framework.cluster.TestRestClient; -import org.opensearch.test.framework.cluster.TestRestClient.HttpResponse; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.opensearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions.Type.ADD; -import static org.opensearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; -import static org.opensearch.client.RequestOptions.DEFAULT; -import static org.opensearch.core.rest.RestStatus.FORBIDDEN; -import static org.opensearch.core.rest.RestStatus.OK; -import static org.opensearch.security.Song.SONGS; -import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL; -import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS; -import static org.opensearch.test.framework.matcher.ExceptionMatcherAssert.assertThatThrownBy; -import static org.opensearch.test.framework.matcher.OpenSearchExceptionMatchers.statusException; -import static org.opensearch.test.framework.matcher.PitResponseMatchers.deleteResponseContainsExactlyPitWithIds; -import static org.opensearch.test.framework.matcher.PitResponseMatchers.getAllResponseContainsExactlyPitWithIds; -import static org.opensearch.test.framework.matcher.PitResponseMatchers.isSuccessfulCreatePitResponse; -import static org.opensearch.test.framework.matcher.PitResponseMatchers.isSuccessfulDeletePitResponse; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.isSuccessfulSearchResponse; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.searchHitsContainDocumentsInAnyOrder; - -@RunWith(RandomizedRunner.class) -@ThreadLeakScope(ThreadLeakScope.Scope.NONE) -public class PointInTimeOperationTest { - - private static final String FIRST_SONG_INDEX = "song-index-1"; - private static final String FIRST_INDEX_ALIAS = "song-index-1-alias"; - private static final String SECOND_SONG_INDEX = "song-index-2"; - private static final String SECOND_INDEX_ALIAS = "song-index-2-alias"; - - private static final TestSecurityConfig.User ADMIN_USER = new TestSecurityConfig.User("admin").roles(ALL_ACCESS); - - /** - * User who is allowed to perform PIT operations only on the {@link #FIRST_SONG_INDEX} - */ - private static final TestSecurityConfig.User LIMITED_POINT_IN_TIME_USER = new TestSecurityConfig.User("limited_point_in_time_user") - .roles( - new TestSecurityConfig.Role("limited_point_in_time_user").indexPermissions( - "indices:data/read/point_in_time/create", - "indices:data/read/point_in_time/delete", - "indices:data/read/search", - "indices:data/read/point_in_time/readall", // anyway user needs the all indexes permission (*) to find all pits - "indices:monitor/point_in_time/segments" // anyway user needs the all indexes permission (*) to list all pits segments - ).on(FIRST_SONG_INDEX) - ); - /** - * User who is allowed to perform PIT operations on all indices - */ - private static final TestSecurityConfig.User POINT_IN_TIME_USER = new TestSecurityConfig.User("point_in_time_user").roles( - new TestSecurityConfig.Role("point_in_time_user").indexPermissions( - "indices:data/read/point_in_time/create", - "indices:data/read/point_in_time/delete", - "indices:data/read/search", - "indices:data/read/point_in_time/readall", - "indices:monitor/point_in_time/segments" - ).on("*") - ); - - private static final String ID_1 = "1"; - private static final String ID_2 = "2"; - private static final String ID_3 = "3"; - private static final String ID_4 = "4"; - - @BeforeClass - public static void createTestData() { - try (Client client = cluster.getInternalNodeClient()) { - client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(FIRST_SONG_INDEX).id(ID_1).source(SONGS[0].asMap())) - .actionGet(); - client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(FIRST_SONG_INDEX).id(ID_2).source(SONGS[1].asMap())) - .actionGet(); - client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(FIRST_SONG_INDEX).id(ID_3).source(SONGS[2].asMap())) - .actionGet(); - client.admin() - .indices() - .aliases( - new IndicesAliasesRequest().addAliasAction( - new IndicesAliasesRequest.AliasActions(ADD).indices(FIRST_SONG_INDEX).alias(FIRST_INDEX_ALIAS) - ) - ) - .actionGet(); - - client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(SECOND_SONG_INDEX).id(ID_4).source(SONGS[3].asMap())) - .actionGet(); - client.admin() - .indices() - .aliases( - new IndicesAliasesRequest().addAliasAction( - new IndicesAliasesRequest.AliasActions(ADD).indices(SECOND_SONG_INDEX).alias(SECOND_INDEX_ALIAS) - ) - ) - .actionGet(); - } - } - - @ClassRule - public static final LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS) - .anonymousAuth(false) - .authc(AUTHC_HTTPBASIC_INTERNAL) - .users(ADMIN_USER, LIMITED_POINT_IN_TIME_USER, POINT_IN_TIME_USER) - .build(); - - @Test - public void createPit_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - CreatePitRequest createPitRequest = new CreatePitRequest(TimeValue.timeValueMinutes(30), false, FIRST_SONG_INDEX); - - CreatePitResponse createPitResponse = restHighLevelClient.createPit(createPitRequest, DEFAULT); - - assertThat(createPitResponse, isSuccessfulCreatePitResponse()); - } - } - - @Test - public void createPitWithIndexAlias_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - CreatePitRequest createPitRequest = new CreatePitRequest(TimeValue.timeValueMinutes(30), false, FIRST_INDEX_ALIAS); - - CreatePitResponse createPitResponse = restHighLevelClient.createPit(createPitRequest, DEFAULT); - - assertThat(createPitResponse, isSuccessfulCreatePitResponse()); - } - } - - @Test - public void createPit_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - CreatePitRequest createPitRequest = new CreatePitRequest(TimeValue.timeValueMinutes(30), false, SECOND_SONG_INDEX); - - assertThatThrownBy(() -> restHighLevelClient.createPit(createPitRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void createPitWithIndexAlias_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - CreatePitRequest createPitRequest = new CreatePitRequest(TimeValue.timeValueMinutes(30), false, SECOND_INDEX_ALIAS); - - assertThatThrownBy(() -> restHighLevelClient.createPit(createPitRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void listAllPits_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(POINT_IN_TIME_USER)) { - cleanUpPits(); - String firstIndexPit = createPitForIndices(FIRST_SONG_INDEX); - String secondIndexPit = createPitForIndices(SECOND_SONG_INDEX); - - GetAllPitNodesResponse getAllPitsResponse = restHighLevelClient.getAllPits(DEFAULT); - - assertThat(getAllPitsResponse, getAllResponseContainsExactlyPitWithIds(firstIndexPit, secondIndexPit)); - } - } - - @Test - public void listAllPits_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - assertThatThrownBy(() -> restHighLevelClient.getAllPits(DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void deletePit_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - String existingPitId = createPitForIndices(FIRST_SONG_INDEX); - - DeletePitResponse deletePitResponse = restHighLevelClient.deletePit(new DeletePitRequest(existingPitId), DEFAULT); - assertThat(deletePitResponse, isSuccessfulDeletePitResponse()); - assertThat(deletePitResponse, deleteResponseContainsExactlyPitWithIds(existingPitId)); - } - } - - @Test - public void deletePitCreatedWithIndexAlias_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - String existingPitId = createPitForIndices(FIRST_INDEX_ALIAS); - - DeletePitResponse deletePitResponse = restHighLevelClient.deletePit(new DeletePitRequest(existingPitId), DEFAULT); - assertThat(deletePitResponse, isSuccessfulDeletePitResponse()); - assertThat(deletePitResponse, deleteResponseContainsExactlyPitWithIds(existingPitId)); - } - } - - @Test - public void deletePit_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - String existingPitId = createPitForIndices(SECOND_SONG_INDEX); - - assertThatThrownBy( - () -> restHighLevelClient.deletePit(new DeletePitRequest(existingPitId), DEFAULT), - statusException(FORBIDDEN) - ); - } - } - - @Test - public void deletePitCreatedWithIndexAlias_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - String existingPitId = createPitForIndices(SECOND_INDEX_ALIAS); - - assertThatThrownBy( - () -> restHighLevelClient.deletePit(new DeletePitRequest(existingPitId), DEFAULT), - statusException(FORBIDDEN) - ); - } - } - - @Test - public void deleteAllPits_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(POINT_IN_TIME_USER)) { - cleanUpPits(); - String firstIndexPit = createPitForIndices(FIRST_SONG_INDEX); - String secondIndexPit = createPitForIndices(SECOND_SONG_INDEX); - - DeletePitResponse deletePitResponse = restHighLevelClient.deleteAllPits(DEFAULT); - assertThat(deletePitResponse, isSuccessfulDeletePitResponse()); - assertThat(deletePitResponse, deleteResponseContainsExactlyPitWithIds(firstIndexPit, secondIndexPit)); - } - } - - @Test - public void deleteAllPits_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - assertThatThrownBy(() -> restHighLevelClient.deleteAllPits(DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void searchWithPit_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - String existingPitId = createPitForIndices(FIRST_SONG_INDEX); - - SearchRequest searchRequest = new SearchRequest(); - searchRequest.source(new SearchSourceBuilder().pointInTimeBuilder(new PointInTimeBuilder(existingPitId))); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat( - searchResponse, - searchHitsContainDocumentsInAnyOrder( - Pair.of(FIRST_SONG_INDEX, ID_1), - Pair.of(FIRST_SONG_INDEX, ID_2), - Pair.of(FIRST_SONG_INDEX, ID_3) - ) - ); - } - } - - @Test - public void searchWithPitCreatedWithIndexAlias_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - String existingPitId = createPitForIndices(FIRST_INDEX_ALIAS); - - SearchRequest searchRequest = new SearchRequest(); - searchRequest.source(new SearchSourceBuilder().pointInTimeBuilder(new PointInTimeBuilder(existingPitId))); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat( - searchResponse, - searchHitsContainDocumentsInAnyOrder( - Pair.of(FIRST_SONG_INDEX, ID_1), - Pair.of(FIRST_SONG_INDEX, ID_2), - Pair.of(FIRST_SONG_INDEX, ID_3) - ) - ); - } - } - - @Test - public void searchWithPit_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - String existingPitId = createPitForIndices(SECOND_SONG_INDEX); - - SearchRequest searchRequest = new SearchRequest(); - searchRequest.source(new SearchSourceBuilder().pointInTimeBuilder(new PointInTimeBuilder(existingPitId))); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void searchWithPitCreatedWithIndexAlias_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_POINT_IN_TIME_USER)) { - String existingPitId = createPitForIndices(SECOND_INDEX_ALIAS); - - SearchRequest searchRequest = new SearchRequest(); - searchRequest.source(new SearchSourceBuilder().pointInTimeBuilder(new PointInTimeBuilder(existingPitId))); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void listPitSegments_positive() throws IOException { - try (TestRestClient restClient = cluster.getRestClient(LIMITED_POINT_IN_TIME_USER)) { - String existingPitId = createPitForIndices(FIRST_SONG_INDEX); - String body = String.format("{\"pit_id\":[\"%s\"]}", existingPitId); - HttpResponse response = restClient.getWithJsonBody("/_cat/pit_segments", body); - - response.assertStatusCode(OK.getStatus()); - } - } - - @Test - public void listPitSegmentsCreatedWithIndexAlias_positive() throws IOException { - try (TestRestClient restClient = cluster.getRestClient(POINT_IN_TIME_USER)) { - String existingPitId = createPitForIndices(FIRST_INDEX_ALIAS); - String body = String.format("{\"pit_id\":[\"%s\"]}", existingPitId); - HttpResponse response = restClient.getWithJsonBody("/_cat/pit_segments", body); - - response.assertStatusCode(OK.getStatus()); - } - } - - @Test - public void listPitSegments_negative() throws IOException { - try (TestRestClient restClient = cluster.getRestClient(LIMITED_POINT_IN_TIME_USER)) { - String existingPitId = createPitForIndices(SECOND_SONG_INDEX); - String body = String.format("{\"pit_id\":[\"%s\"]}", existingPitId); - HttpResponse response = restClient.getWithJsonBody("/_cat/pit_segments", body); - - response.assertStatusCode(FORBIDDEN.getStatus()); - } - } - - @Test - public void listPitSegmentsCreatedWithIndexAlias_negative() throws IOException { - try (TestRestClient restClient = cluster.getRestClient(LIMITED_POINT_IN_TIME_USER)) { - String existingPitId = createPitForIndices(SECOND_INDEX_ALIAS); - String body = String.format("{\"pit_id\":[\"%s\"]}", existingPitId); - HttpResponse response = restClient.getWithJsonBody("/_cat/pit_segments", body); - - response.assertStatusCode(FORBIDDEN.getStatus()); - } - } - - @Test - public void listAllPitSegments_positive() { - try (TestRestClient restClient = cluster.getRestClient(POINT_IN_TIME_USER)) { - HttpResponse response = restClient.get("/_cat/pit_segments/_all"); - - response.assertStatusCode(OK.getStatus()); - } - } - - @Test - public void listAllPitSegments_negative() { - try (TestRestClient restClient = cluster.getRestClient(LIMITED_POINT_IN_TIME_USER)) { - HttpResponse response = restClient.get("/_cat/pit_segments/_all"); - - response.assertStatusCode(FORBIDDEN.getStatus()); - } - } - - /** - * Creates PIT for given indices. Returns PIT id. - */ - private String createPitForIndices(String... indices) throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(ADMIN_USER)) { - CreatePitRequest createPitRequest = new CreatePitRequest(TimeValue.timeValueMinutes(30), false, indices); - - CreatePitResponse createPitResponse = restHighLevelClient.createPit(createPitRequest, DEFAULT); - - assertThat(createPitResponse, isSuccessfulCreatePitResponse()); - return createPitResponse.getId(); - } - } - - /** - * Deletes all PITs. - */ - public void cleanUpPits() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(ADMIN_USER)) { - try { - restHighLevelClient.deleteAllPits(DEFAULT); - } catch (OpenSearchStatusException ex) { - if (ex.status() != RestStatus.NOT_FOUND) { - throw ex; - } - // tried to remove pits but no pit exists - } - } - } - -} diff --git a/src/integrationTest/java/org/opensearch/security/SearchOperationTest.java b/src/integrationTest/java/org/opensearch/security/SearchOperationTest.java deleted file mode 100644 index f16d40e905..0000000000 --- a/src/integrationTest/java/org/opensearch/security/SearchOperationTest.java +++ /dev/null @@ -1,2719 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.security; - -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; - -import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; -import com.google.common.base.Stopwatch; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.awaitility.Awaitility; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.opensearch.action.admin.cluster.repositories.delete.DeleteRepositoryRequest; -import org.opensearch.action.admin.cluster.repositories.put.PutRepositoryRequest; -import org.opensearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse; -import org.opensearch.action.admin.indices.alias.Alias; -import org.opensearch.action.admin.indices.alias.IndicesAliasesRequest; -import org.opensearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; -import org.opensearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest; -import org.opensearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse; -import org.opensearch.action.admin.indices.delete.DeleteIndexRequest; -import org.opensearch.action.admin.indices.exists.indices.IndicesExistsRequest; -import org.opensearch.action.admin.indices.open.OpenIndexRequest; -import org.opensearch.action.admin.indices.open.OpenIndexResponse; -import org.opensearch.action.admin.indices.settings.get.GetSettingsRequest; -import org.opensearch.action.admin.indices.settings.get.GetSettingsResponse; -import org.opensearch.action.admin.indices.settings.put.UpdateSettingsRequest; -import org.opensearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest; -import org.opensearch.action.admin.indices.template.get.GetIndexTemplatesRequest; -import org.opensearch.action.admin.indices.template.get.GetIndexTemplatesResponse; -import org.opensearch.action.bulk.BulkRequest; -import org.opensearch.action.bulk.BulkResponse; -import org.opensearch.action.delete.DeleteRequest; -import org.opensearch.action.delete.DeleteResponse; -import org.opensearch.action.fieldcaps.FieldCapabilitiesRequest; -import org.opensearch.action.fieldcaps.FieldCapabilitiesResponse; -import org.opensearch.action.get.GetRequest; -import org.opensearch.action.get.GetResponse; -import org.opensearch.action.get.MultiGetItemResponse; -import org.opensearch.action.get.MultiGetRequest; -import org.opensearch.action.get.MultiGetRequest.Item; -import org.opensearch.action.get.MultiGetResponse; -import org.opensearch.action.index.IndexRequest; -import org.opensearch.action.search.MultiSearchRequest; -import org.opensearch.action.search.MultiSearchResponse; -import org.opensearch.action.search.SearchRequest; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.action.search.SearchScrollRequest; -import org.opensearch.action.update.UpdateRequest; -import org.opensearch.action.update.UpdateResponse; -import org.opensearch.client.Client; -import org.opensearch.client.ClusterAdminClient; -import org.opensearch.client.IndicesAdminClient; -import org.opensearch.client.RestHighLevelClient; -import org.opensearch.client.core.CountRequest; -import org.opensearch.client.indices.CloseIndexRequest; -import org.opensearch.client.indices.CloseIndexResponse; -import org.opensearch.client.indices.CreateIndexRequest; -import org.opensearch.client.indices.CreateIndexResponse; -import org.opensearch.client.indices.GetIndexRequest; -import org.opensearch.client.indices.GetIndexResponse; -import org.opensearch.client.indices.GetMappingsRequest; -import org.opensearch.client.indices.GetMappingsResponse; -import org.opensearch.client.indices.PutIndexTemplateRequest; -import org.opensearch.client.indices.PutMappingRequest; -import org.opensearch.client.indices.ResizeRequest; -import org.opensearch.client.indices.ResizeResponse; -import org.opensearch.cluster.metadata.IndexMetadata; -import org.opensearch.cluster.metadata.IndexTemplateMetadata; -import org.opensearch.common.settings.Settings; -import org.opensearch.index.query.BoolQueryBuilder; -import org.opensearch.index.query.MatchQueryBuilder; -import org.opensearch.index.query.QueryBuilders; -import org.opensearch.index.reindex.BulkByScrollResponse; -import org.opensearch.index.reindex.ReindexRequest; -import org.opensearch.repositories.RepositoryMissingException; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.search.builder.SearchSourceBuilder; -import org.opensearch.test.framework.AuditCompliance; -import org.opensearch.test.framework.AuditConfiguration; -import org.opensearch.test.framework.AuditFilters; -import org.opensearch.test.framework.TestSecurityConfig.Role; -import org.opensearch.test.framework.TestSecurityConfig.User; -import org.opensearch.test.framework.audit.AuditLogsRule; -import org.opensearch.test.framework.cluster.ClusterManager; -import org.opensearch.test.framework.cluster.LocalCluster; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.arrayContaining; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.opensearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions.Type.ADD; -import static org.opensearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions.Type.REMOVE; -import static org.opensearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions.Type.REMOVE_INDEX; -import static org.opensearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; -import static org.opensearch.client.RequestOptions.DEFAULT; -import static org.opensearch.rest.RestRequest.Method.DELETE; -import static org.opensearch.rest.RestRequest.Method.GET; -import static org.opensearch.rest.RestRequest.Method.POST; -import static org.opensearch.rest.RestRequest.Method.PUT; -import static org.opensearch.core.rest.RestStatus.ACCEPTED; -import static org.opensearch.core.rest.RestStatus.FORBIDDEN; -import static org.opensearch.core.rest.RestStatus.INTERNAL_SERVER_ERROR; -import static org.opensearch.security.Song.FIELD_ARTIST; -import static org.opensearch.security.Song.FIELD_STARS; -import static org.opensearch.security.Song.FIELD_TITLE; -import static org.opensearch.security.Song.QUERY_TITLE_MAGNUM_OPUS; -import static org.opensearch.security.Song.QUERY_TITLE_NEXT_SONG; -import static org.opensearch.security.Song.QUERY_TITLE_POISON; -import static org.opensearch.security.Song.SONGS; -import static org.opensearch.security.Song.TITLE_MAGNUM_OPUS; -import static org.opensearch.security.Song.TITLE_NEXT_SONG; -import static org.opensearch.security.Song.TITLE_POISON; -import static org.opensearch.security.Song.TITLE_SONG_1_PLUS_1; -import static org.opensearch.security.auditlog.impl.AuditCategory.INDEX_EVENT; -import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL; -import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS; -import static org.opensearch.test.framework.audit.AuditMessagePredicate.auditPredicate; -import static org.opensearch.test.framework.audit.AuditMessagePredicate.grantedPrivilege; -import static org.opensearch.test.framework.audit.AuditMessagePredicate.missingPrivilege; -import static org.opensearch.test.framework.audit.AuditMessagePredicate.userAuthenticated; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.averageAggregationRequest; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.getSearchScrollRequest; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.queryStringQueryRequest; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.searchRequestWithScroll; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.statsAggregationRequest; -import static org.opensearch.test.framework.matcher.BulkResponseMatchers.bulkResponseContainExceptions; -import static org.opensearch.test.framework.matcher.BulkResponseMatchers.failureBulkResponse; -import static org.opensearch.test.framework.matcher.BulkResponseMatchers.successBulkResponse; -import static org.opensearch.test.framework.matcher.ClusterMatchers.aliasExists; -import static org.opensearch.test.framework.matcher.ClusterMatchers.clusterContainSuccessSnapshot; -import static org.opensearch.test.framework.matcher.ClusterMatchers.clusterContainTemplate; -import static org.opensearch.test.framework.matcher.ClusterMatchers.clusterContainTemplateWithAlias; -import static org.opensearch.test.framework.matcher.ClusterMatchers.clusterContainsDocument; -import static org.opensearch.test.framework.matcher.ClusterMatchers.clusterContainsDocumentWithFieldValue; -import static org.opensearch.test.framework.matcher.ClusterMatchers.clusterContainsSnapshotRepository; -import static org.opensearch.test.framework.matcher.ClusterMatchers.indexExists; -import static org.opensearch.test.framework.matcher.ClusterMatchers.indexMappingIsEqualTo; -import static org.opensearch.test.framework.matcher.ClusterMatchers.indexSettingsContainValues; -import static org.opensearch.test.framework.matcher.ClusterMatchers.indexStateIsEqualTo; -import static org.opensearch.test.framework.matcher.ClusterMatchers.snapshotInClusterDoesNotExists; -import static org.opensearch.test.framework.matcher.DeleteResponseMatchers.isSuccessfulDeleteResponse; -import static org.opensearch.test.framework.matcher.ExceptionMatcherAssert.assertThatThrownBy; -import static org.opensearch.test.framework.matcher.FieldCapabilitiesResponseMatchers.containsExactlyIndices; -import static org.opensearch.test.framework.matcher.FieldCapabilitiesResponseMatchers.containsFieldWithNameAndType; -import static org.opensearch.test.framework.matcher.FieldCapabilitiesResponseMatchers.numberOfFieldsIsEqualTo; -import static org.opensearch.test.framework.matcher.GetResponseMatchers.containDocument; -import static org.opensearch.test.framework.matcher.GetResponseMatchers.documentContainField; -import static org.opensearch.test.framework.matcher.IndexResponseMatchers.getIndexResponseContainsIndices; -import static org.opensearch.test.framework.matcher.IndexResponseMatchers.getMappingsResponseContainsIndices; -import static org.opensearch.test.framework.matcher.IndexResponseMatchers.getSettingsResponseContainsIndices; -import static org.opensearch.test.framework.matcher.IndexResponseMatchers.isSuccessfulClearIndicesCacheResponse; -import static org.opensearch.test.framework.matcher.IndexResponseMatchers.isSuccessfulCloseIndexResponse; -import static org.opensearch.test.framework.matcher.IndexResponseMatchers.isSuccessfulCreateIndexResponse; -import static org.opensearch.test.framework.matcher.IndexResponseMatchers.isSuccessfulOpenIndexResponse; -import static org.opensearch.test.framework.matcher.IndexResponseMatchers.isSuccessfulResizeResponse; -import static org.opensearch.test.framework.matcher.MultiGetResponseMatchers.isSuccessfulMultiGetResponse; -import static org.opensearch.test.framework.matcher.MultiGetResponseMatchers.numberOfGetItemResponsesIsEqualTo; -import static org.opensearch.test.framework.matcher.MultiSearchResponseMatchers.isSuccessfulMultiSearchResponse; -import static org.opensearch.test.framework.matcher.MultiSearchResponseMatchers.numberOfSearchItemResponsesIsEqualTo; -import static org.opensearch.test.framework.matcher.OpenSearchExceptionMatchers.errorMessageContain; -import static org.opensearch.test.framework.matcher.OpenSearchExceptionMatchers.statusException; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.containAggregationWithNameAndType; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.containNotEmptyScrollingId; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.isSuccessfulSearchResponse; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.numberOfHitsInPageIsEqualTo; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.numberOfTotalHitsIsEqualTo; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.searchHitContainsFieldWithValue; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.searchHitsContainDocumentWithId; -import static org.opensearch.test.framework.matcher.UpdateResponseMatchers.isSuccessfulUpdateResponse; - -@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) -@ThreadLeakScope(ThreadLeakScope.Scope.NONE) -public class SearchOperationTest { - - private static final Logger log = LogManager.getLogger(SearchOperationTest.class); - - public static final String SONG_INDEX_NAME = "song_lyrics"; - public static final String PROHIBITED_SONG_INDEX_NAME = "prohibited_song_lyrics"; - public static final String WRITE_SONG_INDEX_NAME = "write_song_index"; - - public static final String SONG_LYRICS_ALIAS = "song_lyrics_index_alias"; - public static final String PROHIBITED_SONG_ALIAS = "prohibited_song_lyrics_index_alias"; - private static final String COLLECTIVE_INDEX_ALIAS = "collective-index-alias"; - private static final String TEMPLATE_INDEX_PREFIX = "song-transcription*"; - public static final String TEMPORARY_ALIAS_NAME = "temporary-alias"; - public static final String ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0001 = "alias-used-in-musical-index-template-0001"; - public static final String ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0002 = "alias-used-in-musical-index-template-0002"; - public static final String ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0003 = "alias-used-in-musical-index-template-0003"; - public static final String INDEX_NAME_SONG_TRANSCRIPTION_JAZZ = "song-transcription-jazz"; - - public static final String MUSICAL_INDEX_TEMPLATE = "musical-index-template"; - public static final String ALIAS_CREATE_INDEX_WITH_ALIAS_POSITIVE = "alias_create_index_with_alias_positive"; - public static final String ALIAS_CREATE_INDEX_WITH_ALIAS_NEGATIVE = "alias_create_index_with_alias_negative"; - - public static final String UNDELETABLE_TEMPLATE_NAME = "undeletable-template-name"; - - public static final String ALIAS_FROM_UNDELETABLE_TEMPLATE = "alias-from-undeletable-template"; - - public static final String TEST_SNAPSHOT_REPOSITORY_NAME = "test-snapshot-repository"; - - public static final String UNUSED_SNAPSHOT_REPOSITORY_NAME = "unused-snapshot-repository"; - - public static final String RESTORED_SONG_INDEX_NAME = "restored_" + WRITE_SONG_INDEX_NAME; - - public static final String UPDATE_DELETE_OPERATION_INDEX_NAME = "update_delete_index"; - - public static final String DOCUMENT_TO_UPDATE_ID = "doc_to_update"; - - private static final String ID_P4 = "4"; - private static final String ID_S3 = "3"; - private static final String ID_S2 = "2"; - private static final String ID_S1 = "1"; - - static final User ADMIN_USER = new User("admin").roles(ALL_ACCESS); - - /** - * All user read permissions are related to {@link #SONG_INDEX_NAME} index - */ - static final User LIMITED_READ_USER = new User("limited_read_user").roles( - new Role("limited-song-reader").clusterPermissions( - "indices:data/read/mget", - "indices:data/read/msearch", - "indices:data/read/scroll" - ) - .indexPermissions( - "indices:data/read/search", - "indices:data/read/get", - "indices:data/read/mget*", - "indices:admin/aliases", - "indices:data/read/field_caps", - "indices:data/read/field_caps*" - ) - .on(SONG_INDEX_NAME) - ); - - static final User LIMITED_WRITE_USER = new User("limited_write_user").roles( - new Role("limited-write-role").clusterPermissions( - "indices:data/write/bulk", - "indices:admin/template/put", - "indices:admin/template/delete", - "cluster:admin/repository/put", - "cluster:admin/repository/delete", - "cluster:admin/snapshot/create", - "cluster:admin/snapshot/status", - "cluster:admin/snapshot/status[nodes]", - "cluster:admin/snapshot/delete", - "cluster:admin/snapshot/get", - "cluster:admin/snapshot/restore" - ) - .indexPermissions( - "indices:data/write/index", - "indices:data/write/bulk[s]", - "indices:admin/create", - "indices:admin/mapping/put", - "indices:data/write/update", - "indices:data/write/bulk[s]", - "indices:data/write/delete", - "indices:data/write/bulk[s]" - ) - .on(WRITE_SONG_INDEX_NAME), - new Role("transcription-role").indexPermissions( - "indices:data/write/index", - "indices:admin/create", - "indices:data/write/bulk[s]", - "indices:admin/mapping/put" - ).on(INDEX_NAME_SONG_TRANSCRIPTION_JAZZ), - new Role("limited-write-index-restore-role").indexPermissions( - "indices:data/write/index", - "indices:admin/create", - "indices:data/read/search" - ).on(RESTORED_SONG_INDEX_NAME) - ); - - /** - * User who is allowed read both index {@link #SONG_INDEX_NAME} and {@link #PROHIBITED_SONG_INDEX_NAME} - */ - static final User DOUBLE_READER_USER = new User("double_read_user").roles( - new Role("full-song-reader").indexPermissions("indices:data/read/search").on(SONG_INDEX_NAME, PROHIBITED_SONG_INDEX_NAME) - ); - - static final User REINDEXING_USER = new User("reindexing_user").roles( - new Role("song-reindexing-target-write").clusterPermissions("indices:data/write/reindex", "indices:data/write/bulk") - .indexPermissions("indices:admin/create", "indices:data/write/index", "indices:data/write/bulk[s]", "indices:admin/mapping/put") - .on(WRITE_SONG_INDEX_NAME), - new Role("song-reindexing-source-read").clusterPermissions("indices:data/read/scroll") - .indexPermissions("indices:data/read/search") - .on(SONG_INDEX_NAME) - ); - - private Client internalClient; - /** - * User who is allowed to update and delete documents on index {@link #UPDATE_DELETE_OPERATION_INDEX_NAME} - */ - static final User UPDATE_DELETE_USER = new User("update_delete_user").roles( - new Role("document-updater").clusterPermissions("indices:data/write/bulk") - .indexPermissions( - "indices:data/write/update", - "indices:data/write/index", - "indices:data/write/bulk[s]", - "indices:admin/mapping/put" - ) - .on(UPDATE_DELETE_OPERATION_INDEX_NAME), - new Role("document-remover").indexPermissions("indices:data/write/delete").on(UPDATE_DELETE_OPERATION_INDEX_NAME) - ); - - static final String INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX = "index_operations_"; - - /** - * User who is allowed to perform index-related operations on - * indices with names prefixed by the {@link #INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX} - */ - static final User USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES = new User("index-operation-tester").roles( - new Role("index-manager").indexPermissions( - "indices:admin/create", - "indices:admin/get", - "indices:admin/delete", - "indices:admin/close", - "indices:admin/close*", - "indices:admin/open", - "indices:admin/resize", - "indices:monitor/stats", - "indices:monitor/settings/get", - "indices:admin/settings/update", - "indices:admin/mapping/put", - "indices:admin/mappings/get", - "indices:admin/cache/clear", - "indices:admin/aliases" - ).on(INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("*")) - ); - - private static User USER_ALLOWED_TO_CREATE_INDEX = new User("user-allowed-to-create-index").roles( - new Role("create-index-role").indexPermissions("indices:admin/create").on("*") - ); - - @ClassRule - public static final LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS) - .anonymousAuth(false) - .authc(AUTHC_HTTPBASIC_INTERNAL) - .users( - ADMIN_USER, - LIMITED_READ_USER, - LIMITED_WRITE_USER, - DOUBLE_READER_USER, - REINDEXING_USER, - UPDATE_DELETE_USER, - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES, - USER_ALLOWED_TO_CREATE_INDEX - ) - .audit( - new AuditConfiguration(true).compliance(new AuditCompliance().enabled(true)) - .filters(new AuditFilters().enabledRest(true).enabledTransport(true)) - ) - .build(); - - @Rule - public AuditLogsRule auditLogsRule = new AuditLogsRule(); - - @BeforeClass - public static void createTestData() { - try (Client client = cluster.getInternalNodeClient()) { - client.prepareIndex(SONG_INDEX_NAME).setId(ID_S1).setRefreshPolicy(IMMEDIATE).setSource(SONGS[0].asMap()).get(); - client.prepareIndex(UPDATE_DELETE_OPERATION_INDEX_NAME) - .setId(DOCUMENT_TO_UPDATE_ID) - .setRefreshPolicy(IMMEDIATE) - .setSource("field", "value") - .get(); - client.admin() - .indices() - .aliases( - new IndicesAliasesRequest().addAliasAction(new AliasActions(ADD).indices(SONG_INDEX_NAME).alias(SONG_LYRICS_ALIAS)) - ) - .actionGet(); - client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(SONG_INDEX_NAME).id(ID_S2).source(SONGS[1].asMap())) - .actionGet(); - client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(SONG_INDEX_NAME).id(ID_S3).source(SONGS[2].asMap())) - .actionGet(); - - client.prepareIndex(PROHIBITED_SONG_INDEX_NAME).setId(ID_P4).setSource(SONGS[3].asMap()).setRefreshPolicy(IMMEDIATE).get(); - client.admin() - .indices() - .aliases( - new IndicesAliasesRequest().addAliasAction( - new AliasActions(ADD).indices(PROHIBITED_SONG_INDEX_NAME).alias(PROHIBITED_SONG_ALIAS) - ) - ) - .actionGet(); - - client.admin() - .indices() - .aliases( - new IndicesAliasesRequest().addAliasAction( - new AliasActions(ADD).indices(SONG_INDEX_NAME, PROHIBITED_SONG_INDEX_NAME).alias(COLLECTIVE_INDEX_ALIAS) - ) - ) - .actionGet(); - var createTemplateRequest = new org.opensearch.action.admin.indices.template.put.PutIndexTemplateRequest( - UNDELETABLE_TEMPLATE_NAME - ); - createTemplateRequest.patterns(List.of("pattern-does-not-match-to-any-index")); - createTemplateRequest.alias(new Alias(ALIAS_FROM_UNDELETABLE_TEMPLATE)); - client.admin().indices().putTemplate(createTemplateRequest).actionGet(); - - client.admin() - .cluster() - .putRepository( - new PutRepositoryRequest(UNUSED_SNAPSHOT_REPOSITORY_NAME).type("fs") - .settings(Map.of("location", cluster.getSnapshotDirPath())) - ) - .actionGet(); - } - } - - @Before - public void retrieveClusterClient() { - this.internalClient = cluster.getInternalNodeClient(); - } - - @After - public void cleanData() throws ExecutionException, InterruptedException { - Stopwatch stopwatch = Stopwatch.createStarted(); - IndicesAdminClient indices = internalClient.admin().indices(); - List indicesToBeDeleted = List.of( - WRITE_SONG_INDEX_NAME, - INDEX_NAME_SONG_TRANSCRIPTION_JAZZ, - RESTORED_SONG_INDEX_NAME, - INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("*") - ); - for (String indexToBeDeleted : indicesToBeDeleted) { - IndicesExistsRequest indicesExistsRequest = new IndicesExistsRequest(indexToBeDeleted); - var indicesExistsResponse = indices.exists(indicesExistsRequest).get(); - if (indicesExistsResponse.isExists()) { - DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexToBeDeleted); - indices.delete(deleteIndexRequest).actionGet(); - Awaitility.await().ignoreExceptions().until(() -> indices.exists(indicesExistsRequest).get().isExists() == false); - } - } - - List aliasesToBeDeleted = List.of( - TEMPORARY_ALIAS_NAME, - ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0001, - ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0002, - ALIAS_CREATE_INDEX_WITH_ALIAS_POSITIVE, - ALIAS_CREATE_INDEX_WITH_ALIAS_NEGATIVE - ); - for (String aliasToBeDeleted : aliasesToBeDeleted) { - if (indices.exists(new IndicesExistsRequest(aliasToBeDeleted)).get().isExists()) { - AliasActions aliasAction = new AliasActions(AliasActions.Type.REMOVE).indices(SONG_INDEX_NAME).alias(aliasToBeDeleted); - internalClient.admin().indices().aliases(new IndicesAliasesRequest().addAliasAction(aliasAction)).get(); - } - } - - GetIndexTemplatesResponse response = indices.getTemplates(new GetIndexTemplatesRequest(MUSICAL_INDEX_TEMPLATE)).get(); - for (IndexTemplateMetadata metadata : response.getIndexTemplates()) { - indices.deleteTemplate(new DeleteIndexTemplateRequest(metadata.getName())).get(); - } - - ClusterAdminClient clusterClient = internalClient.admin().cluster(); - try { - clusterClient.deleteRepository(new DeleteRepositoryRequest(TEST_SNAPSHOT_REPOSITORY_NAME)).actionGet(); - } catch (RepositoryMissingException e) { - log.debug("Repository '{}' does not exist. This is expected in most of test cases", TEST_SNAPSHOT_REPOSITORY_NAME, e); - } - internalClient.close(); - log.debug("Cleaning data after test took {}", stopwatch.stop()); - } - - @Test - public void shouldSearchForDocuments_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(SONG_INDEX_NAME, QUERY_TITLE_MAGNUM_OPUS); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, ID_S1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_MAGNUM_OPUS)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/song_lyrics/_search")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldSearchForDocuments_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(PROHIBITED_SONG_INDEX_NAME, QUERY_TITLE_POISON); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/prohibited_song_lyrics/_search")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldSearchForDocumentsViaAlias_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(SONG_LYRICS_ALIAS, QUERY_TITLE_MAGNUM_OPUS); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, ID_S1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_MAGNUM_OPUS)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/song_lyrics_index_alias/_search")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldSearchForDocumentsViaAlias_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(PROHIBITED_SONG_ALIAS, QUERY_TITLE_POISON); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/prohibited_song_lyrics_index_alias/_search") - ); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldBeAbleToSearchSongViaMultiIndexAlias_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(DOUBLE_READER_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(COLLECTIVE_INDEX_ALIAS, QUERY_TITLE_NEXT_SONG); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, ID_S3)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_NEXT_SONG)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(DOUBLE_READER_USER).withRestRequest(POST, "/collective-index-alias/_search")); - auditLogsRule.assertExactlyOne(grantedPrivilege(DOUBLE_READER_USER, "SearchRequest")); - } - - @Test - public void shouldBeAbleToSearchSongViaMultiIndexAlias_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(COLLECTIVE_INDEX_ALIAS, QUERY_TITLE_POISON); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/collective-index-alias/_search")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldBeAbleToSearchAllIndexes_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(ADMIN_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(QUERY_TITLE_MAGNUM_OPUS); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, ID_S1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_MAGNUM_OPUS)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(ADMIN_USER).withRestRequest(POST, "/_search")); - auditLogsRule.assertExactlyOne(grantedPrivilege(ADMIN_USER, "SearchRequest")); - } - - @Test - public void shouldBeAbleToSearchAllIndexes_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = queryStringQueryRequest(QUERY_TITLE_MAGNUM_OPUS); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/_search")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldBeAbleToSearchSongIndexesWithAsterisk_prohibitedSongIndex_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(DOUBLE_READER_USER)) { - SearchRequest searchRequest = queryStringQueryRequest("*" + SONG_INDEX_NAME, QUERY_TITLE_POISON); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitsContainDocumentWithId(0, PROHIBITED_SONG_INDEX_NAME, ID_P4)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_POISON)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(DOUBLE_READER_USER).withRestRequest(POST, "/*song_lyrics/_search")); - auditLogsRule.assertExactlyOne(grantedPrivilege(DOUBLE_READER_USER, "SearchRequest")); - } - - @Test - public void shouldBeAbleToSearchSongIndexesWithAsterisk_singIndex_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(DOUBLE_READER_USER)) { - SearchRequest searchRequest = queryStringQueryRequest("*" + SONG_INDEX_NAME, QUERY_TITLE_NEXT_SONG); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, ID_S3)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_NEXT_SONG)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(DOUBLE_READER_USER).withRestRequest(POST, "/*song_lyrics/_search")); - auditLogsRule.assertExactlyOne(grantedPrivilege(DOUBLE_READER_USER, "SearchRequest")); - } - - @Test - public void shouldBeAbleToSearchSongIndexesWithAsterisk_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = queryStringQueryRequest("*" + SONG_INDEX_NAME, QUERY_TITLE_NEXT_SONG); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/*song_lyrics/_search")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldFindSongUsingDslQuery_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = new SearchRequest(SONG_INDEX_NAME); - SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); - BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); - boolQueryBuilder.filter(QueryBuilders.regexpQuery(FIELD_ARTIST, "f.+")); - boolQueryBuilder.filter(new MatchQueryBuilder(FIELD_TITLE, TITLE_MAGNUM_OPUS)); - searchSourceBuilder.query(boolQueryBuilder); - searchRequest.source(searchSourceBuilder); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, ID_S1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_MAGNUM_OPUS)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/song_lyrics/_search")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldFindSongUsingDslQuery_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = new SearchRequest(PROHIBITED_SONG_INDEX_NAME); - SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); - BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); - boolQueryBuilder.filter(QueryBuilders.regexpQuery(FIELD_ARTIST, "n.+")); - boolQueryBuilder.filter(new MatchQueryBuilder(FIELD_TITLE, TITLE_POISON)); - searchSourceBuilder.query(boolQueryBuilder); - searchRequest.source(searchSourceBuilder); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/prohibited_song_lyrics/_search")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldPerformSearchWithAllIndexAlias_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(ADMIN_USER)) { - SearchRequest searchRequest = queryStringQueryRequest("_all", QUERY_TITLE_MAGNUM_OPUS); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, ID_S1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_MAGNUM_OPUS)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(ADMIN_USER).withRestRequest(POST, "/_all/_search")); - auditLogsRule.assertExactlyOne(grantedPrivilege(ADMIN_USER, "SearchRequest")); - } - - @Test - public void shouldPerformSearchWithAllIndexAlias_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = queryStringQueryRequest("_all", QUERY_TITLE_MAGNUM_OPUS); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/_all/_search")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldScrollOverSearchResults_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = searchRequestWithScroll(SONG_INDEX_NAME, 2); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, containNotEmptyScrollingId()); - - SearchScrollRequest scrollRequest = getSearchScrollRequest(searchResponse); - - SearchResponse scrollResponse = restHighLevelClient.scroll(scrollRequest, DEFAULT); - assertThat(scrollResponse, isSuccessfulSearchResponse()); - assertThat(scrollResponse, containNotEmptyScrollingId()); - assertThat(scrollResponse, numberOfTotalHitsIsEqualTo(3)); - assertThat(scrollResponse, numberOfHitsInPageIsEqualTo(1)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/song_lyrics/_search")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "SearchRequest")); - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/_search/scroll")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "SearchScrollRequest")); - } - - @Test - public void shouldScrollOverSearchResults_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(DOUBLE_READER_USER)) { - SearchRequest searchRequest = searchRequestWithScroll(SONG_INDEX_NAME, 2); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, containNotEmptyScrollingId()); - - SearchScrollRequest scrollRequest = getSearchScrollRequest(searchResponse); - - assertThatThrownBy(() -> restHighLevelClient.scroll(scrollRequest, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(DOUBLE_READER_USER).withRestRequest(POST, "/song_lyrics/_search")); - auditLogsRule.assertExactlyOne(grantedPrivilege(DOUBLE_READER_USER, "SearchRequest")); - auditLogsRule.assertExactlyOne(userAuthenticated(DOUBLE_READER_USER).withRestRequest(POST, "/_search/scroll")); - auditLogsRule.assertExactlyOne(missingPrivilege(DOUBLE_READER_USER, "SearchScrollRequest")); - } - - @Test - public void shouldGetDocument_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - GetResponse response = restHighLevelClient.get(new GetRequest(SONG_INDEX_NAME, ID_S1), DEFAULT); - - assertThat(response, containDocument(SONG_INDEX_NAME, ID_S1)); - assertThat(response, documentContainField(FIELD_TITLE, TITLE_MAGNUM_OPUS)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(GET, "/song_lyrics/_doc/1")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "GetRequest")); - } - - @Test - public void shouldGetDocument_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - GetRequest getRequest = new GetRequest(PROHIBITED_SONG_INDEX_NAME, ID_P4); - assertThatThrownBy(() -> restHighLevelClient.get(getRequest, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(GET, "/prohibited_song_lyrics/_doc/4")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "GetRequest")); - } - - @Test - public void shouldPerformMultiGetDocuments_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - MultiGetRequest request = new MultiGetRequest(); - request.add(new Item(SONG_INDEX_NAME, ID_S1)); - request.add(new Item(SONG_INDEX_NAME, ID_S2)); - - MultiGetResponse response = restHighLevelClient.mget(request, DEFAULT); - - assertThat(response, is(notNullValue())); - assertThat(response, isSuccessfulMultiGetResponse()); - assertThat(response, numberOfGetItemResponsesIsEqualTo(2)); - - MultiGetItemResponse[] responses = response.getResponses(); - assertThat( - responses[0].getResponse(), - allOf(containDocument(SONG_INDEX_NAME, ID_S1), documentContainField(FIELD_TITLE, TITLE_MAGNUM_OPUS)) - ); - assertThat( - responses[1].getResponse(), - allOf(containDocument(SONG_INDEX_NAME, ID_S2), documentContainField(FIELD_TITLE, TITLE_SONG_1_PLUS_1)) - ); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/_mget")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "MultiGetRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "MultiGetShardRequest")); - } - - @Test - public void shouldPerformMultiGetDocuments_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(DOUBLE_READER_USER)) { - MultiGetRequest request = new MultiGetRequest(); - request.add(new Item(SONG_INDEX_NAME, ID_S1)); - - assertThatThrownBy(() -> restHighLevelClient.mget(request, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(DOUBLE_READER_USER).withRestRequest(POST, "/_mget")); - auditLogsRule.assertExactlyOne(missingPrivilege(DOUBLE_READER_USER, "MultiGetRequest")); - } - - @Test - public void shouldPerformMultiGetDocuments_partiallyPositive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - MultiGetRequest request = new MultiGetRequest(); - request.add(new Item(SONG_INDEX_NAME, ID_S1)); - request.add(new Item(PROHIBITED_SONG_INDEX_NAME, ID_P4)); - - MultiGetResponse response = restHighLevelClient.mget(request, DEFAULT); - - assertThat(request, notNullValue()); - assertThat(response, not(isSuccessfulMultiGetResponse())); - assertThat(response, numberOfGetItemResponsesIsEqualTo(2)); - - MultiGetItemResponse[] responses = response.getResponses(); - assertThat(responses, arrayContaining(hasProperty("failure", nullValue()), hasProperty("failure", notNullValue()))); - assertThat(responses[1].getFailure().getFailure(), statusException(INTERNAL_SERVER_ERROR)); - assertThat(responses[1].getFailure().getFailure(), errorMessageContain("security_exception")); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/_mget")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "MultiGetRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "MultiGetShardRequest").withIndex(SONG_INDEX_NAME)); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "MultiGetShardRequest").withIndex(PROHIBITED_SONG_INDEX_NAME)); - } - - @Test - public void shouldBeAllowedToPerformMulitSearch_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - MultiSearchRequest request = new MultiSearchRequest(); - request.add(queryStringQueryRequest(SONG_INDEX_NAME, QUERY_TITLE_MAGNUM_OPUS)); - request.add(queryStringQueryRequest(SONG_INDEX_NAME, QUERY_TITLE_NEXT_SONG)); - - MultiSearchResponse response = restHighLevelClient.msearch(request, DEFAULT); - - assertThat(response, notNullValue()); - assertThat(response, isSuccessfulMultiSearchResponse()); - assertThat(response, numberOfSearchItemResponsesIsEqualTo(2)); - - MultiSearchResponse.Item[] responses = response.getResponses(); - - assertThat(responses[0].getResponse(), searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_MAGNUM_OPUS)); - assertThat(responses[0].getResponse(), searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, ID_S1)); - assertThat(responses[1].getResponse(), searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_NEXT_SONG)); - assertThat(responses[1].getResponse(), searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, ID_S3)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/_msearch")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "MultiSearchRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldBeAllowedToPerformMulitSearch_partiallyPositive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - MultiSearchRequest request = new MultiSearchRequest(); - request.add(queryStringQueryRequest(SONG_INDEX_NAME, QUERY_TITLE_MAGNUM_OPUS)); - request.add(queryStringQueryRequest(PROHIBITED_SONG_INDEX_NAME, QUERY_TITLE_POISON)); - - MultiSearchResponse response = restHighLevelClient.msearch(request, DEFAULT); - - assertThat(response, notNullValue()); - assertThat(response, not(isSuccessfulMultiSearchResponse())); - assertThat(response, numberOfSearchItemResponsesIsEqualTo(2)); - - MultiSearchResponse.Item[] responses = response.getResponses(); - assertThat(responses[0].getFailure(), nullValue()); - assertThat(responses[1].getFailure(), statusException(INTERNAL_SERVER_ERROR)); - assertThat(responses[1].getFailure(), errorMessageContain("security_exception")); - assertThat(responses[1].getResponse(), nullValue()); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/_msearch")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "MultiSearchRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "SearchRequest").withIndex(SONG_INDEX_NAME)); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "SearchRequest").withIndex(PROHIBITED_SONG_INDEX_NAME)); - } - - @Test - public void shouldBeAllowedToPerformMulitSearch_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(DOUBLE_READER_USER)) { - MultiSearchRequest request = new MultiSearchRequest(); - request.add(queryStringQueryRequest(SONG_INDEX_NAME, QUERY_TITLE_MAGNUM_OPUS)); - request.add(queryStringQueryRequest(SONG_INDEX_NAME, QUERY_TITLE_NEXT_SONG)); - - assertThatThrownBy(() -> restHighLevelClient.msearch(request, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(DOUBLE_READER_USER).withRestRequest(POST, "/_msearch")); - auditLogsRule.assertExactlyOne(missingPrivilege(DOUBLE_READER_USER, "MultiSearchRequest")); - } - - @Test - public void shouldAggregateDataAndComputeAverage_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - final String aggregationName = "averageStars"; - SearchRequest searchRequest = averageAggregationRequest(SONG_INDEX_NAME, aggregationName, FIELD_STARS); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, containAggregationWithNameAndType(aggregationName, "avg")); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/song_lyrics/_search")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "SearchRequest").withIndex(SONG_INDEX_NAME)); - } - - @Test - public void shouldAggregateDataAndComputeAverage_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = averageAggregationRequest(PROHIBITED_SONG_INDEX_NAME, "averageStars", FIELD_STARS); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/prohibited_song_lyrics/_search")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "SearchRequest").withIndex(PROHIBITED_SONG_INDEX_NAME)); - } - - @Test - public void shouldPerformStatAggregation_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - final String aggregationName = "statsStars"; - SearchRequest searchRequest = statsAggregationRequest(SONG_INDEX_NAME, aggregationName, FIELD_STARS); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, containAggregationWithNameAndType(aggregationName, "stats")); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/song_lyrics/_search")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldPerformStatAggregation_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SearchRequest searchRequest = statsAggregationRequest(PROHIBITED_SONG_INDEX_NAME, "statsStars", FIELD_STARS); - - assertThatThrownBy(() -> restHighLevelClient.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/prohibited_song_lyrics/_search")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "SearchRequest")); - } - - @Test - public void shouldIndexDocumentInBulkRequest_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - BulkRequest bulkRequest = new BulkRequest(); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("one").source(SONGS[0].asMap())); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("two").source(SONGS[1].asMap())); - bulkRequest.setRefreshPolicy(IMMEDIATE); - - BulkResponse response = restHighLevelClient.bulk(bulkRequest, DEFAULT); - - assertThat(response, successBulkResponse()); - assertThat(internalClient, clusterContainsDocument(WRITE_SONG_INDEX_NAME, "one")); - assertThat(internalClient, clusterContainsDocument(WRITE_SONG_INDEX_NAME, "two")); - assertThat(internalClient, clusterContainsDocumentWithFieldValue(WRITE_SONG_INDEX_NAME, "one", FIELD_TITLE, TITLE_MAGNUM_OPUS)); - assertThat( - internalClient, - clusterContainsDocumentWithFieldValue(WRITE_SONG_INDEX_NAME, "two", FIELD_TITLE, TITLE_SONG_1_PLUS_1) - ); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/_bulk")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateIndexRequest")); - auditLogsRule.assertAtLeast(4, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_WRITE_USER));// sometimes 4 or 6 - auditLogsRule.assertAtLeast(2, grantedPrivilege(LIMITED_WRITE_USER, "PutMappingRequest"));// sometimes 2 or 4 - } - - @Test - public void shouldIndexDocumentInBulkRequest_partiallyPositive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - BulkRequest bulkRequest = new BulkRequest(); - bulkRequest.add(new IndexRequest(SONG_INDEX_NAME).id("one").source(SONGS[0].asMap())); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("two").source(SONGS[1].asMap())); - bulkRequest.setRefreshPolicy(IMMEDIATE); - - BulkResponse response = restHighLevelClient.bulk(bulkRequest, DEFAULT); - - assertThat( - response, - bulkResponseContainExceptions(0, allOf(statusException(INTERNAL_SERVER_ERROR), errorMessageContain("security_exception"))) - ); - assertThat(internalClient, clusterContainsDocument(WRITE_SONG_INDEX_NAME, "two")); - assertThat( - internalClient, - clusterContainsDocumentWithFieldValue(WRITE_SONG_INDEX_NAME, "two", FIELD_TITLE, TITLE_SONG_1_PLUS_1) - ); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/_bulk")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateIndexRequest")); - auditLogsRule.assertExactly(6, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_WRITE_USER)); - auditLogsRule.assertExactly(4, grantedPrivilege(LIMITED_WRITE_USER, "PutMappingRequest")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_WRITE_USER, "BulkShardRequest").withIndex(SONG_INDEX_NAME)); - } - - @Test - public void shouldIndexDocumentInBulkRequest_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - BulkRequest bulkRequest = new BulkRequest(); - bulkRequest.add(new IndexRequest(SONG_INDEX_NAME).id("one").source(SONGS[0].asMap())); - bulkRequest.add(new IndexRequest(SONG_INDEX_NAME).id("two").source(SONGS[1].asMap())); - bulkRequest.setRefreshPolicy(IMMEDIATE); - - BulkResponse response = restHighLevelClient.bulk(bulkRequest, DEFAULT); - - assertThat( - response, - allOf( - failureBulkResponse(), - bulkResponseContainExceptions(statusException(INTERNAL_SERVER_ERROR)), - bulkResponseContainExceptions(errorMessageContain("security_exception")) - ) - ); - assertThat(internalClient, not(clusterContainsDocument(SONG_INDEX_NAME, "one"))); - assertThat(internalClient, not(clusterContainsDocument(SONG_INDEX_NAME, "two"))); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/_bulk")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_WRITE_USER, "BulkShardRequest").withIndex(SONG_INDEX_NAME)); - } - - @Test - public void shouldUpdateDocumentsInBulk_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - final String titleOne = "shape of my mind"; - final String titleTwo = "forgiven"; - BulkRequest bulkRequest = new BulkRequest().setRefreshPolicy(IMMEDIATE); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("one").source(SONGS[0].asMap())); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("two").source(SONGS[1].asMap())); - restHighLevelClient.bulk(bulkRequest, DEFAULT); - bulkRequest = new BulkRequest().setRefreshPolicy(IMMEDIATE); - bulkRequest.add(new UpdateRequest(WRITE_SONG_INDEX_NAME, "one").doc(Map.of(FIELD_TITLE, titleOne))); - bulkRequest.add(new UpdateRequest(WRITE_SONG_INDEX_NAME, "two").doc(Map.of(FIELD_TITLE, titleTwo))); - - BulkResponse response = restHighLevelClient.bulk(bulkRequest, DEFAULT); - - assertThat(response, successBulkResponse()); - assertThat(internalClient, clusterContainsDocumentWithFieldValue(WRITE_SONG_INDEX_NAME, "one", FIELD_TITLE, titleOne)); - assertThat(internalClient, clusterContainsDocumentWithFieldValue(WRITE_SONG_INDEX_NAME, "two", FIELD_TITLE, titleTwo)); - } - auditLogsRule.assertExactly(2, userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/_bulk")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateIndexRequest")); - auditLogsRule.assertExactly(4, grantedPrivilege(LIMITED_WRITE_USER, "PutMappingRequest")); - auditLogsRule.assertExactly(6, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_WRITE_USER)); - - } - - @Test - public void shouldUpdateDocumentsInBulk_partiallyPositive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - final String titleOne = "shape of my mind"; - BulkRequest bulkRequest = new BulkRequest().setRefreshPolicy(IMMEDIATE); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("one").source(SONGS[0].asMap())); - restHighLevelClient.bulk(bulkRequest, DEFAULT); - bulkRequest = new BulkRequest().setRefreshPolicy(IMMEDIATE); - bulkRequest.add(new UpdateRequest(WRITE_SONG_INDEX_NAME, "one").doc(Map.of(FIELD_TITLE, titleOne))); - bulkRequest.add(new UpdateRequest(SONG_INDEX_NAME, ID_S2).doc(Map.of(FIELD_TITLE, "forgiven"))); - - BulkResponse response = restHighLevelClient.bulk(bulkRequest, DEFAULT); - - assertThat( - response, - bulkResponseContainExceptions(1, allOf(statusException(INTERNAL_SERVER_ERROR), errorMessageContain("security_exception"))) - ); - assertThat(internalClient, clusterContainsDocumentWithFieldValue(WRITE_SONG_INDEX_NAME, "one", FIELD_TITLE, titleOne)); - assertThat(internalClient, clusterContainsDocumentWithFieldValue(SONG_INDEX_NAME, ID_S2, FIELD_TITLE, TITLE_SONG_1_PLUS_1)); - } - auditLogsRule.assertExactly(2, userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/_bulk")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateIndexRequest")); - auditLogsRule.assertExactly(4, grantedPrivilege(LIMITED_WRITE_USER, "PutMappingRequest")); - auditLogsRule.assertExactly(6, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_WRITE_USER)); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_WRITE_USER, "BulkShardRequest").withIndex(SONG_INDEX_NAME)); - } - - @Test - public void shouldUpdateDocumentsInBulk_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - BulkRequest bulkRequest = new BulkRequest().setRefreshPolicy(IMMEDIATE); - bulkRequest.add(new UpdateRequest(SONG_INDEX_NAME, ID_S1).doc(Map.of(FIELD_TITLE, "shape of my mind"))); - bulkRequest.add(new UpdateRequest(SONG_INDEX_NAME, ID_S2).doc(Map.of(FIELD_TITLE, "forgiven"))); - - BulkResponse response = restHighLevelClient.bulk(bulkRequest, DEFAULT); - - assertThat( - response, - allOf( - failureBulkResponse(), - bulkResponseContainExceptions(statusException(INTERNAL_SERVER_ERROR)), - bulkResponseContainExceptions(errorMessageContain("security_exception")) - ) - ); - assertThat(internalClient, clusterContainsDocumentWithFieldValue(SONG_INDEX_NAME, ID_S1, FIELD_TITLE, TITLE_MAGNUM_OPUS)); - assertThat(internalClient, clusterContainsDocumentWithFieldValue(SONG_INDEX_NAME, ID_S2, FIELD_TITLE, TITLE_SONG_1_PLUS_1)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/_bulk")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_WRITE_USER, "BulkShardRequest")); - } - - @Test - public void shouldDeleteDocumentInBulk_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - BulkRequest bulkRequest = new BulkRequest().setRefreshPolicy(IMMEDIATE); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("one").source(SONGS[0].asMap())); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("two").source(SONGS[1].asMap())); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("three").source(SONGS[2].asMap())); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("four").source(SONGS[3].asMap())); - assertThat(restHighLevelClient.bulk(bulkRequest, DEFAULT), successBulkResponse()); - bulkRequest = new BulkRequest().setRefreshPolicy(IMMEDIATE); - bulkRequest.add(new DeleteRequest(WRITE_SONG_INDEX_NAME, "one")); - bulkRequest.add(new DeleteRequest(WRITE_SONG_INDEX_NAME, "three")); - - BulkResponse response = restHighLevelClient.bulk(bulkRequest, DEFAULT); - - assertThat(response, successBulkResponse()); - assertThat(internalClient, not(clusterContainsDocument(WRITE_SONG_INDEX_NAME, "one"))); - assertThat(internalClient, not(clusterContainsDocument(WRITE_SONG_INDEX_NAME, "three"))); - assertThat( - internalClient, - clusterContainsDocumentWithFieldValue(WRITE_SONG_INDEX_NAME, "two", FIELD_TITLE, TITLE_SONG_1_PLUS_1) - ); - assertThat(internalClient, clusterContainsDocumentWithFieldValue(WRITE_SONG_INDEX_NAME, "four", FIELD_TITLE, TITLE_POISON)); - } - auditLogsRule.assertExactly(2, userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/_bulk")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateIndexRequest")); - auditLogsRule.assertExactly(4, grantedPrivilege(LIMITED_WRITE_USER, "PutMappingRequest")); - auditLogsRule.assertExactly(6, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_WRITE_USER)); - } - - @Test - public void shouldDeleteDocumentInBulk_partiallyPositive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - BulkRequest bulkRequest = new BulkRequest().setRefreshPolicy(IMMEDIATE); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("one").source(SONGS[0].asMap())); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("two").source(SONGS[1].asMap())); - assertThat(restHighLevelClient.bulk(bulkRequest, DEFAULT), successBulkResponse()); - bulkRequest = new BulkRequest().setRefreshPolicy(IMMEDIATE); - bulkRequest.add(new DeleteRequest(WRITE_SONG_INDEX_NAME, "one")); - bulkRequest.add(new DeleteRequest(SONG_INDEX_NAME, ID_S3)); - - BulkResponse response = restHighLevelClient.bulk(bulkRequest, DEFAULT); - assertThat(internalClient, not(clusterContainsDocument(WRITE_SONG_INDEX_NAME, "one"))); - - assertThat( - response, - bulkResponseContainExceptions(1, allOf(statusException(INTERNAL_SERVER_ERROR), errorMessageContain("security_exception"))) - ); - assertThat( - internalClient, - clusterContainsDocumentWithFieldValue(WRITE_SONG_INDEX_NAME, "two", FIELD_TITLE, TITLE_SONG_1_PLUS_1) - ); - assertThat(internalClient, clusterContainsDocumentWithFieldValue(SONG_INDEX_NAME, ID_S3, FIELD_TITLE, TITLE_NEXT_SONG)); - } - auditLogsRule.assertExactly(2, userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/_bulk")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateIndexRequest")); - auditLogsRule.assertExactly(4, grantedPrivilege(LIMITED_WRITE_USER, "PutMappingRequest")); - auditLogsRule.assertExactly(6, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_WRITE_USER)); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_WRITE_USER, "BulkShardRequest")); - } - - @Test - public void shouldDeleteDocumentInBulk_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - BulkRequest bulkRequest = new BulkRequest().setRefreshPolicy(IMMEDIATE); - bulkRequest.add(new DeleteRequest(SONG_INDEX_NAME, ID_S1)); - bulkRequest.add(new DeleteRequest(SONG_INDEX_NAME, ID_S3)); - - BulkResponse response = restHighLevelClient.bulk(bulkRequest, DEFAULT); - - assertThat( - response, - allOf( - failureBulkResponse(), - bulkResponseContainExceptions(statusException(INTERNAL_SERVER_ERROR)), - bulkResponseContainExceptions(errorMessageContain("security_exception")) - ) - ); - assertThat(internalClient, clusterContainsDocument(SONG_INDEX_NAME, ID_S1)); - assertThat(internalClient, clusterContainsDocument(SONG_INDEX_NAME, ID_S3)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/_bulk")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_WRITE_USER, "BulkShardRequest")); - - } - - @Test - public void shouldReindexDocuments_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(REINDEXING_USER)) { - ReindexRequest reindexRequest = new ReindexRequest().setSourceIndices(SONG_INDEX_NAME).setDestIndex(WRITE_SONG_INDEX_NAME); - - BulkByScrollResponse response = restHighLevelClient.reindex(reindexRequest, DEFAULT); - - assertThat(response, notNullValue()); - assertThat(response.getBulkFailures(), empty()); - assertThat(response.getSearchFailures(), empty()); - assertThat(internalClient, clusterContainsDocument(WRITE_SONG_INDEX_NAME, ID_S1)); - assertThat(internalClient, clusterContainsDocument(WRITE_SONG_INDEX_NAME, ID_S2)); - assertThat(internalClient, clusterContainsDocument(WRITE_SONG_INDEX_NAME, ID_S3)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(REINDEXING_USER).withRestRequest(POST, "/_reindex")); - auditLogsRule.assertExactlyOne(grantedPrivilege(REINDEXING_USER, "ReindexRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(REINDEXING_USER, "SearchRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(REINDEXING_USER, "BulkRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(REINDEXING_USER, "CreateIndexRequest")); - auditLogsRule.assertExactly(4, grantedPrivilege(REINDEXING_USER, "PutMappingRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(REINDEXING_USER, "SearchScrollRequest")); - auditLogsRule.assertExactly(6, auditPredicate(INDEX_EVENT).withEffectiveUser(REINDEXING_USER)); - auditLogsRule.assertExactlyOne(missingPrivilege(REINDEXING_USER, "ClearScrollRequest")); - } - - @Test - public void shouldReindexDocuments_negativeSource() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(REINDEXING_USER)) { - ReindexRequest reindexRequest = new ReindexRequest().setSourceIndices(PROHIBITED_SONG_INDEX_NAME) - .setDestIndex(WRITE_SONG_INDEX_NAME); - - assertThatThrownBy(() -> restHighLevelClient.reindex(reindexRequest, DEFAULT), statusException(FORBIDDEN)); - assertThat(internalClient, not(clusterContainsDocument(WRITE_SONG_INDEX_NAME, ID_P4))); - } - auditLogsRule.assertExactlyOne(userAuthenticated(REINDEXING_USER).withRestRequest(POST, "/_reindex")); - auditLogsRule.assertExactlyOne(grantedPrivilege(REINDEXING_USER, "ReindexRequest")); - auditLogsRule.assertExactlyOne(missingPrivilege(REINDEXING_USER, "SearchRequest")); - } - - @Test - public void shouldReindexDocuments_negativeDestination() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(REINDEXING_USER)) { - ReindexRequest reindexRequest = new ReindexRequest().setSourceIndices(SONG_INDEX_NAME).setDestIndex(PROHIBITED_SONG_INDEX_NAME); - - assertThatThrownBy(() -> restHighLevelClient.reindex(reindexRequest, DEFAULT), statusException(FORBIDDEN)); - assertThat(internalClient, not(clusterContainsDocument(PROHIBITED_SONG_INDEX_NAME, ID_S1))); - assertThat(internalClient, not(clusterContainsDocument(PROHIBITED_SONG_INDEX_NAME, ID_S2))); - assertThat(internalClient, not(clusterContainsDocument(PROHIBITED_SONG_INDEX_NAME, ID_S3))); - } - auditLogsRule.assertExactlyOne(userAuthenticated(REINDEXING_USER).withRestRequest(POST, "/_reindex")); - auditLogsRule.assertExactlyOne(grantedPrivilege(REINDEXING_USER, "ReindexRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(REINDEXING_USER, "SearchRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(REINDEXING_USER, "BulkRequest")); - auditLogsRule.assertExactlyOne(missingPrivilege(REINDEXING_USER, "BulkShardRequest")); - auditLogsRule.assertExactlyOne(missingPrivilege(REINDEXING_USER, "ClearScrollRequest")); - } - - @Test - public void shouldReindexDocuments_negativeSourceAndDestination() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(REINDEXING_USER)) { - ReindexRequest reindexRequest = new ReindexRequest().setSourceIndices(PROHIBITED_SONG_INDEX_NAME).setDestIndex(SONG_INDEX_NAME); - - assertThatThrownBy(() -> restHighLevelClient.reindex(reindexRequest, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(REINDEXING_USER).withRestRequest(POST, "/_reindex")); - auditLogsRule.assertExactlyOne(grantedPrivilege(REINDEXING_USER, "ReindexRequest")); - auditLogsRule.assertExactlyOne(missingPrivilege(REINDEXING_USER, "SearchRequest")); - } - - @Test - public void shouldUpdateDocument_positive() throws IOException { - String newField = "newField"; - String newValue = "newValue"; - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(UPDATE_DELETE_USER)) { - UpdateRequest updateRequest = new UpdateRequest(UPDATE_DELETE_OPERATION_INDEX_NAME, DOCUMENT_TO_UPDATE_ID).doc( - newField, - newValue - ).setRefreshPolicy(IMMEDIATE); - - UpdateResponse response = restHighLevelClient.update(updateRequest, DEFAULT); - - assertThat(response, isSuccessfulUpdateResponse()); - assertThat( - internalClient, - clusterContainsDocumentWithFieldValue(UPDATE_DELETE_OPERATION_INDEX_NAME, DOCUMENT_TO_UPDATE_ID, newField, newValue) - ); - } - } - - @Test - public void shouldUpdateDocument_negative() throws IOException { - String newField = "newField"; - String newValue = "newValue"; - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(UPDATE_DELETE_USER)) { - UpdateRequest updateRequest = new UpdateRequest(PROHIBITED_SONG_INDEX_NAME, DOCUMENT_TO_UPDATE_ID).doc(newField, newValue) - .setRefreshPolicy(IMMEDIATE); - - assertThatThrownBy(() -> restHighLevelClient.update(updateRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldDeleteDocument_positive() throws IOException { - String docId = "shouldDeleteDocument_positive"; - try (Client client = cluster.getInternalNodeClient()) { - client.index( - new IndexRequest(UPDATE_DELETE_OPERATION_INDEX_NAME).id(docId).source("field", "value").setRefreshPolicy(IMMEDIATE) - ).actionGet(); - assertThat(internalClient, clusterContainsDocument(UPDATE_DELETE_OPERATION_INDEX_NAME, docId)); - } - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(UPDATE_DELETE_USER)) { - DeleteRequest deleteRequest = new DeleteRequest(UPDATE_DELETE_OPERATION_INDEX_NAME, docId).setRefreshPolicy(IMMEDIATE); - - DeleteResponse response = restHighLevelClient.delete(deleteRequest, DEFAULT); - - assertThat(response, isSuccessfulDeleteResponse()); - assertThat(internalClient, not(clusterContainsDocument(UPDATE_DELETE_OPERATION_INDEX_NAME, docId))); - } - } - - @Test - public void shouldDeleteDocument_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(UPDATE_DELETE_USER)) { - DeleteRequest deleteRequest = new DeleteRequest(PROHIBITED_SONG_INDEX_NAME, ID_S1).setRefreshPolicy(IMMEDIATE); - - assertThatThrownBy(() -> restHighLevelClient.delete(deleteRequest, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldCreateAlias_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - AliasActions aliasAction = new AliasActions(ADD).indices(SONG_INDEX_NAME).alias(TEMPORARY_ALIAS_NAME); - IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest().addAliasAction(aliasAction); - - var response = restHighLevelClient.indices().updateAliases(indicesAliasesRequest, DEFAULT); - - assertThat(response, notNullValue()); - assertThat(response.isAcknowledged(), equalTo(true)); - assertThat(internalClient, clusterContainsDocument(TEMPORARY_ALIAS_NAME, ID_S1)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/_aliases")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_READ_USER, "IndicesAliasesRequest")); - auditLogsRule.assertExactly(2, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_READ_USER)); - } - - @Test - public void shouldCreateAlias_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - AliasActions aliasAction = new AliasActions(ADD).indices(PROHIBITED_SONG_INDEX_NAME).alias(TEMPORARY_ALIAS_NAME); - IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest().addAliasAction(aliasAction); - - assertThatThrownBy( - () -> restHighLevelClient.indices().updateAliases(indicesAliasesRequest, DEFAULT), - statusException(FORBIDDEN) - ); - - assertThat(internalClient, not(clusterContainsDocument(TEMPORARY_ALIAS_NAME, ID_P4))); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/_aliases")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "IndicesAliasesRequest")); - } - - @Test - public void shouldDeleteAlias_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - AliasActions aliasAction = new AliasActions(ADD).indices(SONG_INDEX_NAME).alias(TEMPORARY_ALIAS_NAME); - IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest().addAliasAction(aliasAction); - restHighLevelClient.indices().updateAliases(indicesAliasesRequest, DEFAULT); - aliasAction = new AliasActions(REMOVE).indices(SONG_INDEX_NAME).alias(TEMPORARY_ALIAS_NAME); - indicesAliasesRequest = new IndicesAliasesRequest().addAliasAction(aliasAction); - - var response = restHighLevelClient.indices().updateAliases(indicesAliasesRequest, DEFAULT); - - assertThat(response, notNullValue()); - assertThat(response.isAcknowledged(), equalTo(true)); - assertThat(internalClient, not(clusterContainsDocument(TEMPORARY_ALIAS_NAME, ID_S1))); - } - auditLogsRule.assertExactly(2, userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/_aliases")); - auditLogsRule.assertExactly(4, grantedPrivilege(LIMITED_READ_USER, "IndicesAliasesRequest")); - auditLogsRule.assertExactly(4, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_READ_USER)); - } - - @Test - public void shouldDeleteAlias_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - AliasActions aliasAction = new AliasActions(REMOVE).indices(PROHIBITED_SONG_INDEX_NAME).alias(PROHIBITED_SONG_ALIAS); - IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest().addAliasAction(aliasAction); - - assertThatThrownBy( - () -> restHighLevelClient.indices().updateAliases(indicesAliasesRequest, DEFAULT), - statusException(FORBIDDEN) - ); - - assertThat(internalClient, clusterContainsDocument(PROHIBITED_SONG_INDEX_NAME, ID_P4)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(POST, "/_aliases")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "IndicesAliasesRequest")); - } - - @Test - public void shouldCreateIndexTemplate_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - PutIndexTemplateRequest request = new PutIndexTemplateRequest(MUSICAL_INDEX_TEMPLATE).patterns(List.of(TEMPLATE_INDEX_PREFIX)) - .alias(new Alias(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0001)) - .alias(new Alias(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0002)); - - var response = restHighLevelClient.indices().putTemplate(request, DEFAULT); - - assertThat(response, notNullValue()); - assertThat(response.isAcknowledged(), equalTo(true)); - assertThat(internalClient, clusterContainTemplate(MUSICAL_INDEX_TEMPLATE)); - String documentId = "0001"; - IndexRequest indexRequest = new IndexRequest(INDEX_NAME_SONG_TRANSCRIPTION_JAZZ).id(documentId) - .source(SONGS[0].asMap()) - .setRefreshPolicy(IMMEDIATE); - restHighLevelClient.index(indexRequest, DEFAULT); - assertThat(internalClient, clusterContainsDocument(INDEX_NAME_SONG_TRANSCRIPTION_JAZZ, documentId)); - assertThat(internalClient, clusterContainsDocument(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0001, documentId)); - assertThat(internalClient, clusterContainsDocument(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0002, documentId)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_template/musical-index-template")); - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/song-transcription-jazz/_doc/0001")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "PutIndexTemplateRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "IndexRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateIndexRequest")); - auditLogsRule.assertAtLeast(2, grantedPrivilege(LIMITED_WRITE_USER, "PutMappingRequest")); - auditLogsRule.assertExactly(8, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_WRITE_USER)); - } - - @Test - public void shouldCreateIndexTemplate_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - PutIndexTemplateRequest request = new PutIndexTemplateRequest(MUSICAL_INDEX_TEMPLATE).patterns(List.of(TEMPLATE_INDEX_PREFIX)) - .alias(new Alias(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0001)) - .alias(new Alias(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0002)); - - assertThatThrownBy(() -> restHighLevelClient.indices().putTemplate(request, DEFAULT), statusException(FORBIDDEN)); - assertThat(internalClient, not(clusterContainTemplate(MUSICAL_INDEX_TEMPLATE))); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(PUT, "/_template/musical-index-template")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "PutIndexTemplateRequest")); - } - - @Test - public void shouldDeleteTemplate_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - PutIndexTemplateRequest request = new PutIndexTemplateRequest(MUSICAL_INDEX_TEMPLATE).patterns(List.of(TEMPLATE_INDEX_PREFIX)); - restHighLevelClient.indices().putTemplate(request, DEFAULT); - assertThat(internalClient, clusterContainTemplate(MUSICAL_INDEX_TEMPLATE)); - DeleteIndexTemplateRequest deleteRequest = new DeleteIndexTemplateRequest(MUSICAL_INDEX_TEMPLATE); - - var response = restHighLevelClient.indices().deleteTemplate(deleteRequest, DEFAULT); - - assertThat(response, notNullValue()); - assertThat(response.isAcknowledged(), equalTo(true)); - assertThat(internalClient, not(clusterContainTemplate(MUSICAL_INDEX_TEMPLATE))); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_template/musical-index-template")); - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(DELETE, "/_template/musical-index-template")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "PutIndexTemplateRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "DeleteIndexTemplateRequest")); - auditLogsRule.assertExactly(4, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_WRITE_USER)); - } - - @Test - public void shouldDeleteTemplate_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - DeleteIndexTemplateRequest deleteRequest = new DeleteIndexTemplateRequest(UNDELETABLE_TEMPLATE_NAME); - - assertThatThrownBy(() -> restHighLevelClient.indices().deleteTemplate(deleteRequest, DEFAULT), statusException(FORBIDDEN)); - - assertThat(internalClient, clusterContainTemplate(UNDELETABLE_TEMPLATE_NAME)); - } - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_READ_USER).withRestRequest(DELETE, "/_template/undeletable-template-name") - ); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "DeleteIndexTemplateRequest")); - } - - @Test - public void shouldUpdateTemplate_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - PutIndexTemplateRequest request = new PutIndexTemplateRequest(MUSICAL_INDEX_TEMPLATE).patterns(List.of(TEMPLATE_INDEX_PREFIX)) - .alias(new Alias(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0001)) - .alias(new Alias(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0002)); - restHighLevelClient.indices().putTemplate(request, DEFAULT); - assertThat(internalClient, clusterContainTemplate(MUSICAL_INDEX_TEMPLATE)); - request = new PutIndexTemplateRequest(MUSICAL_INDEX_TEMPLATE).patterns(List.of(TEMPLATE_INDEX_PREFIX)) - .alias(new Alias(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0003)); - - var response = restHighLevelClient.indices().putTemplate(request, DEFAULT); - - assertThat(response, notNullValue()); - assertThat(response.isAcknowledged(), equalTo(true)); - String documentId = "000one"; - IndexRequest indexRequest = new IndexRequest(INDEX_NAME_SONG_TRANSCRIPTION_JAZZ).id(documentId) - .source(SONGS[0].asMap()) - .setRefreshPolicy(IMMEDIATE); - restHighLevelClient.index(indexRequest, DEFAULT); - assertThat(internalClient, clusterContainTemplate(MUSICAL_INDEX_TEMPLATE)); - assertThat(internalClient, clusterContainsDocument(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0003, documentId)); - assertThat(internalClient, not(clusterContainsDocument(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0001, documentId))); - assertThat(internalClient, not(clusterContainsDocument(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0002, documentId))); - } - auditLogsRule.assertExactly(2, userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_template/musical-index-template")); - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/song-transcription-jazz/_doc/000one")); - auditLogsRule.assertExactly(4, grantedPrivilege(LIMITED_WRITE_USER, "PutIndexTemplateRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "IndexRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateIndexRequest")); - auditLogsRule.assertExactly(4, grantedPrivilege(LIMITED_WRITE_USER, "PutMappingRequest")); - auditLogsRule.assertExactly(10, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_WRITE_USER)); - } - - @Test - public void shouldUpdateTemplate_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - PutIndexTemplateRequest request = new PutIndexTemplateRequest(UNDELETABLE_TEMPLATE_NAME).patterns( - List.of(TEMPLATE_INDEX_PREFIX) - ).alias(new Alias(ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0003)); - - assertThatThrownBy(() -> restHighLevelClient.indices().putTemplate(request, DEFAULT), statusException(FORBIDDEN)); - assertThat(internalClient, clusterContainTemplateWithAlias(UNDELETABLE_TEMPLATE_NAME, ALIAS_FROM_UNDELETABLE_TEMPLATE)); - assertThat( - internalClient, - not(clusterContainTemplateWithAlias(UNDELETABLE_TEMPLATE_NAME, ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0003)) - ); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(PUT, "/_template/undeletable-template-name")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "PutIndexTemplateRequest")); - } - - @Test - public void shouldGetFieldCapabilitiesForAllIndexes_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(ADMIN_USER)) { - FieldCapabilitiesRequest request = new FieldCapabilitiesRequest().fields(FIELD_TITLE); - - FieldCapabilitiesResponse response = restHighLevelClient.fieldCaps(request, DEFAULT); - - assertThat(response, notNullValue()); - assertThat(response, containsExactlyIndices(SONG_INDEX_NAME, PROHIBITED_SONG_INDEX_NAME, UPDATE_DELETE_OPERATION_INDEX_NAME)); - assertThat(response, numberOfFieldsIsEqualTo(1)); - assertThat(response, containsFieldWithNameAndType(FIELD_TITLE, "text")); - } - auditLogsRule.assertExactlyOne(userAuthenticated(ADMIN_USER).withRestRequest(GET, "/_field_caps")); - auditLogsRule.assertExactlyOne(grantedPrivilege(ADMIN_USER, "FieldCapabilitiesRequest")); - auditLogsRule.assertExactly(3, grantedPrivilege(ADMIN_USER, "FieldCapabilitiesIndexRequest")); - } - - @Test - public void shouldGetFieldCapabilitiesForAllIndexes_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - FieldCapabilitiesRequest request = new FieldCapabilitiesRequest().fields(FIELD_TITLE); - - assertThatThrownBy(() -> restHighLevelClient.fieldCaps(request, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(GET, "/_field_caps")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "FieldCapabilitiesRequest")); - } - - @Test - public void shouldGetFieldCapabilitiesForParticularIndex_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - FieldCapabilitiesRequest request = new FieldCapabilitiesRequest().indices(SONG_INDEX_NAME).fields(FIELD_TITLE); - - FieldCapabilitiesResponse response = restHighLevelClient.fieldCaps(request, DEFAULT); - - assertThat(response, notNullValue()); - assertThat(response, containsExactlyIndices(SONG_INDEX_NAME)); - assertThat(response, numberOfFieldsIsEqualTo(1)); - assertThat(response, containsFieldWithNameAndType(FIELD_TITLE, "text")); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(GET, "/song_lyrics/_field_caps")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "FieldCapabilitiesRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_READ_USER, "FieldCapabilitiesIndexRequest")); - } - - @Test - public void shouldGetFieldCapabilitiesForParticularIndex_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - FieldCapabilitiesRequest request = new FieldCapabilitiesRequest().indices(PROHIBITED_SONG_INDEX_NAME).fields(FIELD_TITLE); - - assertThatThrownBy(() -> restHighLevelClient.fieldCaps(request, DEFAULT), statusException(FORBIDDEN)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(GET, "/prohibited_song_lyrics/_field_caps")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "FieldCapabilitiesRequest")); - } - - @Test - public void shouldCreateSnapshotRepository_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - String snapshotDirPath = cluster.getSnapshotDirPath(); - - var response = steps.createSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotDirPath, "fs"); - - assertThat(response, notNullValue()); - assertThat(response.isAcknowledged(), equalTo(true)); - assertThat(internalClient, clusterContainsSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "PutRepositoryRequest")); - } - - @Test - public void shouldCreateSnapshotRepository_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - String snapshotDirPath = cluster.getSnapshotDirPath(); - - assertThatThrownBy( - () -> steps.createSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotDirPath, "fs"), - statusException(FORBIDDEN) - ); - assertThat(internalClient, not(clusterContainsSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME))); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_READ_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository")); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "PutRepositoryRequest")); - } - - @Test - public void shouldDeleteSnapshotRepository_positive() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - steps.createSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME, cluster.getSnapshotDirPath(), "fs"); - assertThat(internalClient, clusterContainsSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME)); - - var response = steps.deleteSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME); - - assertThat(response, notNullValue()); - assertThat(response.isAcknowledged(), equalTo(true)); - assertThat(internalClient, not(clusterContainsSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME))); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository")); - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_WRITE_USER).withRestRequest(DELETE, "/_snapshot/test-snapshot-repository") - ); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "PutRepositoryRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "DeleteRepositoryRequest")); - } - - @Test - public void shouldDeleteSnapshotRepository_negative() throws IOException { - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - - assertThatThrownBy(() -> steps.deleteSnapshotRepository(UNUSED_SNAPSHOT_REPOSITORY_NAME), statusException(FORBIDDEN)); - assertThat(internalClient, clusterContainsSnapshotRepository(UNUSED_SNAPSHOT_REPOSITORY_NAME)); - } - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_READ_USER).withRestRequest(DELETE, "/_snapshot/unused-snapshot-repository") - ); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "DeleteRepositoryRequest")); - } - - @Test // Bug which can be reproduced with the below test: https://github.com/opensearch-project/security/issues/2169 - public void shouldCreateSnapshot_positive() throws IOException { - final String snapshotName = "snapshot-positive-test"; - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - steps.createSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME, cluster.getSnapshotDirPath(), "fs"); - - CreateSnapshotResponse response = steps.createSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName, SONG_INDEX_NAME); - - assertThat(response, notNullValue()); - assertThat(response.status(), equalTo(RestStatus.ACCEPTED)); - steps.waitForSnapshotCreation(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName); - assertThat(internalClient, clusterContainSuccessSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository")); - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository/snapshot-positive-test") - ); - auditLogsRule.assertAtLeast( - 1, - userAuthenticated(LIMITED_WRITE_USER).withRestRequest(GET, "/_snapshot/test-snapshot-repository/snapshot-positive-test") - ); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "PutRepositoryRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateSnapshotRequest")); - auditLogsRule.assertAtLeast(2, grantedPrivilege(LIMITED_WRITE_USER, "GetSnapshotsRequest")); - } - - @Test - public void shouldCreateSnapshot_negative() throws IOException { - final String snapshotName = "snapshot-negative-test"; - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - - assertThatThrownBy( - () -> steps.createSnapshot(UNUSED_SNAPSHOT_REPOSITORY_NAME, snapshotName, SONG_INDEX_NAME), - statusException(FORBIDDEN) - ); - - assertThat(internalClient, snapshotInClusterDoesNotExists(UNUSED_SNAPSHOT_REPOSITORY_NAME, snapshotName)); - } - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_READ_USER).withRestRequest(PUT, "/_snapshot/unused-snapshot-repository/snapshot-negative-test") - ); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_READ_USER, "CreateSnapshotRequest")); - } - - @Test - public void shouldDeleteSnapshot_positive() throws IOException { - String snapshotName = "delete-snapshot-positive"; - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - restHighLevelClient.snapshot(); - steps.createSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME, cluster.getSnapshotDirPath(), "fs"); - steps.createSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName, SONG_INDEX_NAME); - steps.waitForSnapshotCreation(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName); - - var response = steps.deleteSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName); - - assertThat(response.isAcknowledged(), equalTo(true)); - assertThat(internalClient, snapshotInClusterDoesNotExists(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository")); - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository/delete-snapshot-positive") - ); - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_WRITE_USER).withRestRequest(DELETE, "/_snapshot/test-snapshot-repository/delete-snapshot-positive") - ); - auditLogsRule.assertAtLeast( - 1, - userAuthenticated(LIMITED_WRITE_USER).withRestRequest(GET, "/_snapshot/test-snapshot-repository/delete-snapshot-positive") - ); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "PutRepositoryRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateSnapshotRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "DeleteSnapshotRequest")); - auditLogsRule.assertAtLeast(2, grantedPrivilege(LIMITED_WRITE_USER, "GetSnapshotsRequest")); - } - - @Test - public void shouldDeleteSnapshot_negative() throws IOException { - String snapshotName = "delete-snapshot-negative"; - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - steps.createSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME, cluster.getSnapshotDirPath(), "fs"); - steps.createSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName, SONG_INDEX_NAME); - steps.waitForSnapshotCreation(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName); - } - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - assertThatThrownBy(() -> steps.deleteSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName), statusException(FORBIDDEN)); - - assertThat(internalClient, clusterContainSuccessSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName)); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository")); - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository/delete-snapshot-negative") - ); - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_READ_USER).withRestRequest(DELETE, "/_snapshot/test-snapshot-repository/delete-snapshot-negative") - ); - auditLogsRule.assertAtLeast( - 1, - userAuthenticated(LIMITED_WRITE_USER).withRestRequest(GET, "/_snapshot/test-snapshot-repository/delete-snapshot-negative") - ); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "PutRepositoryRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateSnapshotRequest")); - auditLogsRule.assertExactly(1, missingPrivilege(LIMITED_READ_USER, "DeleteSnapshotRequest")); - auditLogsRule.assertAtLeast(2, grantedPrivilege(LIMITED_WRITE_USER, "GetSnapshotsRequest")); - } - - @Test - public void shouldRestoreSnapshot_positive() throws IOException { - final String snapshotName = "restore-snapshot-positive"; - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - // 1. create some documents - BulkRequest bulkRequest = new BulkRequest(); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("Eins").source(SONGS[0].asMap())); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("Zwei").source(SONGS[1].asMap())); - bulkRequest.setRefreshPolicy(IMMEDIATE); - restHighLevelClient.bulk(bulkRequest, DEFAULT); - - // 2. create snapshot repository - steps.createSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME, cluster.getSnapshotDirPath(), "fs"); - - // 3. create snapshot - steps.createSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName, WRITE_SONG_INDEX_NAME); - - // 4. wait till snapshot is ready - steps.waitForSnapshotCreation(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName); - - // 5. introduce some changes - bulkRequest = new BulkRequest(); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("Drei").source(SONGS[2].asMap())); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("Vier").source(SONGS[3].asMap())); - bulkRequest.add(new DeleteRequest(WRITE_SONG_INDEX_NAME, "Eins")); - bulkRequest.setRefreshPolicy(IMMEDIATE); - restHighLevelClient.bulk(bulkRequest, DEFAULT); - - // 6. restore the snapshot - var response = steps.restoreSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName, "(.+)", "restored_$1"); - - assertThat(response, notNullValue()); - assertThat(response.status(), equalTo(ACCEPTED)); - - // 7. wait until snapshot is restored - CountRequest countRequest = new CountRequest(RESTORED_SONG_INDEX_NAME); - Awaitility.await() - .ignoreExceptions() - .alias("Index contains proper number of documents restored from snapshot.") - .until(() -> restHighLevelClient.count(countRequest, DEFAULT).getCount() == 2); - - // 8. verify that document are present in restored index - assertThat( - internalClient, - clusterContainsDocumentWithFieldValue(RESTORED_SONG_INDEX_NAME, "Eins", FIELD_TITLE, TITLE_MAGNUM_OPUS) - ); - assertThat( - internalClient, - clusterContainsDocumentWithFieldValue(RESTORED_SONG_INDEX_NAME, "Zwei", FIELD_TITLE, TITLE_SONG_1_PLUS_1) - ); - assertThat(internalClient, not(clusterContainsDocument(RESTORED_SONG_INDEX_NAME, "Drei"))); - assertThat(internalClient, not(clusterContainsDocument(RESTORED_SONG_INDEX_NAME, "Vier"))); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository")); - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository/restore-snapshot-positive") - ); - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_WRITE_USER).withRestRequest( - POST, - "/_snapshot/test-snapshot-repository/restore-snapshot-positive/_restore" - ) - ); - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/restored_write_song_index/_count")); - auditLogsRule.assertExactly(2, userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/_bulk")); - auditLogsRule.assertAtLeast( - 1, - userAuthenticated(LIMITED_WRITE_USER).withRestRequest(GET, "/_snapshot/test-snapshot-repository/restore-snapshot-positive") - ); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "PutRepositoryRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateSnapshotRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateIndexRequest")); - auditLogsRule.assertExactly(4, grantedPrivilege(LIMITED_WRITE_USER, "PutMappingRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "RestoreSnapshotRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "SearchRequest")); - auditLogsRule.assertAtLeast(2, grantedPrivilege(LIMITED_WRITE_USER, "GetSnapshotsRequest")); - auditLogsRule.assertExactly(6, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_WRITE_USER)); - } - - @Test - public void shouldRestoreSnapshot_failureForbiddenIndex() throws IOException { - final String snapshotName = "restore-snapshot-negative-forbidden-index"; - String restoreToIndex = "forbidden_index"; - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - // 1. create some documents - BulkRequest bulkRequest = new BulkRequest(); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("Eins").source(SONGS[0].asMap())); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("Zwei").source(SONGS[1].asMap())); - bulkRequest.setRefreshPolicy(IMMEDIATE); - restHighLevelClient.bulk(bulkRequest, DEFAULT); - - // 2. create snapshot repository - steps.createSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME, cluster.getSnapshotDirPath(), "fs"); - - // 3. create snapshot - steps.createSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName, WRITE_SONG_INDEX_NAME); - - // 4. wait till snapshot is ready - steps.waitForSnapshotCreation(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName); - - // 5. restore the snapshot - assertThatThrownBy( - () -> steps.restoreSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName, "(.+)", restoreToIndex), - statusException(FORBIDDEN) - ); - - // 6. verify that document are not present in restored index - assertThat(internalClient, not(clusterContainsDocument(RESTORED_SONG_INDEX_NAME, "Eins"))); - assertThat(internalClient, not(clusterContainsDocument(RESTORED_SONG_INDEX_NAME, "Zwei"))); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository")); - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_WRITE_USER).withRestRequest( - PUT, - "/_snapshot/test-snapshot-repository/restore-snapshot-negative-forbidden-index" - ) - ); - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_WRITE_USER).withRestRequest( - POST, - "/_snapshot/test-snapshot-repository/restore-snapshot-negative-forbidden-index/_restore" - ) - ); - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/_bulk")); - auditLogsRule.assertAtLeast( - 1, - userAuthenticated(LIMITED_WRITE_USER).withRestRequest( - GET, - "/_snapshot/test-snapshot-repository/restore-snapshot-negative-forbidden-index" - ) - ); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "PutRepositoryRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateSnapshotRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateIndexRequest")); - auditLogsRule.assertExactly(4, grantedPrivilege(LIMITED_WRITE_USER, "PutMappingRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "RestoreSnapshotRequest")); - auditLogsRule.assertAtLeast(2, grantedPrivilege(LIMITED_WRITE_USER, "GetSnapshotsRequest")); - auditLogsRule.assertExactly(6, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_WRITE_USER)); - auditLogsRule.assertExactlyOne(missingPrivilege(LIMITED_WRITE_USER, "RestoreSnapshotRequest")); - } - - @Test - public void shouldRestoreSnapshot_failureOperationForbidden() throws IOException { - String snapshotName = "restore-snapshot-negative-forbidden-operation"; - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_WRITE_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - // 1. create some documents - BulkRequest bulkRequest = new BulkRequest(); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("Eins").source(SONGS[0].asMap())); - bulkRequest.add(new IndexRequest(WRITE_SONG_INDEX_NAME).id("Zwei").source(SONGS[1].asMap())); - bulkRequest.setRefreshPolicy(IMMEDIATE); - restHighLevelClient.bulk(bulkRequest, DEFAULT); - - // 2. create snapshot repository - steps.createSnapshotRepository(TEST_SNAPSHOT_REPOSITORY_NAME, cluster.getSnapshotDirPath(), "fs"); - - // 3. create snapshot - steps.createSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName, WRITE_SONG_INDEX_NAME); - - // 4. wait till snapshot is ready - steps.waitForSnapshotCreation(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName); - } - // 5. restore the snapshot - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_READ_USER)) { - SnapshotSteps steps = new SnapshotSteps(restHighLevelClient); - assertThatThrownBy( - () -> steps.restoreSnapshot(TEST_SNAPSHOT_REPOSITORY_NAME, snapshotName, "(.+)", "restored_$1"), - statusException(FORBIDDEN) - ); - - // 6. verify that documents does not exist - assertThat(internalClient, not(clusterContainsDocument(RESTORED_SONG_INDEX_NAME, "Eins"))); - assertThat(internalClient, not(clusterContainsDocument(RESTORED_SONG_INDEX_NAME, "Zwei"))); - } - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(PUT, "/_snapshot/test-snapshot-repository")); - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_WRITE_USER).withRestRequest( - PUT, - "/_snapshot/test-snapshot-repository/restore-snapshot-negative-forbidden-operation" - ) - ); - auditLogsRule.assertExactlyOne( - userAuthenticated(LIMITED_READ_USER).withRestRequest( - POST, - "/_snapshot/test-snapshot-repository/restore-snapshot-negative-forbidden-operation/_restore" - ) - ); - auditLogsRule.assertExactlyOne(userAuthenticated(LIMITED_WRITE_USER).withRestRequest(POST, "/_bulk")); - auditLogsRule.assertAtLeast( - 1, - userAuthenticated(LIMITED_WRITE_USER).withRestRequest( - GET, - "/_snapshot/test-snapshot-repository/restore-snapshot-negative-forbidden-operation" - ) - ); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "PutRepositoryRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateSnapshotRequest")); - auditLogsRule.assertExactlyOne(grantedPrivilege(LIMITED_WRITE_USER, "BulkRequest")); - auditLogsRule.assertExactly(2, grantedPrivilege(LIMITED_WRITE_USER, "CreateIndexRequest")); - auditLogsRule.assertExactly(4, grantedPrivilege(LIMITED_WRITE_USER, "PutMappingRequest")); - auditLogsRule.assertExactly(1, missingPrivilege(LIMITED_READ_USER, "RestoreSnapshotRequest")); - auditLogsRule.assertAtLeast(2, grantedPrivilege(LIMITED_WRITE_USER, "GetSnapshotsRequest")); - auditLogsRule.assertExactly(6, auditPredicate(INDEX_EVENT).withEffectiveUser(LIMITED_WRITE_USER)); - } - - @Test - // required permissions: "indices:admin/create" - public void createIndex_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("create_index_positive"); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName); - CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, DEFAULT); - - assertThat(createIndexResponse, isSuccessfulCreateIndexResponse(indexName)); - assertThat(cluster, indexExists(indexName)); - } - } - - @Test - public void createIndex_negative() throws IOException { - String indexName = "create_index_negative"; - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName); - - assertThatThrownBy(() -> restHighLevelClient.indices().create(createIndexRequest, DEFAULT), statusException(FORBIDDEN)); - assertThat(cluster, not(indexExists(indexName))); - } - } - - @Test - // required permissions: "indices:admin/get" - public void checkIfIndexExists_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("index_exists_positive"); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - boolean exists = restHighLevelClient.indices().exists(new GetIndexRequest(indexName), DEFAULT); - - assertThat(exists, is(false)); - } - } - - @Test - public void checkIfIndexExists_negative() throws IOException { - String indexThatUserHasNoAccessTo = "index_exists_negative"; - String indexThatUserHasAccessTo = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat(indexThatUserHasNoAccessTo); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - assertThatThrownBy( - () -> restHighLevelClient.indices().exists(new GetIndexRequest(indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices() - .exists(new GetIndexRequest(indexThatUserHasAccessTo, indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy(() -> restHighLevelClient.indices().exists(new GetIndexRequest("*"), DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - // required permissions: "indices:admin/delete" - public void deleteIndex_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("delete_index_positive"); - IndexOperationsHelper.createIndex(cluster, indexName); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName); - var response = restHighLevelClient.indices().delete(deleteIndexRequest, DEFAULT); - - assertThat(response.isAcknowledged(), is(true)); - assertThat(cluster, not(indexExists(indexName))); - } - } - - @Test - public void deleteIndex_negative() throws IOException { - String indexThatUserHasNoAccessTo = "delete_index_negative"; - String indexThatUserHasAccessTo = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat(indexThatUserHasNoAccessTo); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - - assertThatThrownBy( - () -> restHighLevelClient.indices().delete(new DeleteIndexRequest(indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices() - .delete(new DeleteIndexRequest(indexThatUserHasAccessTo, indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices().delete(new DeleteIndexRequest("*"), DEFAULT), - statusException(FORBIDDEN) - ); - } - } - - @Test - // required permissions: indices:admin/aliases, indices:admin/delete - public void shouldDeleteIndexByAliasRequest_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("delete_index_by_alias_request_positive"); - IndexOperationsHelper.createIndex(cluster, indexName); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - IndicesAliasesRequest request = new IndicesAliasesRequest().addAliasAction(new AliasActions(REMOVE_INDEX).indices(indexName)); - - var response = restHighLevelClient.indices().updateAliases(request, DEFAULT); - - assertThat(response.isAcknowledged(), is(true)); - assertThat(cluster, not(indexExists(indexName))); - } - auditLogsRule.assertExactlyOne( - userAuthenticated(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES).withRestRequest(POST, "/_aliases") - ); - auditLogsRule.assertExactly( - 2, - grantedPrivilege(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES, "IndicesAliasesRequest") - ); - auditLogsRule.assertExactly( - 2, - auditPredicate(INDEX_EVENT).withEffectiveUser(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES) - ); - } - - @Test - public void shouldDeleteIndexByAliasRequest_negative() throws IOException { - String indexName = "delete_index_by_alias_request_negative"; - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - IndicesAliasesRequest request = new IndicesAliasesRequest().addAliasAction(new AliasActions(REMOVE_INDEX).indices(indexName)); - - assertThatThrownBy(() -> restHighLevelClient.indices().updateAliases(request, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - // required permissions: "indices:admin/get" - public void getIndex_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("get_index_positive"); - IndexOperationsHelper.createIndex(cluster, indexName); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - GetIndexRequest getIndexRequest = new GetIndexRequest(indexName); - GetIndexResponse response = restHighLevelClient.indices().get(getIndexRequest, DEFAULT); - - assertThat(response, getIndexResponseContainsIndices(indexName)); - } - } - - @Test - public void getIndex_negative() throws IOException { - String indexThatUserHasNoAccessTo = "get_index_negative"; - String indexThatUserHasAccessTo = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat(indexThatUserHasNoAccessTo); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - - assertThatThrownBy( - () -> restHighLevelClient.indices().get(new GetIndexRequest(indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices().get(new GetIndexRequest(indexThatUserHasAccessTo, indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy(() -> restHighLevelClient.indices().get(new GetIndexRequest("*"), DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - // required permissions: "indices:admin/close", "indices:admin/close*" - public void closeIndex_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("close_index_positive"); - IndexOperationsHelper.createIndex(cluster, indexName); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - CloseIndexRequest closeIndexRequest = new CloseIndexRequest(indexName); - CloseIndexResponse response = restHighLevelClient.indices().close(closeIndexRequest, DEFAULT); - - assertThat(response, isSuccessfulCloseIndexResponse()); - assertThat(cluster, indexStateIsEqualTo(indexName, IndexMetadata.State.CLOSE)); - } - } - - @Test - public void closeIndex_negative() throws IOException { - String indexThatUserHasNoAccessTo = "close_index_negative"; - String indexThatUserHasAccessTo = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat(indexThatUserHasNoAccessTo); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - - assertThatThrownBy( - () -> restHighLevelClient.indices().close(new CloseIndexRequest(indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices() - .close(new CloseIndexRequest(indexThatUserHasAccessTo, indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy(() -> restHighLevelClient.indices().close(new CloseIndexRequest("*"), DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - // required permissions: "indices:admin/open" - public void openIndex_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("open_index_positive"); - IndexOperationsHelper.createIndex(cluster, indexName); - IndexOperationsHelper.closeIndex(cluster, indexName); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - OpenIndexRequest closeIndexRequest = new OpenIndexRequest(indexName); - OpenIndexResponse response = restHighLevelClient.indices().open(closeIndexRequest, DEFAULT); - - assertThat(response, isSuccessfulOpenIndexResponse()); - assertThat(cluster, indexStateIsEqualTo(indexName, IndexMetadata.State.OPEN)); - } - } - - @Test - public void openIndex_negative() throws IOException { - String indexThatUserHasNoAccessTo = "open_index_negative"; - String indexThatUserHasAccessTo = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat(indexThatUserHasNoAccessTo); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - - assertThatThrownBy( - () -> restHighLevelClient.indices().open(new OpenIndexRequest(indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices() - .open(new OpenIndexRequest(indexThatUserHasAccessTo, indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy(() -> restHighLevelClient.indices().open(new OpenIndexRequest("*"), DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - @Ignore - // required permissions: "indices:admin/resize", "indices:monitor/stats - // todo even when I assign the `indices:admin/resize` and `indices:monitor/stats` permissions to test user, this test fails. - // Issue: https://github.com/opensearch-project/security/issues/2141 - public void shrinkIndex_positive() throws IOException { - String sourceIndexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("shrink_index_positive_source"); - Settings sourceIndexSettings = Settings.builder().put("index.blocks.write", true).put("index.number_of_shards", 2).build(); - String targetIndexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("shrink_index_positive_target"); - IndexOperationsHelper.createIndex(cluster, sourceIndexName, sourceIndexSettings); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - ResizeRequest resizeRequest = new ResizeRequest(targetIndexName, sourceIndexName); - ResizeResponse response = restHighLevelClient.indices().shrink(resizeRequest, DEFAULT); - - assertThat(response, isSuccessfulResizeResponse(targetIndexName)); - assertThat(cluster, indexExists(targetIndexName)); - } - } - - @Test - public void shrinkIndex_negative() throws IOException { - // user cannot access target index - String sourceIndexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("shrink_index_negative_source"); - String targetIndexName = "shrink_index_negative_target"; - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - ResizeRequest resizeRequest = new ResizeRequest(targetIndexName, sourceIndexName); - - assertThatThrownBy(() -> restHighLevelClient.indices().shrink(resizeRequest, DEFAULT), statusException(FORBIDDEN)); - assertThat(cluster, not(indexExists(targetIndexName))); - } - - // user cannot access source index - sourceIndexName = "shrink_index_negative_source"; - targetIndexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("shrink_index_negative_target"); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - ResizeRequest resizeRequest = new ResizeRequest(targetIndexName, sourceIndexName); - - assertThatThrownBy(() -> restHighLevelClient.indices().shrink(resizeRequest, DEFAULT), statusException(FORBIDDEN)); - assertThat(cluster, not(indexExists(targetIndexName))); - } - } - - @Test - @Ignore - // required permissions: "indices:admin/resize", "indices:monitor/stats - // todo even when I assign the `indices:admin/resize` and `indices:monitor/stats` permissions to test user, this test fails. - // Issue: https://github.com/opensearch-project/security/issues/2141 - public void cloneIndex_positive() throws IOException { - String sourceIndexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("clone_index_positive_source"); - Settings sourceIndexSettings = Settings.builder().put("index.blocks.write", true).build(); - String targetIndexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("clone_index_positive_target"); - IndexOperationsHelper.createIndex(cluster, sourceIndexName, sourceIndexSettings); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - ResizeRequest resizeRequest = new ResizeRequest(targetIndexName, sourceIndexName); - ResizeResponse response = restHighLevelClient.indices().clone(resizeRequest, DEFAULT); - - assertThat(response, isSuccessfulResizeResponse(targetIndexName)); - assertThat(cluster, indexExists(targetIndexName)); - } - } - - @Test - public void cloneIndex_negative() throws IOException { - // user cannot access target index - String sourceIndexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("clone_index_negative_source"); - String targetIndexName = "clone_index_negative_target"; - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - ResizeRequest resizeRequest = new ResizeRequest(targetIndexName, sourceIndexName); - - assertThatThrownBy(() -> restHighLevelClient.indices().clone(resizeRequest, DEFAULT), statusException(FORBIDDEN)); - assertThat(cluster, not(indexExists(targetIndexName))); - } - - // user cannot access source index - sourceIndexName = "clone_index_negative_source"; - targetIndexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("clone_index_negative_target"); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - ResizeRequest resizeRequest = new ResizeRequest(targetIndexName, sourceIndexName); - - assertThatThrownBy(() -> restHighLevelClient.indices().clone(resizeRequest, DEFAULT), statusException(FORBIDDEN)); - assertThat(cluster, not(indexExists(targetIndexName))); - } - } - - @Test - @Ignore - // required permissions: "indices:admin/resize", "indices:monitor/stats - // todo even when I assign the `indices:admin/resize` and `indices:monitor/stats` permissions to test user, this test fails. - // Issue: https://github.com/opensearch-project/security/issues/2141 - public void splitIndex_positive() throws IOException { - String sourceIndexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("split_index_positive_source"); - Settings sourceIndexSettings = Settings.builder().put("index.blocks.write", true).build(); - String targetIndexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("split_index_positive_target"); - IndexOperationsHelper.createIndex(cluster, sourceIndexName, sourceIndexSettings); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - ResizeRequest resizeRequest = new ResizeRequest(targetIndexName, sourceIndexName); - resizeRequest.setSettings(Settings.builder().put("index.number_of_shards", 2).build()); - ResizeResponse response = restHighLevelClient.indices().split(resizeRequest, DEFAULT); - - assertThat(response, isSuccessfulResizeResponse(targetIndexName)); - assertThat(cluster, indexExists(targetIndexName)); - } - } - - @Test - public void splitIndex_negative() throws IOException { - // user cannot access target index - String sourceIndexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("split_index_negative_source"); - String targetIndexName = "split_index_negative_target"; - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - ResizeRequest resizeRequest = new ResizeRequest(targetIndexName, sourceIndexName); - resizeRequest.setSettings(Settings.builder().put("index.number_of_shards", 2).build()); - - assertThatThrownBy(() -> restHighLevelClient.indices().split(resizeRequest, DEFAULT), statusException(FORBIDDEN)); - assertThat(cluster, not(indexExists(targetIndexName))); - } - - // user cannot access source index - sourceIndexName = "split_index_negative_source"; - targetIndexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("split_index_negative_target"); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - ResizeRequest resizeRequest = new ResizeRequest(targetIndexName, sourceIndexName); - resizeRequest.setSettings(Settings.builder().put("index.number_of_shards", 2).build()); - - assertThatThrownBy(() -> restHighLevelClient.indices().split(resizeRequest, DEFAULT), statusException(FORBIDDEN)); - assertThat(cluster, not(indexExists(targetIndexName))); - } - } - - @Test - // required permissions: "indices:monitor/settings/get" - public void getIndexSettings_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("get_index_settings_positive"); - IndexOperationsHelper.createIndex(cluster, indexName); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - GetSettingsRequest getSettingsRequest = new GetSettingsRequest().indices(indexName); - GetSettingsResponse response = restHighLevelClient.indices().getSettings(getSettingsRequest, DEFAULT); - - assertThat(response, getSettingsResponseContainsIndices(indexName)); - } - } - - @Test - public void getIndexSettings_negative() throws IOException { - String indexThatUserHasNoAccessTo = "get_index_settings_negative"; - String indexThatUserHasAccessTo = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat(indexThatUserHasNoAccessTo); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - assertThatThrownBy( - () -> restHighLevelClient.indices().getSettings(new GetSettingsRequest().indices(indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices() - .getSettings(new GetSettingsRequest().indices(indexThatUserHasAccessTo, indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices().getSettings(new GetSettingsRequest().indices("*"), DEFAULT), - statusException(FORBIDDEN) - ); - } - } - - @Test - // required permissions: "indices:admin/settings/update" - public void updateIndexSettings_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("update_index_settings_positive"); - Settings initialSettings = Settings.builder().put("index.number_of_replicas", "2").build(); - Settings updatedSettings = Settings.builder().put("index.number_of_replicas", "4").build(); - IndexOperationsHelper.createIndex(cluster, indexName, initialSettings); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - UpdateSettingsRequest updateSettingsRequest = new UpdateSettingsRequest(indexName).settings(updatedSettings); - var response = restHighLevelClient.indices().putSettings(updateSettingsRequest, DEFAULT); - - assertThat(response.isAcknowledged(), is(true)); - assertThat(cluster, indexSettingsContainValues(indexName, updatedSettings)); - } - } - - @Test - public void updateIndexSettings_negative() throws IOException { - String indexThatUserHasNoAccessTo = "update_index_settings_negative"; - String indexThatUserHasAccessTo = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat(indexThatUserHasNoAccessTo); - Settings settingsToUpdate = Settings.builder().put("index.number_of_replicas", 2).build(); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - - assertThatThrownBy( - () -> restHighLevelClient.indices() - .putSettings(new UpdateSettingsRequest(indexThatUserHasNoAccessTo).settings(settingsToUpdate), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices() - .putSettings( - new UpdateSettingsRequest(indexThatUserHasAccessTo, indexThatUserHasNoAccessTo).settings(settingsToUpdate), - DEFAULT - ), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices().putSettings(new UpdateSettingsRequest("*").settings(settingsToUpdate), DEFAULT), - statusException(FORBIDDEN) - ); - } - } - - @Test - // required permissions: indices:admin/mapping/put - public void createIndexMappings_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("create_index_mappings_positive"); - Map indexMapping = Map.of("properties", Map.of("message", Map.of("type", "text"))); - IndexOperationsHelper.createIndex(cluster, indexName); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - PutMappingRequest putMappingRequest = new PutMappingRequest(indexName).source(indexMapping); - var response = restHighLevelClient.indices().putMapping(putMappingRequest, DEFAULT); - - assertThat(response.isAcknowledged(), is(true)); - assertThat(cluster, indexMappingIsEqualTo(indexName, indexMapping)); - } - } - - @Test - public void createIndexMappings_negative() throws IOException { - String indexThatUserHasNoAccessTo = "create_index_mappings_negative"; - String indexThatUserHasAccessTo = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat(indexThatUserHasNoAccessTo); - Map indexMapping = Map.of("properties", Map.of("message", Map.of("type", "text"))); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - - assertThatThrownBy( - () -> restHighLevelClient.indices() - .putMapping(new PutMappingRequest(indexThatUserHasNoAccessTo).source(indexMapping), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices() - .putMapping(new PutMappingRequest(indexThatUserHasAccessTo, indexThatUserHasNoAccessTo).source(indexMapping), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices().putMapping(new PutMappingRequest("*").source(indexMapping), DEFAULT), - statusException(FORBIDDEN) - ); - } - } - - @Test - // required permissions: indices:admin/mappings/get - public void getIndexMappings_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("get_index_mappings_positive"); - Map indexMapping = Map.of("properties", Map.of("message", Map.of("type", "text"))); - IndexOperationsHelper.createIndex(cluster, indexName); - IndexOperationsHelper.createMapping(cluster, indexName, indexMapping); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - GetMappingsRequest getMappingsRequest = new GetMappingsRequest().indices(indexName); - GetMappingsResponse response = restHighLevelClient.indices().getMapping(getMappingsRequest, DEFAULT); - - assertThat(response, getMappingsResponseContainsIndices(indexName)); - } - } - - @Test - public void getIndexMappings_negative() throws IOException { - String indexThatUserHasNoAccessTo = "get_index_mappings_negative"; - String indexThatUserHasAccessTo = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat(indexThatUserHasNoAccessTo); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - - assertThatThrownBy( - () -> restHighLevelClient.indices().getMapping(new GetMappingsRequest().indices(indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices() - .getMapping(new GetMappingsRequest().indices(indexThatUserHasAccessTo, indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices().getMapping(new GetMappingsRequest().indices("*"), DEFAULT), - statusException(FORBIDDEN) - ); - } - } - - @Test - // required permissions: "indices:admin/cache/clear" - public void clearIndexCache_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("clear_index_cache_positive"); - IndexOperationsHelper.createIndex(cluster, indexName); - - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - ClearIndicesCacheRequest clearIndicesCacheRequest = new ClearIndicesCacheRequest(indexName); - ClearIndicesCacheResponse response = restHighLevelClient.indices().clearCache(clearIndicesCacheRequest, DEFAULT); - - assertThat(response, isSuccessfulClearIndicesCacheResponse()); - } - } - - @Test - public void clearIndexCache_negative() throws IOException { - String indexThatUserHasNoAccessTo = "clear_index_cache_negative"; - String indexThatUserHasAccessTo = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat(indexThatUserHasNoAccessTo); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - - assertThatThrownBy( - () -> restHighLevelClient.indices().clearCache(new ClearIndicesCacheRequest(indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices() - .clearCache(new ClearIndicesCacheRequest(indexThatUserHasAccessTo, indexThatUserHasNoAccessTo), DEFAULT), - statusException(FORBIDDEN) - ); - assertThatThrownBy( - () -> restHighLevelClient.indices().clearCache(new ClearIndicesCacheRequest("*"), DEFAULT), - statusException(FORBIDDEN) - ); - } - } - - @Test - // required permissions: "indices:admin/create", "indices:admin/aliases" - public void shouldCreateIndexWithAlias_positive() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("create_index_with_alias_positive"); - try ( - RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient( - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES - ) - ) { - CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName).alias( - new Alias(ALIAS_CREATE_INDEX_WITH_ALIAS_POSITIVE) - ); - - CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, DEFAULT); - - assertThat(createIndexResponse, isSuccessfulCreateIndexResponse(indexName)); - assertThat(cluster, indexExists(indexName)); - assertThat(internalClient, aliasExists(ALIAS_CREATE_INDEX_WITH_ALIAS_POSITIVE)); - } - auditLogsRule.assertExactlyOne( - userAuthenticated(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES).withRestRequest( - PUT, - "/index_operations_create_index_with_alias_positive" - ) - ); - auditLogsRule.assertExactly( - 2, - grantedPrivilege(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES, "CreateIndexRequest") - ); - auditLogsRule.assertExactly( - 2, - auditPredicate(INDEX_EVENT).withEffectiveUser(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES) - ); - } - - @Test - public void shouldCreateIndexWithAlias_negative() throws IOException { - String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("create_index_with_alias_negative"); - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(USER_ALLOWED_TO_CREATE_INDEX)) { - CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName).alias( - new Alias(ALIAS_CREATE_INDEX_WITH_ALIAS_NEGATIVE) - ); - - assertThatThrownBy(() -> restHighLevelClient.indices().create(createIndexRequest, DEFAULT), statusException(FORBIDDEN)); - - assertThat(internalClient, not(aliasExists(ALIAS_CREATE_INDEX_WITH_ALIAS_NEGATIVE))); - } - auditLogsRule.assertExactlyOne( - userAuthenticated(USER_ALLOWED_TO_CREATE_INDEX).withRestRequest(PUT, "/index_operations_create_index_with_alias_negative") - ); - auditLogsRule.assertExactlyOne(missingPrivilege(USER_ALLOWED_TO_CREATE_INDEX, "CreateIndexRequest")); - } -} diff --git a/src/integrationTest/java/org/opensearch/security/http/JwtAuthenticationTests.java b/src/integrationTest/java/org/opensearch/security/http/JwtAuthenticationTests.java deleted file mode 100644 index 9df611e207..0000000000 --- a/src/integrationTest/java/org/opensearch/security/http/JwtAuthenticationTests.java +++ /dev/null @@ -1,270 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.security.http; - -import java.io.IOException; -import java.security.KeyPair; -import java.util.Base64; -import java.util.List; -import java.util.Map; - -import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.security.Keys; -import org.apache.hc.core5.http.Header; -import org.apache.hc.core5.http.message.BasicHeader; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.opensearch.action.search.SearchRequest; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.client.Client; -import org.opensearch.client.RestHighLevelClient; -import org.opensearch.test.framework.JwtConfigBuilder; -import org.opensearch.test.framework.TestSecurityConfig; -import org.opensearch.test.framework.TestSecurityConfig.Role; -import org.opensearch.test.framework.cluster.ClusterManager; -import org.opensearch.test.framework.cluster.LocalCluster; -import org.opensearch.test.framework.cluster.TestRestClient; -import org.opensearch.test.framework.cluster.TestRestClient.HttpResponse; -import org.opensearch.test.framework.log.LogsRule; - -import static java.nio.charset.StandardCharsets.US_ASCII; -import static org.apache.http.HttpHeaders.AUTHORIZATION; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; -import static org.opensearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; -import static org.opensearch.client.RequestOptions.DEFAULT; -import static org.opensearch.core.rest.RestStatus.FORBIDDEN; -import static org.opensearch.security.Song.FIELD_TITLE; -import static org.opensearch.security.Song.QUERY_TITLE_MAGNUM_OPUS; -import static org.opensearch.security.Song.SONGS; -import static org.opensearch.security.Song.TITLE_MAGNUM_OPUS; -import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL; -import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.BASIC_AUTH_DOMAIN_ORDER; -import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.queryStringQueryRequest; -import static org.opensearch.test.framework.matcher.ExceptionMatcherAssert.assertThatThrownBy; -import static org.opensearch.test.framework.matcher.OpenSearchExceptionMatchers.statusException; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.isSuccessfulSearchResponse; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.numberOfTotalHitsIsEqualTo; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.searchHitContainsFieldWithValue; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.searchHitsContainDocumentWithId; - -@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) -@ThreadLeakScope(ThreadLeakScope.Scope.NONE) -public class JwtAuthenticationTests { - - public static final String CLAIM_USERNAME = "preferred-username"; - public static final String CLAIM_ROLES = "backend-user-roles"; - - public static final String USER_SUPERHERO = "superhero"; - public static final String USERNAME_ROOT = "root"; - public static final String ROLE_ADMIN = "role_admin"; - public static final String ROLE_DEVELOPER = "role_developer"; - public static final String ROLE_QA = "role_qa"; - public static final String ROLE_CTO = "role_cto"; - public static final String ROLE_CEO = "role_ceo"; - public static final String ROLE_VP = "role_vp"; - public static final String POINTER_BACKEND_ROLES = "/backend_roles"; - public static final String POINTER_USERNAME = "/user_name"; - - public static final String QA_DEPARTMENT = "qa-department"; - - public static final String CLAIM_DEPARTMENT = "department"; - - public static final String DEPARTMENT_SONG_INDEX_PATTERN = String.format("song_lyrics_${attr.jwt.%s}", CLAIM_DEPARTMENT); - - public static final String QA_SONG_INDEX_NAME = String.format("song_lyrics_%s", QA_DEPARTMENT); - - private static final KeyPair KEY_PAIR = Keys.keyPairFor(SignatureAlgorithm.RS256); - private static final String PUBLIC_KEY = new String(Base64.getEncoder().encode(KEY_PAIR.getPublic().getEncoded()), US_ASCII); - - static final TestSecurityConfig.User ADMIN_USER = new TestSecurityConfig.User("admin").roles(ALL_ACCESS); - - private static final String JWT_AUTH_HEADER = "jwt-auth"; - - private static final JwtAuthorizationHeaderFactory tokenFactory = new JwtAuthorizationHeaderFactory( - KEY_PAIR.getPrivate(), - CLAIM_USERNAME, - CLAIM_ROLES, - JWT_AUTH_HEADER - ); - - public static final TestSecurityConfig.AuthcDomain JWT_AUTH_DOMAIN = new TestSecurityConfig.AuthcDomain( - "jwt", - BASIC_AUTH_DOMAIN_ORDER - 1 - ).jwtHttpAuthenticator( - new JwtConfigBuilder().jwtHeader(JWT_AUTH_HEADER).signingKey(PUBLIC_KEY).subjectKey(CLAIM_USERNAME).rolesKey(CLAIM_ROLES) - ).backend("noop"); - public static final String SONG_ID_1 = "song-id-01"; - - public static final Role DEPARTMENT_SONG_LISTENER_ROLE = new Role("department-song-listener-role").indexPermissions( - "indices:data/read/search" - ).on(DEPARTMENT_SONG_INDEX_PATTERN); - - @ClassRule - public static final LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE) - .anonymousAuth(false) - .nodeSettings( - Map.of("plugins.security.restapi.roles_enabled", List.of("user_" + ADMIN_USER.getName() + "__" + ALL_ACCESS.getName())) - ) - .authc(AUTHC_HTTPBASIC_INTERNAL) - .users(ADMIN_USER) - .roles(DEPARTMENT_SONG_LISTENER_ROLE) - .authc(JWT_AUTH_DOMAIN) - .build(); - - @Rule - public LogsRule logsRule = new LogsRule("com.amazon.dlic.auth.http.jwt.HTTPJwtAuthenticator"); - - @BeforeClass - public static void createTestData() { - try (Client client = cluster.getInternalNodeClient()) { - client.prepareIndex(QA_SONG_INDEX_NAME).setId(SONG_ID_1).setRefreshPolicy(IMMEDIATE).setSource(SONGS[0].asMap()).get(); - } - try (TestRestClient client = cluster.getRestClient(ADMIN_USER)) { - client.createRoleMapping(ROLE_VP, DEPARTMENT_SONG_LISTENER_ROLE.getName()); - } - } - - @Test - public void shouldAuthenticateWithJwtToken_positive() { - try (TestRestClient client = cluster.getRestClient(tokenFactory.generateValidToken(USER_SUPERHERO))) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(200); - String username = response.getTextFromJsonBody(POINTER_USERNAME); - assertThat(username, equalTo(USER_SUPERHERO)); - } - } - - @Test - public void shouldAuthenticateWithJwtToken_positiveWithAnotherUsername() { - try (TestRestClient client = cluster.getRestClient(tokenFactory.generateValidToken(USERNAME_ROOT))) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(200); - String username = response.getTextFromJsonBody(POINTER_USERNAME); - assertThat(username, equalTo(USERNAME_ROOT)); - } - } - - @Test - public void shouldAuthenticateWithJwtToken_failureLackingUserName() { - try (TestRestClient client = cluster.getRestClient(tokenFactory.generateTokenWithoutPreferredUsername(USER_SUPERHERO))) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(401); - logsRule.assertThatContainExactly("No subject found in JWT token"); - } - } - - @Test - public void shouldAuthenticateWithJwtToken_failureExpiredToken() { - try (TestRestClient client = cluster.getRestClient(tokenFactory.generateExpiredToken(USER_SUPERHERO))) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(401); - logsRule.assertThatContainExactly("Invalid or expired JWT token."); - } - } - - @Test - public void shouldAuthenticateWithJwtToken_failureIncorrectFormatOfToken() { - Header header = new BasicHeader(AUTHORIZATION, "not.a.token"); - try (TestRestClient client = cluster.getRestClient(header)) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(401); - logsRule.assertThatContainExactly(String.format("No JWT token found in '%s' header header", JWT_AUTH_HEADER)); - } - } - - @Test - public void shouldAuthenticateWithJwtToken_failureIncorrectSignature() { - KeyPair incorrectKeyPair = Keys.keyPairFor(SignatureAlgorithm.RS256); - Header header = tokenFactory.generateTokenSignedWithKey(incorrectKeyPair.getPrivate(), USER_SUPERHERO); - try (TestRestClient client = cluster.getRestClient(header)) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(401); - logsRule.assertThatContainExactly("Invalid or expired JWT token."); - } - } - - @Test - public void shouldReadRolesFromToken_positiveFirstRoleSet() { - Header header = tokenFactory.generateValidToken(USER_SUPERHERO, ROLE_ADMIN, ROLE_DEVELOPER, ROLE_QA); - try (TestRestClient client = cluster.getRestClient(header)) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(200); - List roles = response.getTextArrayFromJsonBody(POINTER_BACKEND_ROLES); - assertThat(roles, hasSize(3)); - assertThat(roles, containsInAnyOrder(ROLE_ADMIN, ROLE_DEVELOPER, ROLE_QA)); - } - } - - @Test - public void shouldReadRolesFromToken_positiveSecondRoleSet() { - Header header = tokenFactory.generateValidToken(USER_SUPERHERO, ROLE_CTO, ROLE_CEO, ROLE_VP); - try (TestRestClient client = cluster.getRestClient(header)) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(200); - List roles = response.getTextArrayFromJsonBody(POINTER_BACKEND_ROLES); - assertThat(roles, hasSize(3)); - assertThat(roles, containsInAnyOrder(ROLE_CTO, ROLE_CEO, ROLE_VP)); - } - } - - @Test - public void shouldExposeTokenClaimsAsUserAttributes_positive() throws IOException { - String[] roles = { ROLE_VP }; - Map additionalClaims = Map.of(CLAIM_DEPARTMENT, QA_DEPARTMENT); - Header header = tokenFactory.generateValidTokenWithCustomClaims(USER_SUPERHERO, roles, additionalClaims); - try (RestHighLevelClient client = cluster.getRestHighLevelClient(List.of(header))) { - SearchRequest searchRequest = queryStringQueryRequest(QA_SONG_INDEX_NAME, QUERY_TITLE_MAGNUM_OPUS); - - SearchResponse response = client.search(searchRequest, DEFAULT); - - assertThat(response, isSuccessfulSearchResponse()); - assertThat(response, numberOfTotalHitsIsEqualTo(1)); - assertThat(response, searchHitsContainDocumentWithId(0, QA_SONG_INDEX_NAME, SONG_ID_1)); - assertThat(response, searchHitContainsFieldWithValue(0, FIELD_TITLE, TITLE_MAGNUM_OPUS)); - } - } - - @Test - public void shouldExposeTokenClaimsAsUserAttributes_negative() throws IOException { - String[] roles = { ROLE_VP }; - Map additionalClaims = Map.of(CLAIM_DEPARTMENT, "department-without-access-to-qa-song-index"); - Header header = tokenFactory.generateValidTokenWithCustomClaims(USER_SUPERHERO, roles, additionalClaims); - try (RestHighLevelClient client = cluster.getRestHighLevelClient(List.of(header))) { - SearchRequest searchRequest = queryStringQueryRequest(QA_SONG_INDEX_NAME, QUERY_TITLE_MAGNUM_OPUS); - - assertThatThrownBy(() -> client.search(searchRequest, DEFAULT), statusException(FORBIDDEN)); - } - } -} diff --git a/src/integrationTest/java/org/opensearch/security/http/LdapTlsAuthenticationTest.java b/src/integrationTest/java/org/opensearch/security/http/LdapTlsAuthenticationTest.java deleted file mode 100644 index bac79ffd12..0000000000 --- a/src/integrationTest/java/org/opensearch/security/http/LdapTlsAuthenticationTest.java +++ /dev/null @@ -1,414 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.security.http; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; -import org.apache.hc.core5.http.message.BasicHeader; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; - -import org.opensearch.action.search.SearchRequest; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.client.Client; -import org.opensearch.client.RestHighLevelClient; -import org.opensearch.test.framework.AuthorizationBackend; -import org.opensearch.test.framework.AuthzDomain; -import org.opensearch.test.framework.LdapAuthenticationConfigBuilder; -import org.opensearch.test.framework.LdapAuthorizationConfigBuilder; -import org.opensearch.test.framework.RolesMapping; -import org.opensearch.test.framework.TestSecurityConfig.AuthcDomain; -import org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AuthenticationBackend; -import org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.HttpAuthenticator; -import org.opensearch.test.framework.TestSecurityConfig.Role; -import org.opensearch.test.framework.TestSecurityConfig.User; -import org.opensearch.test.framework.certificate.TestCertificates; -import org.opensearch.test.framework.cluster.ClusterManager; -import org.opensearch.test.framework.cluster.LocalCluster; -import org.opensearch.test.framework.cluster.TestRestClient; -import org.opensearch.test.framework.cluster.TestRestClient.HttpResponse; -import org.opensearch.test.framework.ldap.EmbeddedLDAPServer; -import org.opensearch.test.framework.log.LogsRule; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.not; -import static org.opensearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; -import static org.opensearch.client.RequestOptions.DEFAULT; -import static org.opensearch.core.rest.RestStatus.FORBIDDEN; -import static org.opensearch.security.Song.SONGS; -import static org.opensearch.security.http.DirectoryInformationTrees.CN_GROUP_ADMIN; -import static org.opensearch.security.http.DirectoryInformationTrees.CN_GROUP_BRIDGE; -import static org.opensearch.security.http.DirectoryInformationTrees.CN_GROUP_CREW; -import static org.opensearch.security.http.DirectoryInformationTrees.DN_CAPTAIN_SPOCK_PEOPLE_TEST_ORG; -import static org.opensearch.security.http.DirectoryInformationTrees.DN_GROUPS_TEST_ORG; -import static org.opensearch.security.http.DirectoryInformationTrees.DN_OPEN_SEARCH_PEOPLE_TEST_ORG; -import static org.opensearch.security.http.DirectoryInformationTrees.DN_PEOPLE_TEST_ORG; -import static org.opensearch.security.http.DirectoryInformationTrees.LDIF_DATA; -import static org.opensearch.security.http.DirectoryInformationTrees.PASSWORD_JEAN; -import static org.opensearch.security.http.DirectoryInformationTrees.PASSWORD_KIRK; -import static org.opensearch.security.http.DirectoryInformationTrees.PASSWORD_LEONARD; -import static org.opensearch.security.http.DirectoryInformationTrees.PASSWORD_OPEN_SEARCH; -import static org.opensearch.security.http.DirectoryInformationTrees.PASSWORD_SPOCK; -import static org.opensearch.security.http.DirectoryInformationTrees.USERNAME_ATTRIBUTE; -import static org.opensearch.security.http.DirectoryInformationTrees.USER_JEAN; -import static org.opensearch.security.http.DirectoryInformationTrees.USER_KIRK; -import static org.opensearch.security.http.DirectoryInformationTrees.USER_LEONARD; -import static org.opensearch.security.http.DirectoryInformationTrees.USER_SEARCH; -import static org.opensearch.security.http.DirectoryInformationTrees.USER_SPOCK; -import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL; -import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.BASIC_AUTH_DOMAIN_ORDER; -import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.queryStringQueryRequest; -import static org.opensearch.test.framework.matcher.ExceptionMatcherAssert.assertThatThrownBy; -import static org.opensearch.test.framework.matcher.OpenSearchExceptionMatchers.statusException; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.isSuccessfulSearchResponse; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.numberOfTotalHitsIsEqualTo; -import static org.opensearch.test.framework.matcher.SearchResponseMatchers.searchHitsContainDocumentWithId; - -/** -* Test uses plain TLS connection between OpenSearch and LDAP server. -*/ -@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) -@ThreadLeakScope(ThreadLeakScope.Scope.NONE) -public class LdapTlsAuthenticationTest { - - private static final String SONG_INDEX_NAME = "song_lyrics"; - - private static final String HEADER_NAME_IMPERSONATE = "opendistro_security_impersonate_as"; - - private static final String PERSONAL_INDEX_NAME_SPOCK = "personal-" + USER_SPOCK; - private static final String PERSONAL_INDEX_NAME_KIRK = "personal-" + USER_KIRK; - - private static final String POINTER_BACKEND_ROLES = "/backend_roles"; - private static final String POINTER_ROLES = "/roles"; - private static final String POINTER_USERNAME = "/user_name"; - private static final String POINTER_ERROR_REASON = "/error/reason"; - - private static final String SONG_ID_1 = "l0001"; - private static final String SONG_ID_2 = "l0002"; - private static final String SONG_ID_3 = "l0003"; - - private static final User ADMIN_USER = new User("admin").roles(ALL_ACCESS); - - private static final TestCertificates TEST_CERTIFICATES = new TestCertificates(); - - private static final Role ROLE_INDEX_ADMINISTRATOR = new Role("index_administrator").indexPermissions("*").on("*"); - private static final Role ROLE_PERSONAL_INDEX_ACCESS = new Role("personal_index_access").indexPermissions("*") - .on("personal-${attr.ldap.uid}"); - - private static final EmbeddedLDAPServer embeddedLDAPServer = new EmbeddedLDAPServer( - TEST_CERTIFICATES.getRootCertificateData(), - TEST_CERTIFICATES.getLdapCertificateData(), - LDIF_DATA - ); - - private static final Map USER_IMPERSONATION_CONFIGURATION = Map.of( - "plugins.security.authcz.rest_impersonation_user." + USER_KIRK, - List.of(USER_SPOCK) - ); - - private static final LocalCluster cluster = new LocalCluster.Builder().testCertificates(TEST_CERTIFICATES) - .clusterManager(ClusterManager.SINGLENODE) - .anonymousAuth(false) - .nodeSettings(USER_IMPERSONATION_CONFIGURATION) - .authc( - new AuthcDomain("ldap", BASIC_AUTH_DOMAIN_ORDER + 1, true).httpAuthenticator(new HttpAuthenticator("basic").challenge(false)) - .backend( - new AuthenticationBackend("ldap").config( - () -> LdapAuthenticationConfigBuilder.config() - // this port is available when embeddedLDAPServer is already started, therefore Supplier interface is used - .hosts(List.of("localhost:" + embeddedLDAPServer.getLdapTlsPort())) - .enableSsl(true) - .bindDn(DN_OPEN_SEARCH_PEOPLE_TEST_ORG) - .password(PASSWORD_OPEN_SEARCH) - .userBase(DN_PEOPLE_TEST_ORG) - .userSearch(USER_SEARCH) - .usernameAttribute(USERNAME_ATTRIBUTE) - .penTrustedCasFilePath(TEST_CERTIFICATES.getRootCertificate().getAbsolutePath()) - .build() - ) - ) - ) - .authc(AUTHC_HTTPBASIC_INTERNAL) - .users(ADMIN_USER) - .roles(ROLE_INDEX_ADMINISTRATOR, ROLE_PERSONAL_INDEX_ACCESS) - .rolesMapping( - new RolesMapping(ROLE_INDEX_ADMINISTRATOR).backendRoles(CN_GROUP_ADMIN), - new RolesMapping(ROLE_PERSONAL_INDEX_ACCESS).backendRoles(CN_GROUP_CREW) - ) - .authz( - new AuthzDomain("ldap_roles").httpEnabled(true) - .transportEnabled(true) - .authorizationBackend( - new AuthorizationBackend("ldap").config( - () -> new LdapAuthorizationConfigBuilder().hosts(List.of("localhost:" + embeddedLDAPServer.getLdapTlsPort())) - .enableSsl(true) - .bindDn(DN_OPEN_SEARCH_PEOPLE_TEST_ORG) - .password(PASSWORD_OPEN_SEARCH) - .userBase(DN_PEOPLE_TEST_ORG) - .userSearch(USER_SEARCH) - .usernameAttribute(USERNAME_ATTRIBUTE) - .penTrustedCasFilePath(TEST_CERTIFICATES.getRootCertificate().getAbsolutePath()) - .roleBase(DN_GROUPS_TEST_ORG) - .roleSearch("(uniqueMember={0})") - .userRoleAttribute(null) - .userRoleName("disabled") - .roleName("cn") - .resolveNestedRoles(true) - .build() - ) - ) - ) - .build(); - - @ClassRule - public static final RuleChain ruleChain = RuleChain.outerRule(embeddedLDAPServer).around(cluster); - - @Rule - public LogsRule logsRule = new LogsRule("com.amazon.dlic.auth.ldap.backend.LDAPAuthenticationBackend"); - - @BeforeClass - public static void createTestData() { - try (Client client = cluster.getInternalNodeClient()) { - client.prepareIndex(SONG_INDEX_NAME).setId(SONG_ID_1).setRefreshPolicy(IMMEDIATE).setSource(SONGS[0].asMap()).get(); - client.prepareIndex(PERSONAL_INDEX_NAME_SPOCK).setId(SONG_ID_2).setRefreshPolicy(IMMEDIATE).setSource(SONGS[1].asMap()).get(); - client.prepareIndex(PERSONAL_INDEX_NAME_KIRK).setId(SONG_ID_3).setRefreshPolicy(IMMEDIATE).setSource(SONGS[2].asMap()).get(); - } - } - - @Test - public void shouldAuthenticateUserWithLdap_positiveSpockUser() { - try (TestRestClient client = cluster.getRestClient(USER_SPOCK, PASSWORD_SPOCK)) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(200); - String username = response.getTextFromJsonBody(POINTER_USERNAME); - assertThat(username, equalTo(USER_SPOCK)); - } - } - - @Test - public void shouldAuthenticateUserWithLdap_positiveKirkUser() { - try (TestRestClient client = cluster.getRestClient(USER_KIRK, PASSWORD_KIRK)) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(200); - String username = response.getTextFromJsonBody(POINTER_USERNAME); - assertThat(username, equalTo(USER_KIRK)); - } - } - - @Test - public void shouldAuthenticateUserWithLdap_negativeWhenIncorrectPassword() { - try (TestRestClient client = cluster.getRestClient(USER_SPOCK, "incorrect password")) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(401); - String expectedStackTraceFragment = "Unable to bind as user '".concat(DN_CAPTAIN_SPOCK_PEOPLE_TEST_ORG) - .concat("' because the provided password was incorrect."); - logsRule.assertThatStackTraceContain(expectedStackTraceFragment); - } - } - - @Test - public void shouldAuthenticateUserWithLdap_negativeWhenIncorrectUsername() { - final String username = "invalid-user-name"; - try (TestRestClient client = cluster.getRestClient(username, PASSWORD_SPOCK)) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(401); - logsRule.assertThatStackTraceContain(String.format("No user %s found", username)); - } - } - - @Test - public void shouldAuthenticateUserWithLdap_negativeWhenUserDoesNotExist() { - final String username = "doesNotExist"; - try (TestRestClient client = cluster.getRestClient(username, "password")) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(401); - logsRule.assertThatStackTraceContain(String.format("No user %s found", username)); - } - } - - @Test - public void shouldResolveUserRolesAgainstLdapBackend_positiveSpockUser() { - try (TestRestClient client = cluster.getRestClient(USER_SPOCK, PASSWORD_SPOCK)) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(200); - List backendRoles = response.getTextArrayFromJsonBody(POINTER_BACKEND_ROLES); - assertThat(backendRoles, contains(CN_GROUP_CREW)); - assertThat(response.getTextArrayFromJsonBody(POINTER_ROLES), contains(ROLE_PERSONAL_INDEX_ACCESS.getName())); - } - } - - @Test - public void shouldResolveUserRolesAgainstLdapBackend_positiveKirkUser() { - try (TestRestClient client = cluster.getRestClient(USER_KIRK, PASSWORD_KIRK)) { - - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(200); - assertThat(response.getTextArrayFromJsonBody(POINTER_BACKEND_ROLES), contains(CN_GROUP_ADMIN)); - assertThat(response.getTextArrayFromJsonBody(POINTER_ROLES), contains(ROLE_INDEX_ADMINISTRATOR.getName())); - } - } - - @Test - public void shouldPerformAuthorizationAgainstLdapToAccessIndex_positive() throws IOException { - try (RestHighLevelClient client = cluster.getRestHighLevelClient(USER_KIRK, PASSWORD_KIRK)) { - SearchRequest request = queryStringQueryRequest(SONG_INDEX_NAME, "*"); - - SearchResponse searchResponse = client.search(request, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitsContainDocumentWithId(0, SONG_INDEX_NAME, SONG_ID_1)); - } - } - - @Test - public void shouldPerformAuthorizationAgainstLdapToAccessIndex_negative() throws IOException { - try (RestHighLevelClient client = cluster.getRestHighLevelClient(USER_LEONARD, PASSWORD_LEONARD)) { - SearchRequest request = queryStringQueryRequest(SONG_INDEX_NAME, "*"); - - assertThatThrownBy(() -> client.search(request, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldResolveUserAttributesLoadedFromLdap_positive() throws IOException { - try (RestHighLevelClient client = cluster.getRestHighLevelClient(USER_SPOCK, PASSWORD_SPOCK)) { - SearchRequest request = queryStringQueryRequest(PERSONAL_INDEX_NAME_SPOCK, "*"); - - SearchResponse searchResponse = client.search(request, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitsContainDocumentWithId(0, PERSONAL_INDEX_NAME_SPOCK, SONG_ID_2)); - } - } - - @Test - public void shouldResolveUserAttributesLoadedFromLdap_negative() throws IOException { - try (RestHighLevelClient client = cluster.getRestHighLevelClient(USER_SPOCK, PASSWORD_SPOCK)) { - SearchRequest request = queryStringQueryRequest(PERSONAL_INDEX_NAME_KIRK, "*"); - - assertThatThrownBy(() -> client.search(request, DEFAULT), statusException(FORBIDDEN)); - } - } - - @Test - public void shouldResolveNestedGroups_positive() { - try (TestRestClient client = cluster.getRestClient(USER_JEAN, PASSWORD_JEAN)) { - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(200); - List backendRoles = response.getTextArrayFromJsonBody(POINTER_BACKEND_ROLES); - assertThat(backendRoles, hasSize(2)); - // CN_GROUP_CREW is retrieved recursively: cn=Jean,ou=people,o=test.org -> cn=bridge,ou=groups,o=test.org -> - // cn=crew,ou=groups,o=test.org - assertThat(backendRoles, containsInAnyOrder(CN_GROUP_CREW, CN_GROUP_BRIDGE)); - assertThat(response.getTextArrayFromJsonBody(POINTER_ROLES), contains(ROLE_PERSONAL_INDEX_ACCESS.getName())); - } - } - - @Test - public void shouldResolveNestedGroups_negative() { - try (TestRestClient client = cluster.getRestClient(USER_KIRK, PASSWORD_KIRK)) { - HttpResponse response = client.getAuthInfo(); - - response.assertStatusCode(200); - List backendRoles = response.getTextArrayFromJsonBody(POINTER_BACKEND_ROLES); - assertThat(backendRoles, not(containsInAnyOrder(CN_GROUP_CREW))); - } - } - - @Test - public void shouldImpersonateUser_positive() { - try (TestRestClient client = cluster.getRestClient(USER_KIRK, PASSWORD_KIRK)) { - - HttpResponse response = client.getAuthInfo(new BasicHeader(HEADER_NAME_IMPERSONATE, USER_SPOCK)); - - response.assertStatusCode(200); - assertThat(response.getTextFromJsonBody(POINTER_USERNAME), equalTo(USER_SPOCK)); - List backendRoles = response.getTextArrayFromJsonBody(POINTER_BACKEND_ROLES); - assertThat(backendRoles, hasSize(1)); - assertThat(backendRoles, contains(CN_GROUP_CREW)); - } - } - - @Test - public void shouldImpersonateUser_negativeJean() { - try (TestRestClient client = cluster.getRestClient(USER_KIRK, PASSWORD_KIRK)) { - - HttpResponse response = client.getAuthInfo(new BasicHeader(HEADER_NAME_IMPERSONATE, USER_JEAN)); - - response.assertStatusCode(403); - String expectedMessage = String.format("'%s' is not allowed to impersonate as '%s'", USER_KIRK, USER_JEAN); - assertThat(response.getTextFromJsonBody(POINTER_ERROR_REASON), equalTo(expectedMessage)); - } - } - - @Test - public void shouldImpersonateUser_negativeKirk() { - try (TestRestClient client = cluster.getRestClient(USER_JEAN, PASSWORD_JEAN)) { - - HttpResponse response = client.getAuthInfo(new BasicHeader(HEADER_NAME_IMPERSONATE, USER_KIRK)); - - response.assertStatusCode(403); - String expectedMessage = String.format("'%s' is not allowed to impersonate as '%s'", USER_JEAN, USER_KIRK); - assertThat(response.getTextFromJsonBody(POINTER_ERROR_REASON), equalTo(expectedMessage)); - } - } - - @Test - public void shouldAccessImpersonatedUserPersonalIndex_positive() throws IOException { - BasicHeader impersonateHeader = new BasicHeader(HEADER_NAME_IMPERSONATE, USER_SPOCK); - try (RestHighLevelClient client = cluster.getRestHighLevelClient(USER_KIRK, PASSWORD_KIRK, impersonateHeader)) { - SearchRequest request = queryStringQueryRequest(PERSONAL_INDEX_NAME_SPOCK, "*"); - - SearchResponse searchResponse = client.search(request, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitsContainDocumentWithId(0, PERSONAL_INDEX_NAME_SPOCK, SONG_ID_2)); - } - } - - @Test - public void shouldAccessImpersonatedUserPersonalIndex_negative() throws IOException { - BasicHeader impersonateHeader = new BasicHeader(HEADER_NAME_IMPERSONATE, USER_SPOCK); - try (RestHighLevelClient client = cluster.getRestHighLevelClient(USER_KIRK, PASSWORD_KIRK, impersonateHeader)) { - SearchRequest request = queryStringQueryRequest(PERSONAL_INDEX_NAME_KIRK, "*"); - - assertThatThrownBy(() -> client.search(request, DEFAULT), statusException(FORBIDDEN)); - } - } -} diff --git a/src/integrationTest/java/org/opensearch/test/framework/TestSecurityConfig.java b/src/integrationTest/java/org/opensearch/test/framework/TestSecurityConfig.java deleted file mode 100644 index d44f10eba0..0000000000 --- a/src/integrationTest/java/org/opensearch/test/framework/TestSecurityConfig.java +++ /dev/null @@ -1,717 +0,0 @@ -/* -* Copyright 2021 floragunn GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -*/ - -/* -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -* Modifications Copyright OpenSearch Contributors. See -* GitHub history for details. -*/ - -package org.opensearch.test.framework; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.bouncycastle.crypto.generators.OpenBSDBCrypt; - -import org.opensearch.action.admin.indices.create.CreateIndexRequest; -import org.opensearch.action.index.IndexRequest; -import org.opensearch.action.update.UpdateRequest; -import org.opensearch.client.Client; -import org.opensearch.common.Strings; -import org.opensearch.core.common.bytes.BytesReference; -import org.opensearch.common.xcontent.XContentFactory; -import org.opensearch.core.xcontent.ToXContentObject; -import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.security.securityconf.impl.CType; -import org.opensearch.test.framework.cluster.OpenSearchClientProvider.UserCredentialsHolder; - -import static org.apache.http.HttpHeaders.AUTHORIZATION; -import static org.opensearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; - -/** -* This class allows the declarative specification of the security configuration; in particular: -* -* - config.yml -* - internal_users.yml -* - roles.yml -* - roles_mapping.yml -* -* The class does the whole round-trip, i.e., the configuration is serialized to YAML/JSON and then written to -* the configuration index of the security plugin. -*/ -public class TestSecurityConfig { - - private static final Logger log = LogManager.getLogger(TestSecurityConfig.class); - - private Config config = new Config(); - private Map internalUsers = new LinkedHashMap<>(); - private Map roles = new LinkedHashMap<>(); - private AuditConfiguration auditConfiguration; - private Map rolesMapping = new LinkedHashMap<>(); - - private String indexName = ".opendistro_security"; - - public TestSecurityConfig() { - - } - - public TestSecurityConfig configIndexName(String configIndexName) { - this.indexName = configIndexName; - return this; - } - - public TestSecurityConfig authFailureListeners(AuthFailureListeners listener) { - config.authFailureListeners(listener); - return this; - } - - public TestSecurityConfig anonymousAuth(boolean anonymousAuthEnabled) { - config.anonymousAuth(anonymousAuthEnabled); - return this; - } - - public TestSecurityConfig doNotFailOnForbidden(boolean doNotFailOnForbidden) { - config.doNotFailOnForbidden(doNotFailOnForbidden); - return this; - } - - public TestSecurityConfig xff(XffConfig xffConfig) { - config.xffConfig(xffConfig); - return this; - } - - public TestSecurityConfig authc(AuthcDomain authcDomain) { - config.authc(authcDomain); - return this; - } - - public TestSecurityConfig authz(AuthzDomain authzDomain) { - config.authz(authzDomain); - return this; - } - - public TestSecurityConfig user(User user) { - this.internalUsers.put(user.name, user); - - for (Role role : user.roles) { - this.roles.put(role.name, role); - } - - return this; - } - - public List getUsers() { - return new ArrayList<>(internalUsers.values()); - } - - public TestSecurityConfig roles(Role... roles) { - for (Role role : roles) { - if (this.roles.containsKey(role.name)) { - throw new IllegalStateException("Role with name " + role.name + " is already defined"); - } - this.roles.put(role.name, role); - } - - return this; - } - - public TestSecurityConfig audit(AuditConfiguration auditConfiguration) { - this.auditConfiguration = auditConfiguration; - return this; - } - - public TestSecurityConfig rolesMapping(RolesMapping... mappings) { - for (RolesMapping mapping : mappings) { - String roleName = mapping.getRoleName(); - if (rolesMapping.containsKey(roleName)) { - throw new IllegalArgumentException("Role mapping " + roleName + " already exists"); - } - this.rolesMapping.put(roleName, mapping); - } - return this; - } - - public static class Config implements ToXContentObject { - private boolean anonymousAuth; - - private Boolean doNotFailOnForbidden; - private XffConfig xffConfig; - private Map authcDomainMap = new LinkedHashMap<>(); - - private AuthFailureListeners authFailureListeners; - private Map authzDomainMap = new LinkedHashMap<>(); - - public Config anonymousAuth(boolean anonymousAuth) { - this.anonymousAuth = anonymousAuth; - return this; - } - - public Config doNotFailOnForbidden(Boolean doNotFailOnForbidden) { - this.doNotFailOnForbidden = doNotFailOnForbidden; - return this; - } - - public Config xffConfig(XffConfig xffConfig) { - this.xffConfig = xffConfig; - return this; - } - - public Config authc(AuthcDomain authcDomain) { - authcDomainMap.put(authcDomain.id, authcDomain); - return this; - } - - public Config authFailureListeners(AuthFailureListeners authFailureListeners) { - this.authFailureListeners = authFailureListeners; - return this; - } - - public Config authz(AuthzDomain authzDomain) { - authzDomainMap.put(authzDomain.getId(), authzDomain); - return this; - } - - @Override - public XContentBuilder toXContent(XContentBuilder xContentBuilder, Params params) throws IOException { - xContentBuilder.startObject(); - xContentBuilder.startObject("dynamic"); - - if (anonymousAuth || (xffConfig != null)) { - xContentBuilder.startObject("http"); - xContentBuilder.field("anonymous_auth_enabled", anonymousAuth); - if (xffConfig != null) { - xContentBuilder.field("xff", xffConfig); - } - xContentBuilder.endObject(); - } - if (doNotFailOnForbidden != null) { - xContentBuilder.field("do_not_fail_on_forbidden", doNotFailOnForbidden); - } - - xContentBuilder.field("authc", authcDomainMap); - if (authzDomainMap.isEmpty() == false) { - xContentBuilder.field("authz", authzDomainMap); - } - - if (authFailureListeners != null) { - xContentBuilder.field("auth_failure_listeners", authFailureListeners); - } - - xContentBuilder.endObject(); - xContentBuilder.endObject(); - return xContentBuilder; - } - } - - public static class User implements UserCredentialsHolder, ToXContentObject { - - public final static TestSecurityConfig.User USER_ADMIN = new TestSecurityConfig.User("admin").roles( - new Role("allaccess").indexPermissions("*").on("*").clusterPermissions("*") - ); - - String name; - private String password; - List roles = new ArrayList<>(); - private Map attributes = new HashMap<>(); - - public User(String name) { - this.name = name; - this.password = "secret"; - } - - public User password(String password) { - this.password = password; - return this; - } - - public User roles(Role... roles) { - // We scope the role names by user to keep tests free of potential side effects - String roleNamePrefix = "user_" + this.getName() + "__"; - this.roles.addAll( - Arrays.asList(roles).stream().map((r) -> r.clone().name(roleNamePrefix + r.getName())).collect(Collectors.toSet()) - ); - return this; - } - - public User attr(String key, Object value) { - this.attributes.put(key, value); - return this; - } - - public String getName() { - return name; - } - - public String getPassword() { - return password; - } - - public Set getRoleNames() { - return roles.stream().map(Role::getName).collect(Collectors.toSet()); - } - - public Object getAttribute(String attributeName) { - return attributes.get(attributeName); - } - - @Override - public XContentBuilder toXContent(XContentBuilder xContentBuilder, Params params) throws IOException { - xContentBuilder.startObject(); - - xContentBuilder.field("hash", hash(password.toCharArray())); - - Set roleNames = getRoleNames(); - - if (!roleNames.isEmpty()) { - xContentBuilder.field("opendistro_security_roles", roleNames); - } - - if (attributes != null && attributes.size() != 0) { - xContentBuilder.field("attributes", attributes); - } - - xContentBuilder.endObject(); - return xContentBuilder; - } - } - - public static class Role implements ToXContentObject { - public static Role ALL_ACCESS = new Role("all_access").clusterPermissions("*").indexPermissions("*").on("*"); - - private String name; - private List clusterPermissions = new ArrayList<>(); - - private List indexPermissions = new ArrayList<>(); - - public Role(String name) { - this.name = name; - } - - public Role clusterPermissions(String... clusterPermissions) { - this.clusterPermissions.addAll(Arrays.asList(clusterPermissions)); - return this; - } - - public IndexPermission indexPermissions(String... indexPermissions) { - return new IndexPermission(this, indexPermissions); - } - - public Role name(String name) { - this.name = name; - return this; - } - - public String getName() { - return name; - } - - public Role clone() { - Role role = new Role(this.name); - role.clusterPermissions.addAll(this.clusterPermissions); - role.indexPermissions.addAll(this.indexPermissions); - return role; - } - - @Override - public XContentBuilder toXContent(XContentBuilder xContentBuilder, Params params) throws IOException { - xContentBuilder.startObject(); - - if (!clusterPermissions.isEmpty()) { - xContentBuilder.field("cluster_permissions", clusterPermissions); - } - - if (!indexPermissions.isEmpty()) { - xContentBuilder.field("index_permissions", indexPermissions); - } - - xContentBuilder.endObject(); - return xContentBuilder; - } - } - - public static class IndexPermission implements ToXContentObject { - private List allowedActions; - private List indexPatterns; - private Role role; - private String dlsQuery; - private List fls; - private List maskedFields; - - IndexPermission(Role role, String... allowedActions) { - this.allowedActions = Arrays.asList(allowedActions); - this.role = role; - } - - public IndexPermission dls(String dlsQuery) { - this.dlsQuery = dlsQuery; - return this; - } - - public IndexPermission fls(String... fls) { - this.fls = Arrays.asList(fls); - return this; - } - - public IndexPermission maskedFields(String... maskedFields) { - this.maskedFields = Arrays.asList(maskedFields); - return this; - } - - public Role on(String... indexPatterns) { - this.indexPatterns = Arrays.asList(indexPatterns); - this.role.indexPermissions.add(this); - return this.role; - } - - public Role on(TestIndex... testindices) { - this.indexPatterns = Arrays.asList(testindices).stream().map(TestIndex::getName).collect(Collectors.toList()); - this.role.indexPermissions.add(this); - return this.role; - } - - @Override - public XContentBuilder toXContent(XContentBuilder xContentBuilder, Params params) throws IOException { - xContentBuilder.startObject(); - - xContentBuilder.field("index_patterns", indexPatterns); - xContentBuilder.field("allowed_actions", allowedActions); - - if (dlsQuery != null) { - xContentBuilder.field("dls", dlsQuery); - } - - if (fls != null) { - xContentBuilder.field("fls", fls); - } - - if (maskedFields != null) { - xContentBuilder.field("masked_fields", maskedFields); - } - - xContentBuilder.endObject(); - return xContentBuilder; - } - } - - public static class AuthcDomain implements ToXContentObject { - - private static String PUBLIC_KEY = - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoqZbjLUAWc+DZTkinQAdvy1GFjPHPnxheU89hSiWoDD3NOW76H3u3T7cCDdOah2msdxSlBmCBH6wik8qLYkcV8owWukQg3PQmbEhrdPaKo0QCgomWs4nLgtmEYqcZ+QQldd82MdTlQ1QmoQmI9Uxqs1SuaKZASp3Gy19y8su5CV+FZ6BruUw9HELK055sAwl3X7j5ouabXGbcib2goBF3P52LkvbJLuWr5HDZEOeSkwIeqSeMojASM96K5SdotD+HwEyjaTjzRPL2Aa1BEQFWOQ6CFJLyLH7ZStDuPM1mJU1VxIVfMbZrhsUBjAnIhRynmWxML7YlNqkP9j6jyOIYQIDAQAB"; - - public static final int BASIC_AUTH_DOMAIN_ORDER = 0; - public final static AuthcDomain AUTHC_HTTPBASIC_INTERNAL = new TestSecurityConfig.AuthcDomain("basic", BASIC_AUTH_DOMAIN_ORDER) - .httpAuthenticatorWithChallenge("basic") - .backend("internal"); - - public final static AuthcDomain AUTHC_HTTPBASIC_INTERNAL_WITHOUT_CHALLENGE = new TestSecurityConfig.AuthcDomain( - "basic", - BASIC_AUTH_DOMAIN_ORDER - ).httpAuthenticator("basic").backend("internal"); - - public final static AuthcDomain DISABLED_AUTHC_HTTPBASIC_INTERNAL = new TestSecurityConfig.AuthcDomain( - "basic", - BASIC_AUTH_DOMAIN_ORDER, - false - ).httpAuthenticator("basic").backend("internal"); - - public final static AuthcDomain JWT_AUTH_DOMAIN = new TestSecurityConfig.AuthcDomain("jwt", 1).jwtHttpAuthenticator( - new JwtConfigBuilder().jwtHeader(AUTHORIZATION).signingKey(PUBLIC_KEY) - ).backend("noop"); - - private final String id; - private boolean enabled = true; - private int order; - private List skipUsers = new ArrayList<>(); - private HttpAuthenticator httpAuthenticator; - private AuthenticationBackend authenticationBackend; - - public AuthcDomain(String id, int order, boolean enabled) { - this.id = id; - this.order = order; - this.enabled = enabled; - } - - public AuthcDomain(String id, int order) { - this(id, order, true); - } - - public AuthcDomain httpAuthenticator(String type) { - this.httpAuthenticator = new HttpAuthenticator(type); - return this; - } - - public AuthcDomain jwtHttpAuthenticator(JwtConfigBuilder builder) { - this.httpAuthenticator = new HttpAuthenticator("jwt").challenge(false).config(builder.build()); - return this; - } - - public AuthcDomain httpAuthenticatorWithChallenge(String type) { - this.httpAuthenticator = new HttpAuthenticator(type).challenge(true); - return this; - } - - public AuthcDomain httpAuthenticator(HttpAuthenticator httpAuthenticator) { - this.httpAuthenticator = httpAuthenticator; - return this; - } - - public AuthcDomain backend(String type) { - this.authenticationBackend = new AuthenticationBackend(type); - return this; - } - - public AuthcDomain backend(AuthenticationBackend authenticationBackend) { - this.authenticationBackend = authenticationBackend; - return this; - } - - public AuthcDomain skipUsers(String... users) { - this.skipUsers.addAll(Arrays.asList(users)); - return this; - } - - @Override - public XContentBuilder toXContent(XContentBuilder xContentBuilder, Params params) throws IOException { - xContentBuilder.startObject(); - - xContentBuilder.field("http_enabled", enabled); - xContentBuilder.field("order", order); - - if (httpAuthenticator != null) { - xContentBuilder.field("http_authenticator", httpAuthenticator); - } - - if (authenticationBackend != null) { - xContentBuilder.field("authentication_backend", authenticationBackend); - } - - if (skipUsers != null && skipUsers.size() > 0) { - xContentBuilder.field("skip_users", skipUsers); - } - - xContentBuilder.endObject(); - return xContentBuilder; - } - - public static class HttpAuthenticator implements ToXContentObject { - private final String type; - private boolean challenge; - private Map config = new HashMap(); - - public HttpAuthenticator(String type) { - this.type = type; - } - - public HttpAuthenticator challenge(boolean challenge) { - this.challenge = challenge; - return this; - } - - public HttpAuthenticator config(Map config) { - this.config.putAll(config); - return this; - } - - @Override - public XContentBuilder toXContent(XContentBuilder xContentBuilder, Params params) throws IOException { - xContentBuilder.startObject(); - - xContentBuilder.field("type", type); - xContentBuilder.field("challenge", challenge); - xContentBuilder.field("config", config); - - xContentBuilder.endObject(); - return xContentBuilder; - } - } - - public static class AuthenticationBackend implements ToXContentObject { - private final String type; - private Supplier> config = () -> new HashMap(); - - public AuthenticationBackend(String type) { - this.type = type; - } - - public AuthenticationBackend config(Map config) { - Map configCopy = new HashMap<>(config); - this.config = () -> configCopy; - return this; - } - - public AuthenticationBackend config(Supplier> configSupplier) { - this.config = configSupplier; - return this; - } - - @Override - public XContentBuilder toXContent(XContentBuilder xContentBuilder, Params params) throws IOException { - xContentBuilder.startObject(); - - xContentBuilder.field("type", type); - xContentBuilder.field("config", config.get()); - - xContentBuilder.endObject(); - return xContentBuilder; - } - } - } - - public void initIndex(Client client) { - Map settings = new HashMap<>(); - if (indexName.startsWith(".")) { - settings.put("index.hidden", true); - } - client.admin().indices().create(new CreateIndexRequest(indexName).settings(settings)).actionGet(); - - writeSingleEntryConfigToIndex(client, CType.CONFIG, config); - if (auditConfiguration != null) { - writeSingleEntryConfigToIndex(client, CType.AUDIT, "config", auditConfiguration); - } - writeConfigToIndex(client, CType.ROLES, roles); - writeConfigToIndex(client, CType.INTERNALUSERS, internalUsers); - writeConfigToIndex(client, CType.ROLESMAPPING, rolesMapping); - writeEmptyConfigToIndex(client, CType.ACTIONGROUPS); - writeEmptyConfigToIndex(client, CType.TENANTS); - } - - public void updateInternalUsersConfiguration(Client client, List users) { - Map userMap = new HashMap<>(); - for (User user : users) { - userMap.put(user.getName(), user); - } - updateConfigInIndex(client, CType.INTERNALUSERS, userMap); - } - - static String hash(final char[] clearTextPassword) { - final byte[] salt = new byte[16]; - new SecureRandom().nextBytes(salt); - final String hash = OpenBSDBCrypt.generate((Objects.requireNonNull(clearTextPassword)), salt, 12); - Arrays.fill(salt, (byte) 0); - Arrays.fill(clearTextPassword, '\0'); - return hash; - } - - private void writeEmptyConfigToIndex(Client client, CType configType) { - writeConfigToIndex(client, configType, Collections.emptyMap()); - } - - private void writeConfigToIndex(Client client, CType configType, Map config) { - try { - String json = configToJson(configType, config); - - log.info("Writing security configuration into index " + configType + ":\n" + json); - - BytesReference bytesReference = toByteReference(json); - client.index( - new IndexRequest(indexName).id(configType.toLCString()) - .setRefreshPolicy(IMMEDIATE) - .source(configType.toLCString(), bytesReference) - ).actionGet(); - } catch (Exception e) { - throw new RuntimeException("Error while initializing config for " + indexName, e); - } - } - - private static BytesReference toByteReference(String string) throws UnsupportedEncodingException { - return BytesReference.fromByteBuffer(ByteBuffer.wrap(string.getBytes("utf-8"))); - } - - private void updateConfigInIndex(Client client, CType configType, Map config) { - try { - String json = configToJson(configType, config); - BytesReference bytesReference = toByteReference(json); - log.info("Update configuration of type '{}' in index '{}', new value '{}'.", configType, indexName, json); - UpdateRequest upsert = new UpdateRequest(indexName, configType.toLCString()).doc(configType.toLCString(), bytesReference) - .setRefreshPolicy(IMMEDIATE); - client.update(upsert).actionGet(); - } catch (Exception e) { - throw new RuntimeException("Error while updating config for " + indexName, e); - } - } - - private static String configToJson(CType configType, Map config) throws IOException { - XContentBuilder builder = XContentFactory.jsonBuilder(); - - builder.startObject(); - builder.startObject("_meta"); - builder.field("type", configType.toLCString()); - builder.field("config_version", 2); - builder.endObject(); - - for (Map.Entry entry : config.entrySet()) { - builder.field(entry.getKey(), entry.getValue()); - } - - builder.endObject(); - - return Strings.toString(builder); - } - - private void writeSingleEntryConfigToIndex(Client client, CType configType, ToXContentObject config) { - writeSingleEntryConfigToIndex(client, configType, configType.toLCString(), config); - } - - private void writeSingleEntryConfigToIndex(Client client, CType configType, String configurationRoot, ToXContentObject config) { - try { - XContentBuilder builder = XContentFactory.jsonBuilder(); - - builder.startObject(); - builder.startObject("_meta"); - builder.field("type", configType.toLCString()); - builder.field("config_version", 2); - builder.endObject(); - - builder.field(configurationRoot, config); - - builder.endObject(); - - String json = Strings.toString(builder); - - log.info("Writing security plugin configuration into index " + configType + ":\n" + json); - - client.index( - new IndexRequest(indexName).id(configType.toLCString()) - .setRefreshPolicy(IMMEDIATE) - .source(configType.toLCString(), toByteReference(json)) - ).actionGet(); - } catch (Exception e) { - throw new RuntimeException("Error while initializing config for " + indexName, e); - } - } -} diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/OpenSearchExceptionMatchers.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/OpenSearchExceptionMatchers.java deleted file mode 100644 index 6e8519c230..0000000000 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/OpenSearchExceptionMatchers.java +++ /dev/null @@ -1,37 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.test.framework.matcher; - -import org.hamcrest.Matcher; - -import org.opensearch.core.rest.RestStatus; - -import static org.hamcrest.Matchers.containsString; - -public class OpenSearchExceptionMatchers { - - private OpenSearchExceptionMatchers() {} - - public static Matcher statusException(RestStatus expectedRestStatus) { - return new OpenSearchStatusExceptionMatcher(expectedRestStatus); - } - - public static Matcher errorMessage(Matcher errorMessageMatcher) { - return new ExceptionErrorMessageMatcher(errorMessageMatcher); - } - - public static Matcher errorMessageContain(String errorMessage) { - return errorMessage(containsString(errorMessage)); - } - - public static Matcher hasCause(Class clazz) { - return new ExceptionHasCauseMatcher(clazz); - } -} diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/OpenSearchStatusExceptionMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/OpenSearchStatusExceptionMatcher.java deleted file mode 100644 index e8efcf151f..0000000000 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/OpenSearchStatusExceptionMatcher.java +++ /dev/null @@ -1,52 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.test.framework.matcher; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeDiagnosingMatcher; - -import org.opensearch.OpenSearchException; -import org.opensearch.core.rest.RestStatus; - -import static java.util.Objects.requireNonNull; - -class OpenSearchStatusExceptionMatcher extends TypeSafeDiagnosingMatcher { - - private final RestStatus expectedRestStatus; - - public OpenSearchStatusExceptionMatcher(RestStatus expectedRestStatus) { - this.expectedRestStatus = requireNonNull(expectedRestStatus, "Expected rest status is required."); - } - - @Override - protected boolean matchesSafely(Throwable throwable, Description mismatchDescription) { - if ((throwable instanceof OpenSearchException) == false) { - mismatchDescription.appendText("actual exception type is ") - .appendValue(throwable.getClass().getCanonicalName()) - .appendText(", error message ") - .appendValue(throwable.getMessage()); - return false; - } - OpenSearchException openSearchException = (OpenSearchException) throwable; - if (expectedRestStatus.equals(openSearchException.status()) == false) { - mismatchDescription.appendText("actual status code is ") - .appendValue(openSearchException.status()) - .appendText(", error message ") - .appendValue(throwable.getMessage()); - return false; - } - return true; - } - - @Override - public void describeTo(Description description) { - description.appendText("OpenSearchException with status code ").appendValue(expectedRestStatus); - } -} diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/SearchResponseMatchers.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/SearchResponseMatchers.java deleted file mode 100644 index cf3a6d9e57..0000000000 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/SearchResponseMatchers.java +++ /dev/null @@ -1,87 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.test.framework.matcher; - -import java.util.Arrays; -import java.util.List; -import java.util.Optional; - -import org.apache.commons.lang3.tuple.Pair; -import org.hamcrest.Matcher; - -import org.opensearch.action.search.SearchResponse; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.search.SearchHits; - -public class SearchResponseMatchers { - - private SearchResponseMatchers() {} - - public static Matcher isSuccessfulSearchResponse() { - return new SuccessfulSearchResponseMatcher(); - } - - public static Matcher numberOfTotalHitsIsEqualTo(int expectedNumberOfHits) { - return new NumberOfTotalHitsIsEqualToMatcher(expectedNumberOfHits); - } - - public static Matcher numberOfHitsInPageIsEqualTo(int expectedNumberOfHits) { - return new NumberOfHitsInPageIsEqualToMatcher(expectedNumberOfHits); - } - - public static Matcher searchHitContainsFieldWithValue(int hitIndex, String fieldName, T expectedValue) { - return new SearchHitContainsFieldWithValueMatcher<>(hitIndex, fieldName, expectedValue); - } - - public static Matcher searchHitDoesNotContainField(int hitIndex, String fieldName) { - return new SearchHitDoesNotContainFieldMatcher(hitIndex, fieldName); - } - - public static Matcher searchHitsContainDocumentWithId(int hitIndex, String indexName, String documentId) { - return new SearchHitsContainDocumentWithIdMatcher(hitIndex, indexName, documentId); - } - - public static Matcher restStatusIs(RestStatus expectedRestStatus) { - return new SearchResponseWithStatusCodeMatcher(expectedRestStatus); - } - - public static Matcher containNotEmptyScrollingId() { - return new ContainNotEmptyScrollingIdMatcher(); - } - - public static Matcher containAggregationWithNameAndType( - String expectedAggregationName, - String expectedAggregationType - ) { - return new ContainsAggregationWithNameAndTypeMatcher(expectedAggregationName, expectedAggregationType); - } - - /** - * Matcher checks if search result contains all expected documents - * - * @param documentIds Pair contain index name and document id - * @return matcher - */ - public static Matcher searchHitsContainDocumentsInAnyOrder(List> documentIds) { - return new SearchHitsContainDocumentsInAnyOrderMatcher(documentIds); - } - - public static Matcher searchHitsContainDocumentsInAnyOrder(Pair... documentIds) { - return new SearchHitsContainDocumentsInAnyOrderMatcher(Arrays.asList(documentIds)); - } - - static Long readTotalHits(SearchResponse searchResponse) { - return Optional.ofNullable(searchResponse) - .map(SearchResponse::getHits) - .map(SearchHits::getTotalHits) - .map(totalHits -> totalHits.value) - .orElse(null); - } -} diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/SearchResponseWithStatusCodeMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/SearchResponseWithStatusCodeMatcher.java deleted file mode 100644 index 5b0f99e11b..0000000000 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/SearchResponseWithStatusCodeMatcher.java +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.test.framework.matcher; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeDiagnosingMatcher; - -import org.opensearch.action.search.SearchResponse; -import org.opensearch.core.rest.RestStatus; - -class SearchResponseWithStatusCodeMatcher extends TypeSafeDiagnosingMatcher { - - private final RestStatus expectedRestStatus; - - public SearchResponseWithStatusCodeMatcher(RestStatus expectedRestStatus) { - this.expectedRestStatus = expectedRestStatus; - } - - @Override - protected boolean matchesSafely(SearchResponse searchResponse, Description mismatchDescription) { - if (expectedRestStatus.equals(searchResponse.status()) == false) { - mismatchDescription.appendText("actual response status is ").appendValue(searchResponse.status()); - return false; - } - return true; - } - - @Override - public void describeTo(Description description) { - description.appendText("Expected response status is ").appendValue(expectedRestStatus); - } -} diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessBulkResponseMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessBulkResponseMatcher.java deleted file mode 100644 index ca4b94d148..0000000000 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessBulkResponseMatcher.java +++ /dev/null @@ -1,47 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.test.framework.matcher; - -import java.util.Arrays; -import java.util.stream.Collectors; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeDiagnosingMatcher; - -import org.opensearch.action.bulk.BulkItemResponse; -import org.opensearch.action.bulk.BulkResponse; -import org.opensearch.core.rest.RestStatus; - -class SuccessBulkResponseMatcher extends TypeSafeDiagnosingMatcher { - - @Override - protected boolean matchesSafely(BulkResponse response, Description mismatchDescription) { - RestStatus status = response.status(); - if (RestStatus.OK.equals(status) == false) { - mismatchDescription.appendText("incorrect response status ").appendValue(status); - return false; - } - if (response.hasFailures()) { - String failureDescription = Arrays.stream(response.getItems()) - .filter(BulkItemResponse::isFailed) - .map(BulkItemResponse::getFailure) - .map(Object::toString) - .collect(Collectors.joining(",\n")); - mismatchDescription.appendText("bulk response contains failures ").appendValue(failureDescription); - return false; - } - return true; - } - - @Override - public void describeTo(Description description) { - description.appendText("success bulk response"); - } -} diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulClearIndicesCacheResponseMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulClearIndicesCacheResponseMatcher.java deleted file mode 100644 index b70b2c2f9e..0000000000 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulClearIndicesCacheResponseMatcher.java +++ /dev/null @@ -1,37 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.test.framework.matcher; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeDiagnosingMatcher; - -import org.opensearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse; -import org.opensearch.core.rest.RestStatus; - -class SuccessfulClearIndicesCacheResponseMatcher extends TypeSafeDiagnosingMatcher { - - @Override - protected boolean matchesSafely(ClearIndicesCacheResponse response, Description mismatchDescription) { - if (!RestStatus.OK.equals(response.getStatus())) { - mismatchDescription.appendText("Status is equal to ").appendValue(response.getStatus()); - return false; - } - if (response.getShardFailures().length != 0) { - mismatchDescription.appendText("Contains ").appendValue(response.getShardFailures().length).appendText(" shard failures"); - return false; - } - return true; - } - - @Override - public void describeTo(Description description) { - description.appendText("Successful clear index cache response"); - } -} diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulCreatePitResponseMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulCreatePitResponseMatcher.java deleted file mode 100644 index 66b59b1526..0000000000 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulCreatePitResponseMatcher.java +++ /dev/null @@ -1,37 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.test.framework.matcher; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeDiagnosingMatcher; - -import org.opensearch.action.search.CreatePitResponse; -import org.opensearch.core.rest.RestStatus; - -class SuccessfulCreatePitResponseMatcher extends TypeSafeDiagnosingMatcher { - - @Override - protected boolean matchesSafely(CreatePitResponse response, Description mismatchDescription) { - if (!RestStatus.OK.equals(response.status())) { - mismatchDescription.appendText("has status ").appendValue(response.status()).appendText(" which denotes failure."); - return false; - } - if (response.getShardFailures().length != 0) { - mismatchDescription.appendText("contains ").appendValue(response.getShardFailures().length).appendText(" shard failures"); - return false; - } - return true; - } - - @Override - public void describeTo(Description description) { - description.appendText("Successful create pit response"); - } -} diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulDeletePitResponseMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulDeletePitResponseMatcher.java deleted file mode 100644 index 20906946f1..0000000000 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulDeletePitResponseMatcher.java +++ /dev/null @@ -1,42 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.test.framework.matcher; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeDiagnosingMatcher; - -import org.opensearch.action.search.DeletePitInfo; -import org.opensearch.action.search.DeletePitResponse; -import org.opensearch.core.rest.RestStatus; - -class SuccessfulDeletePitResponseMatcher extends TypeSafeDiagnosingMatcher { - - @Override - protected boolean matchesSafely(DeletePitResponse response, Description mismatchDescription) { - if (!RestStatus.OK.equals(response.status())) { - mismatchDescription.appendText("has status ").appendValue(response.status()).appendText(" which denotes failure."); - return false; - } - for (DeletePitInfo deletePitInfo : response.getDeletePitResults()) { - if (!deletePitInfo.isSuccessful()) { - mismatchDescription.appendValue("Pit: ") - .appendValue(deletePitInfo.getPitId()) - .appendText(" - delete result was not successful"); - return false; - } - } - return true; - } - - @Override - public void describeTo(Description description) { - description.appendText("Successful delete pit response"); - } -} diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulDeleteResponseMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulDeleteResponseMatcher.java deleted file mode 100644 index 6c10b2b6f8..0000000000 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulDeleteResponseMatcher.java +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.test.framework.matcher; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeDiagnosingMatcher; - -import org.opensearch.action.delete.DeleteResponse; -import org.opensearch.core.rest.RestStatus; - -class SuccessfulDeleteResponseMatcher extends TypeSafeDiagnosingMatcher { - - @Override - protected boolean matchesSafely(DeleteResponse response, Description mismatchDescription) { - if (!RestStatus.OK.equals(response.status())) { - mismatchDescription.appendText("has status ").appendValue(response.status()).appendText(" which denotes failure."); - return false; - } - if (response.getShardInfo().getFailures().length != 0) { - mismatchDescription.appendText("contains ") - .appendValue(response.getShardInfo().getFailures().length) - .appendText(" shard failures"); - return false; - } - return true; - } - - @Override - public void describeTo(Description description) { - description.appendText("Successful delete response"); - } -} diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulSearchResponseMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulSearchResponseMatcher.java deleted file mode 100644 index 21017a9014..0000000000 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulSearchResponseMatcher.java +++ /dev/null @@ -1,37 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.test.framework.matcher; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeDiagnosingMatcher; - -import org.opensearch.action.search.SearchResponse; -import org.opensearch.core.rest.RestStatus; - -class SuccessfulSearchResponseMatcher extends TypeSafeDiagnosingMatcher { - - @Override - protected boolean matchesSafely(SearchResponse searchResponse, Description mismatchDescription) { - if (RestStatus.OK.equals(searchResponse.status()) == false) { - mismatchDescription.appendText("has status ").appendValue(searchResponse.status()).appendText(" which denotes failure."); - return false; - } - if (searchResponse.getShardFailures().length != 0) { - mismatchDescription.appendText("contains ").appendValue(searchResponse.getShardFailures().length).appendText(" shard failures"); - return false; - } - return true; - } - - @Override - public void describeTo(Description description) { - description.appendText("Successful search response"); - } -} diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulUpdateResponseMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulUpdateResponseMatcher.java deleted file mode 100644 index 14faab0c4c..0000000000 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/SuccessfulUpdateResponseMatcher.java +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -* -*/ -package org.opensearch.test.framework.matcher; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeDiagnosingMatcher; - -import org.opensearch.action.update.UpdateResponse; -import org.opensearch.core.rest.RestStatus; - -class SuccessfulUpdateResponseMatcher extends TypeSafeDiagnosingMatcher { - - @Override - protected boolean matchesSafely(UpdateResponse response, Description mismatchDescription) { - if (!RestStatus.OK.equals(response.status())) { - mismatchDescription.appendText("has status ").appendValue(response.status()).appendText(" which denotes failure."); - return false; - } - if (response.getShardInfo().getFailures().length != 0) { - mismatchDescription.appendText("contains ") - .appendValue(response.getShardInfo().getFailures().length) - .appendText(" shard failures"); - return false; - } - return true; - } - - @Override - public void describeTo(Description description) { - description.appendText("Successful update response"); - } -}