From d47668756fda437dffb24a53f9b38f6579812d62 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Fri, 31 Mar 2023 08:13:47 -0500 Subject: [PATCH 01/16] Add Andriy Redko as a co-maintainer (#2610) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I nominated Andriy Redko (@reta) to be a co-maintainer for Security through our [nomination process](https://github.com/opensearch-project/.github/blob/main/MAINTAINERS.md#nomination). The maintainers have agreed, and Andriy has kindly accepted. Andriy’s involvement has taken many shapes, here are some highlights: * Code * Features work such as support for HTTP/2 * Manual Backports for CVEs * Build infrastructure such as Gradle changes * Test infrastructure such as fixes to OpenSSLTests * Particpation in issues * Adding contributors * @willyborankin * Active participate in triage meeting / process * Passion for quality Thank you Signed-off-by: Peter Nied --- .github/CODEOWNERS | 2 +- MAINTAINERS.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5478135783..5832378bff 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @cliu123 @cwperks @DarshitChanpura @davidlago @peternied @RyanL1997 @scrawfor99 +* @cliu123 @cwperks @DarshitChanpura @davidlago @peternied @RyanL1997 @scrawfor99 @reta diff --git a/MAINTAINERS.md b/MAINTAINERS.md index c72f5f3e3a..4605135a16 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -21,6 +21,7 @@ This document contains a list of maintainers in this repo. See [opensearch-proje | Craig Perkins | [cwperks](https://github.com/cwperks) | Amazon | | Ryan Liang | [RyanL1997](https://github.com/RyanL1997) | Amazon | | Stephen Crawford | [scrawfor99](https://github.com/scrawfor99) | Amazon | +| Andriy Redko | [reta](https://github.com/reta) | Aiven | ## Practices From 9bcf4a432c6a66a16972d62d2fc0fe40328feb65 Mon Sep 17 00:00:00 2001 From: Stephen Crawford <65832608+scrawfor99@users.noreply.github.com> Date: Fri, 31 Mar 2023 09:29:03 -0400 Subject: [PATCH 02/16] Update Spring and JSON-Smart (#2606) Signed-off-by: Stephen Crawford --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 4f4d5fcc61..1f32ff7e33 100644 --- a/build.gradle +++ b/build.gradle @@ -404,7 +404,7 @@ dependencies { implementation 'commons-lang:commons-lang:2.4' implementation 'commons-collections:commons-collections:3.2.2' implementation 'com.jayway.jsonpath:json-path:2.4.0' - implementation 'net.minidev:json-smart:2.4.7' + implementation 'net.minidev:json-smart:2.4.10' runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.10.8' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.10.8' runtimeOnly 'com.google.guava:failureaccess:1.0.1' @@ -462,7 +462,7 @@ dependencies { testCompileOnly 'org.apiguardian:apiguardian-api:1.0.0' // Kafka test execution testRuntimeOnly 'org.springframework.retry:spring-retry:1.3.3' - testRuntimeOnly ('org.springframework:spring-core:5.3.21') { + testRuntimeOnly ('org.springframework:spring-core:5.3.26') { exclude(group:'org.springframework', module: 'spring-jcl' ) } testRuntimeOnly 'org.scala-lang:scala-library:2.13.9' From a9bad908d6692be439694288958bbb4b42f4b577 Mon Sep 17 00:00:00 2001 From: Stephen Crawford <65832608+scrawfor99@users.noreply.github.com> Date: Fri, 31 Mar 2023 09:40:41 -0400 Subject: [PATCH 03/16] Expand Dls Tests for easier verification of functionality (#2585) * Additional DlsTests Signed-off-by: Stephen Crawford * DLS Tests Signed-off-by: Stephen Crawford * Fix comments Signed-off-by: Stephen Crawford * Fix bad changes Signed-off-by: Stephen Crawford --------- Signed-off-by: Stephen Crawford --- .../security/DlsIntegrationTests.java | 479 ++++++++++++++++++ .../security/dlic/dlsfls/DlsTest.java | 92 ++-- 2 files changed, 525 insertions(+), 46 deletions(-) create mode 100644 src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java diff --git a/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java b/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java new file mode 100644 index 0000000000..a99d584a50 --- /dev/null +++ b/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java @@ -0,0 +1,479 @@ +/* +* 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.TreeMap; +import java.util.function.BiFunction; + +import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; +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.search.SearchRequest; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.client.Client; +import org.opensearch.client.RestHighLevelClient; +import org.opensearch.index.query.QueryBuilders; +import org.opensearch.search.aggregations.Aggregation; +import org.opensearch.search.aggregations.metrics.ParsedAvg; +import org.opensearch.test.framework.TestSecurityConfig; +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.instanceOf; +import static org.hamcrest.Matchers.is; +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.security.Song.ARTIST_FIRST; +import static org.opensearch.security.Song.ARTIST_NO; +import static org.opensearch.security.Song.ARTIST_STRING; +import static org.opensearch.security.Song.ARTIST_TWINS; +import static org.opensearch.security.Song.ARTIST_UNKNOWN; +import static org.opensearch.security.Song.ARTIST_YES; +import static org.opensearch.security.Song.FIELD_ARTIST; +import static org.opensearch.security.Song.FIELD_STARS; +import static org.opensearch.security.Song.QUERY_TITLE_NEXT_SONG; +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.cluster.SearchRequestFactory.averageAggregationRequest; +import static org.opensearch.test.framework.matcher.SearchResponseMatchers.containAggregationWithNameAndType; +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; + +@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) +@ThreadLeakScope(ThreadLeakScope.Scope.NONE) +public class DlsIntegrationTests { + + static final String FIRST_INDEX_ID_SONG_1 = "INDEX_1_S1"; + static final String FIRST_INDEX_ID_SONG_2 = "INDEX_1_S2"; + static final String FIRST_INDEX_ID_SONG_3 = "INDEX_1_S3"; + static final String FIRST_INDEX_ID_SONG_4 = "INDEX_1_S4"; + static final String FIRST_INDEX_ID_SONG_5 = "INDEX_1_S5"; + static final String FIRST_INDEX_ID_SONG_6 = "INDEX_1_S6"; + static final String SECOND_INDEX_ID_SONG_1 = "INDEX_2_S1"; + static final String SECOND_INDEX_ID_SONG_2 = "INDEX_2_S2"; + static final String SECOND_INDEX_ID_SONG_3 = "INDEX_2_S3"; + static final String SECOND_INDEX_ID_SONG_4 = "INDEX_2_S4"; + + static final String INDEX_NAME_SUFFIX = "-test-index"; + static final String FIRST_INDEX_NAME = "first".concat(INDEX_NAME_SUFFIX); + static final String SECOND_INDEX_NAME = "second".concat(INDEX_NAME_SUFFIX); + static final String FIRST_INDEX_ALIAS = FIRST_INDEX_NAME.concat("-alias"); + static final String SECOND_INDEX_ALIAS = SECOND_INDEX_NAME.concat("-alias"); + static final String FIRST_INDEX_ALIAS_FILTERED_BY_NEXT_SONG_TITLE = FIRST_INDEX_NAME.concat("-filtered-by-next-song-title"); + static final String FIRST_INDEX_ALIAS_FILTERED_BY_TWINS_ARTIST = FIRST_INDEX_NAME.concat("-filtered-by-twins-artist"); + static final String FIRST_INDEX_ALIAS_FILTERED_BY_FIRST_ARTIST = FIRST_INDEX_NAME.concat("-filtered-by-first-artist"); + static final String ALL_INDICES_ALIAS = "_all"; + + + static final TestSecurityConfig.User ADMIN_USER = new TestSecurityConfig.User("admin").roles(ALL_ACCESS); + + /** + * User who is allowed to read all indices. + */ + static final TestSecurityConfig.User READ_ALL_USER = new TestSecurityConfig.User("read_all_user") + .roles( + new TestSecurityConfig.Role("read_all_user") + .clusterPermissions("cluster_composite_ops_ro") + .indexPermissions("read") + .on("*") + ); + + /** + * User who is allowed to see all fields on indices {@link #FIRST_INDEX_NAME} and {@link #SECOND_INDEX_NAME}. + */ + static final TestSecurityConfig.User READ_FIRST_AND_SECOND_USER = new TestSecurityConfig.User("read_first_and_second_user") + .roles( + new TestSecurityConfig.Role("first_index_reader") + .clusterPermissions("cluster_composite_ops_ro") + .indexPermissions("read") + .on(FIRST_INDEX_NAME), + new TestSecurityConfig.Role("second_index_reader") + .clusterPermissions("cluster_composite_ops_ro") + .indexPermissions("read") + .on(SECOND_INDEX_NAME) + ); + + /** + * User who is allowed to see documents on all indices where value of the {@link Song#FIELD_ARTIST} field matches {@link Song#ARTIST_STRING}. + */ + static final TestSecurityConfig.User READ_WHERE_FIELD_ARTIST_MATCHES_ARTIST_STRING = new TestSecurityConfig.User("read_where_field_artist_matches_artist_string") + .roles( + new TestSecurityConfig.Role("read_where_field_artist_matches_artist_string") + .clusterPermissions("cluster_composite_ops_ro") + .indexPermissions("read") + .dls(String.format("{\"match\":{\"%s\":\"%s\"}}", FIELD_ARTIST, ARTIST_STRING)) + .on("*") + ); + + /** + * User who is allowed to see documents on all indices where value of the {@link Song#FIELD_ARTIST} field matches {@link Song#ARTIST_TWINS} OR {@link Song#FIELD_STARS} is greater than five. + */ + static final TestSecurityConfig.User READ_WHERE_FIELD_ARTIST_MATCHES_ARTIST_TWINS_OR_FIELD_STARS_GREATER_THAN_FIVE = new TestSecurityConfig.User("read_where_field_artist_matches_artist_twins_or_field_stars_greater_than_five") + .roles( + new TestSecurityConfig.Role("read_where_field_artist_matches_artist_twins") + .clusterPermissions("cluster_composite_ops_ro") + .indexPermissions("read") + .dls(String.format("{\"match\":{\"%s\":\"%s\"}}", FIELD_ARTIST, ARTIST_TWINS)) + .on("*"), + new TestSecurityConfig.Role("read_where_field_stars_greater_than_five") + .clusterPermissions("cluster_composite_ops_ro") + .indexPermissions("read") + .dls(String.format("{\"range\":{\"%s\":{\"gt\":%d}}}", FIELD_STARS, 5)) + .on("*") + ); + + + /** + * User who is allowed to see documents on indices where value of {@link Song#FIELD_ARTIST} field matches {@link Song#ARTIST_TWINS} or {@link Song#FIELD_ARTIST} field matches {@link Song#ARTIST_FIRST}: + */ + static final TestSecurityConfig.User READ_WHERE_FIELD_ARTIST_MATCHES_ARTIST_TWINS_OR_MATCHES_ARTIST_FIRST = new TestSecurityConfig.User("read_where_field_artist_matches_artist_twins_or_artist_first") + .roles( + new TestSecurityConfig.Role("read_where_field_artist_matches_artist_twins") + .clusterPermissions("cluster_composite_ops_ro") + .indexPermissions("read") + .dls(String.format("{\"match\":{\"%s\":\"%s\"}}", FIELD_ARTIST, ARTIST_TWINS)) + .on(FIRST_INDEX_NAME), + new TestSecurityConfig.Role("read_where_field_artist_matches_artist_first") + .clusterPermissions("cluster_composite_ops_ro") + .indexPermissions("read") + .dls(String.format("{\"match\":{\"%s\":\"%s\"}}", FIELD_ARTIST, ARTIST_FIRST)) + .on(SECOND_INDEX_NAME) + ); + + /** + * User who is allowed to see documents on all indices where value of the {@link Song#FIELD_STARS} is less than three. + */ + static final TestSecurityConfig.User READ_WHERE_STARS_LESS_THAN_THREE = new TestSecurityConfig.User("read_where_stars_less_than_three") + .roles( + new TestSecurityConfig.Role("read_where_stars_less_than_three") + .clusterPermissions("cluster_composite_ops_ro") + .indexPermissions("read") + .dls(String.format("{\"range\":{\"%s\":{\"lt\":%d}}}", FIELD_STARS, 3)) + .on("*") + ); + + @ClassRule + public static final LocalCluster cluster = new LocalCluster.Builder() + .clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS).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, READ_ALL_USER, READ_FIRST_AND_SECOND_USER, READ_WHERE_FIELD_ARTIST_MATCHES_ARTIST_STRING, + READ_WHERE_STARS_LESS_THAN_THREE, READ_WHERE_FIELD_ARTIST_MATCHES_ARTIST_TWINS_OR_FIELD_STARS_GREATER_THAN_FIVE, + READ_WHERE_FIELD_ARTIST_MATCHES_ARTIST_TWINS_OR_MATCHES_ARTIST_FIRST + ) + .build(); + + /** + * Function that returns id assigned to song with title equal to given title or throws {@link RuntimeException} + * when no song matches. + */ + static final BiFunction, String, String> FIND_ID_OF_SONG_WITH_TITLE = (map, title) -> map.entrySet() + .stream().filter(entry -> title.equals(entry.getValue().getTitle())) + .findAny() + .map(Map.Entry::getKey) + .orElseThrow(() -> new RuntimeException("Cannot find id of song with title: " + title)); + + /** + * Function that returns id assigned to song with artist equal to given artist or throws {@link RuntimeException} + * when no song matches. + */ + static final BiFunction, String, String> FIND_ID_OF_SONG_WITH_ARTIST = (map, artist) -> map.entrySet() + .stream().filter(entry -> artist.equals(entry.getValue().getArtist())) + .findAny() + .map(Map.Entry::getKey) + .orElseThrow(() -> new RuntimeException("Cannot find id of song with artist: " + artist)); + + static final TreeMap FIRST_INDEX_SONGS_BY_ID = new TreeMap<>() {{ // SONG = (String artist, String title, String lyrics, Integer stars, String genre) + put(FIRST_INDEX_ID_SONG_1, SONGS[0]); // (ARTIST_FIRST, TITLE_MAGNUM_OPUS ,LYRICS_1, 1, GENRE_ROCK) + put(FIRST_INDEX_ID_SONG_2, SONGS[1]); // (ARTIST_STRING, TITLE_SONG_1_PLUS_1, LYRICS_2, 2, GENRE_BLUES), + put(FIRST_INDEX_ID_SONG_3, SONGS[2]); // (ARTIST_TWINS, TITLE_NEXT_SONG, LYRICS_3, 3, GENRE_JAZZ), + put(FIRST_INDEX_ID_SONG_4, SONGS[3]); // (ARTIST_NO, TITLE_POISON, LYRICS_4, 4, GENRE_ROCK), + put(FIRST_INDEX_ID_SONG_5, SONGS[4]); // (ARTIST_YES, TITLE_AFFIRMATIVE,LYRICS_5, 5, GENRE_BLUES), + put(FIRST_INDEX_ID_SONG_6, SONGS[5]); // (ARTIST_UNKNOWN, TITLE_CONFIDENTIAL, LYRICS_6, 6, GENRE_JAZZ) + }}; + + static final TreeMap SECOND_INDEX_SONGS_BY_ID = new TreeMap<>() {{ + put(SECOND_INDEX_ID_SONG_1, SONGS[3]); // (ARTIST_NO, TITLE_POISON, LYRICS_4, 4, GENRE_ROCK), + put(SECOND_INDEX_ID_SONG_2, SONGS[2]); // (ARTIST_TWINS, TITLE_NEXT_SONG, LYRICS_3, 3, GENRE_JAZZ), + put(SECOND_INDEX_ID_SONG_3, SONGS[1]); // (ARTIST_STRING, TITLE_SONG_1_PLUS_1, LYRICS_2, 2, GENRE_BLUES), + put(SECOND_INDEX_ID_SONG_4, SONGS[0]); // (ARTIST_FIRST, TITLE_MAGNUM_OPUS ,LYRICS_1, 1, GENRE_ROCK) + }}; + + @BeforeClass + public static void createTestData() { + try(Client client = cluster.getInternalNodeClient()){ + FIRST_INDEX_SONGS_BY_ID.forEach((id, song) -> { + client.prepareIndex(FIRST_INDEX_NAME).setId(id).setRefreshPolicy(IMMEDIATE).setSource(song.asMap()).get(); + }); + + client.admin().indices().aliases(new IndicesAliasesRequest().addAliasAction(new IndicesAliasesRequest.AliasActions(ADD) + .indices(FIRST_INDEX_NAME) + .alias(FIRST_INDEX_ALIAS) + )).actionGet(); + client.admin().indices().aliases(new IndicesAliasesRequest().addAliasAction(new IndicesAliasesRequest.AliasActions(ADD) + .index(FIRST_INDEX_NAME) + .alias(FIRST_INDEX_ALIAS_FILTERED_BY_NEXT_SONG_TITLE) + .filter(QueryBuilders.queryStringQuery(QUERY_TITLE_NEXT_SONG)) + )).actionGet(); + client.admin().indices().aliases(new IndicesAliasesRequest().addAliasAction(new IndicesAliasesRequest.AliasActions(ADD) + .index(FIRST_INDEX_NAME) + .alias(FIRST_INDEX_ALIAS_FILTERED_BY_TWINS_ARTIST) + .filter(QueryBuilders.queryStringQuery(String.format("%s:%s", FIELD_ARTIST, ARTIST_TWINS))) + )).actionGet(); + client.admin().indices().aliases(new IndicesAliasesRequest().addAliasAction(new IndicesAliasesRequest.AliasActions(ADD) + .index(FIRST_INDEX_NAME) + .alias(FIRST_INDEX_ALIAS_FILTERED_BY_FIRST_ARTIST) + .filter(QueryBuilders.queryStringQuery(String.format("%s:%s", FIELD_ARTIST, ARTIST_FIRST))) + )).actionGet(); + + SECOND_INDEX_SONGS_BY_ID.forEach((id, song) -> { + client.prepareIndex(SECOND_INDEX_NAME).setId(id).setRefreshPolicy(IMMEDIATE).setSource(song.asMap()).get(); + }); + client.admin().indices().aliases(new IndicesAliasesRequest().addAliasAction(new IndicesAliasesRequest.AliasActions(ADD) + .indices(SECOND_INDEX_NAME) + .alias(SECOND_INDEX_ALIAS) + )).actionGet(); + } + } + + @Test + public void testShouldSearchAll() throws IOException { + + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { + SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_NAME); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); + assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); + assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); + assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); + assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); + + searchRequest = new SearchRequest(SECOND_INDEX_NAME); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); + } + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_FIRST_AND_SECOND_USER)) { + SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_NAME); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); + assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); + assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); + assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); + assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); + + searchRequest = new SearchRequest(SECOND_INDEX_NAME); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); + } + } + + @Test + public void testShouldSearchI1_S2I2_S3() throws IOException { + + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_WHERE_FIELD_ARTIST_MATCHES_ARTIST_STRING)) { + SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_NAME); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_STRING)); + + searchRequest = new SearchRequest(SECOND_INDEX_NAME); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_STRING)); + } + } + + public void testShouldSearchI1_S3I1_S6I2_S2() throws IOException { + + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_WHERE_FIELD_ARTIST_MATCHES_ARTIST_TWINS_OR_FIELD_STARS_GREATER_THAN_FIVE)) { + SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_NAME); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(2)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_TWINS)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_UNKNOWN)); + + searchRequest = new SearchRequest(SECOND_INDEX_NAME); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_TWINS)); + } + } + + public void testShouldSearchI1_S1I1_S3I2_S2I2_S4() throws IOException { + + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_WHERE_FIELD_ARTIST_MATCHES_ARTIST_TWINS_OR_MATCHES_ARTIST_FIRST)) { + SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_NAME); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(2)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_TWINS)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_FIRST)); + + searchRequest = new SearchRequest(SECOND_INDEX_NAME); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(2)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_TWINS)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_FIRST)); + } + } + + public void testShouldSearchStarsLessThanThree() throws IOException { + + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_WHERE_STARS_LESS_THAN_THREE)) { + SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_NAME); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(2)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); + + searchRequest = new SearchRequest(SECOND_INDEX_NAME); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(2)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_STRING)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_FIRST)); + } + } + + + @Test + public void testSearchForAllDocumentsWithIndexPattern() throws IOException { + + //DLS + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { + SearchRequest searchRequest = new SearchRequest("*".concat(FIRST_INDEX_NAME)); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); + assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); + assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); + assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); + assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); + + searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); + } + } + + @Test + public void testSearchForAllDocumentsWithAlias() throws IOException { + + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { + SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); + assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); + assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); + assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); + assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); + + searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); + } + } + + @Test + public void testAggregateAndComputeStarRatings() throws IOException { + + //DLS + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_WHERE_FIELD_ARTIST_MATCHES_ARTIST_TWINS_OR_MATCHES_ARTIST_FIRST)) { + String aggregationName = "averageStars"; + Song song = FIRST_INDEX_SONGS_BY_ID.get(FIND_ID_OF_SONG_WITH_ARTIST.apply(FIRST_INDEX_SONGS_BY_ID, ARTIST_TWINS)); + + SearchRequest searchRequest = averageAggregationRequest(FIRST_INDEX_NAME, aggregationName, FIELD_STARS); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, containAggregationWithNameAndType(aggregationName, "avg")); + Aggregation actualAggregation = searchResponse.getAggregations().get(aggregationName); + assertThat(actualAggregation, instanceOf(ParsedAvg.class)); + assertThat(((ParsedAvg) actualAggregation).getValue(), is(song.getStars()*1.0)); + } + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_WHERE_FIELD_ARTIST_MATCHES_ARTIST_TWINS_OR_FIELD_STARS_GREATER_THAN_FIVE)) { + String aggregationName = "averageStars"; + SearchRequest searchRequest = averageAggregationRequest(FIRST_INDEX_NAME, aggregationName, FIELD_STARS); + + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, containAggregationWithNameAndType(aggregationName, "avg")); + Aggregation actualAggregation = searchResponse.getAggregations().get(aggregationName); + assertThat(actualAggregation, instanceOf(ParsedAvg.class)); + assertThat(((ParsedAvg) actualAggregation).getValue(), is(4.5)); + } + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_WHERE_STARS_LESS_THAN_THREE)) { + String aggregationName = "averageStars"; + SearchRequest searchRequest = averageAggregationRequest(FIRST_INDEX_NAME, aggregationName, FIELD_STARS); + + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, containAggregationWithNameAndType(aggregationName, "avg")); + Aggregation actualAggregation = searchResponse.getAggregations().get(aggregationName); + assertThat(actualAggregation, instanceOf(ParsedAvg.class)); + assertThat(((ParsedAvg) actualAggregation).getValue(), is(1.5)); + } + } +} diff --git a/src/test/java/org/opensearch/security/dlic/dlsfls/DlsTest.java b/src/test/java/org/opensearch/security/dlic/dlsfls/DlsTest.java index 45a1e7b53f..5405146263 100644 --- a/src/test/java/org/opensearch/security/dlic/dlsfls/DlsTest.java +++ b/src/test/java/org/opensearch/security/dlic/dlsfls/DlsTest.java @@ -53,13 +53,13 @@ public void testDlsAggregations() throws Exception { String query = "{"+ - "\"query\" : {"+ - "\"match_all\": {}"+ - "},"+ - "\"aggs\" : {"+ + "\"query\" : {"+ + "\"match_all\": {}"+ + "},"+ + "\"aggs\" : {"+ "\"thesum\" : { \"sum\" : { \"field\" : \"amount\" } }"+ - "}"+ - "}"; + "}"+ + "}"; HttpResponse res; Assert.assertEquals(HttpStatus.SC_OK, (res = rh.executePostRequest("/deals/_search?pretty", query, encodeBasicHeader("dept_manager", "password"))).getStatusCode()); @@ -113,17 +113,17 @@ public void testDls() throws Exception { String query = - "{"+ - "\"query\": {"+ - "\"range\" : {"+ - "\"amount\" : {"+ - "\"gte\" : 8,"+ - "\"lte\" : 20,"+ - "\"boost\" : 3.0"+ + "{"+ + "\"query\": {"+ + "\"range\" : {"+ + "\"amount\" : {"+ + "\"gte\" : 8,"+ + "\"lte\" : 20,"+ + "\"boost\" : 3.0"+ "}"+ - "}"+ - "}"+ - "}"; + "}"+ + "}"+ + "}"; Assert.assertEquals(HttpStatus.SC_OK, (res = rh.executePostRequest("/deals/_search?pretty", query,encodeBasicHeader("dept_manager", "password"))).getStatusCode()); @@ -133,16 +133,16 @@ public void testDls() throws Exception { query = "{"+ - "\"query\": {"+ - "\"range\" : {"+ - "\"amount\" : {"+ - "\"gte\" : 100,"+ - "\"lte\" : 2000,"+ - "\"boost\" : 2.0"+ - "}"+ + "\"query\": {"+ + "\"range\" : {"+ + "\"amount\" : {"+ + "\"gte\" : 100,"+ + "\"lte\" : 2000,"+ + "\"boost\" : 2.0"+ "}"+ - "}"+ - "}"; + "}"+ + "}"+ + "}"; Assert.assertEquals(HttpStatus.SC_OK, (res = rh.executePostRequest("/deals/_search?pretty", query,encodeBasicHeader("dept_manager", "password"))).getStatusCode()); @@ -179,9 +179,9 @@ public void testDls() throws Exception { //msearch String msearchBody = "{\"index\":\"deals\", \"ignore_unavailable\": true}"+System.lineSeparator()+ - "{\"size\":10, \"query\":{\"bool\":{\"must\":{\"match_all\":{}}}}}"+System.lineSeparator()+ - "{\"index\":\"deals\", \"ignore_unavailable\": true}"+System.lineSeparator()+ - "{\"size\":10, \"query\":{\"bool\":{\"must\":{\"match_all\":{}}}}}"+System.lineSeparator(); + "{\"size\":10, \"query\":{\"bool\":{\"must\":{\"match_all\":{}}}}}"+System.lineSeparator()+ + "{\"index\":\"deals\", \"ignore_unavailable\": true}"+System.lineSeparator()+ + "{\"size\":10, \"query\":{\"bool\":{\"must\":{\"match_all\":{}}}}}"+System.lineSeparator(); Assert.assertEquals(HttpStatus.SC_OK, (res = rh.executePostRequest("_msearch?pretty", msearchBody, encodeBasicHeader("dept_manager", "password"))).getStatusCode()); @@ -193,16 +193,16 @@ public void testDls() throws Exception { String mgetBody = "{"+ "\"docs\" : ["+ - "{"+ - "\"_index\" : \"deals\","+ - "\"_id\" : \"1\""+ - " },"+ - " {"+ - "\"_index\" : \"deals\","+ - " \"_id\" : \"2\""+ - "}"+ + "{"+ + "\"_index\" : \"deals\","+ + "\"_id\" : \"1\""+ + " },"+ + " {"+ + "\"_index\" : \"deals\","+ + " \"_id\" : \"2\""+ + "}"+ "]"+ - "}"; + "}"; Assert.assertEquals(HttpStatus.SC_OK, (res = rh.executePostRequest("_mget?pretty", mgetBody, encodeBasicHeader("dept_manager", "password"))).getStatusCode()); Assert.assertFalse(res.getBody().contains("_opendistro_security_dls_query")); @@ -222,16 +222,16 @@ public void testNonDls() throws Exception { "{"+ "\"_source\": false,"+ - "\"query\": {"+ - "\"range\" : {"+ - "\"amount\" : {"+ - "\"gte\" : 100,"+ - "\"lte\" : 2000,"+ - "\"boost\" : 2.0"+ - "}"+ + "\"query\": {"+ + "\"range\" : {"+ + "\"amount\" : {"+ + "\"gte\" : 100,"+ + "\"lte\" : 2000,"+ + "\"boost\" : 2.0"+ "}"+ - "}"+ - "}"; + "}"+ + "}"+ + "}"; Assert.assertEquals(HttpStatus.SC_OK, (res = rh.executePostRequest("/deals/_search?pretty", query,encodeBasicHeader("dept_manager", "password"))).getStatusCode()); From 8fdc45aec7fa85af0b850d4b9e60b314fe7a020a Mon Sep 17 00:00:00 2001 From: Ryan Liang <109499885+RyanL1997@users.noreply.github.com> Date: Mon, 3 Apr 2023 18:04:59 -0700 Subject: [PATCH 04/16] Upgrade spotbugs to version 5.0.14 (#2639) Signed-off-by: Ryan Liang --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1f32ff7e33..916f1ec5e3 100644 --- a/build.gradle +++ b/build.gradle @@ -57,7 +57,7 @@ plugins { id 'com.netflix.nebula.ospackage' version "11.0.0" id "org.gradle.test-retry" version "1.5.2" id 'eclipse' - id "com.github.spotbugs" version "5.0.13" + id "com.github.spotbugs" version "5.0.14" id "com.google.osdetector" version "1.7.3" } From 4988a74cdeac09be2e2657c6ab0793a63af76065 Mon Sep 17 00:00:00 2001 From: Stephen Crawford <65832608+scrawfor99@users.noreply.github.com> Date: Wed, 5 Apr 2023 02:30:07 -0400 Subject: [PATCH 05/16] Remove DLS from FlsDlsAndFieldMasking to avoid duplicates (#2637) * Remove DLS from FlsDlsAndFieldMasking to avoid duplicates with separated out tests Signed-off-by: Stephen Crawford --- ...Test.java => FlsAndFieldMaskingTests.java} | 206 +----------------- 1 file changed, 1 insertion(+), 205 deletions(-) rename src/integrationTest/java/org/opensearch/security/{FlsDlsAndFieldMaskingTest.java => FlsAndFieldMaskingTests.java} (79%) diff --git a/src/integrationTest/java/org/opensearch/security/FlsDlsAndFieldMaskingTest.java b/src/integrationTest/java/org/opensearch/security/FlsAndFieldMaskingTests.java similarity index 79% rename from src/integrationTest/java/org/opensearch/security/FlsDlsAndFieldMaskingTest.java rename to src/integrationTest/java/org/opensearch/security/FlsAndFieldMaskingTests.java index 4bef7ef4f6..692a3d8e4f 100644 --- a/src/integrationTest/java/org/opensearch/security/FlsDlsAndFieldMaskingTest.java +++ b/src/integrationTest/java/org/opensearch/security/FlsAndFieldMaskingTests.java @@ -59,13 +59,11 @@ import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; 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.security.Song.ARTIST_FIRST; -import static org.opensearch.security.Song.ARTIST_NO; import static org.opensearch.security.Song.ARTIST_STRING; import static org.opensearch.security.Song.ARTIST_TWINS; import static org.opensearch.security.Song.FIELD_ARTIST; @@ -101,7 +99,7 @@ @RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) @ThreadLeakScope(ThreadLeakScope.Scope.NONE) -public class FlsDlsAndFieldMaskingTest { +public class FlsAndFieldMaskingTests { static final String FIRST_INDEX_ID_SONG_1 = "INDEX_1_S1"; static final String FIRST_INDEX_ID_SONG_2 = "INDEX_1_S2"; @@ -472,23 +470,6 @@ public void searchForDocuments() throws IOException { assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, song.getArtist())); assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_STARS, song.getStars())); } - - //DLS - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(TWINS_FIRST_ARTIST_READER)) { - SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_NAME); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_TWINS)); - - searchRequest = new SearchRequest(SECOND_INDEX_NAME); - searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); - } } @Test @@ -524,23 +505,6 @@ public void searchForDocumentsWithIndexPattern() throws IOException { assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, song.getArtist())); assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_STARS, song.getStars())); } - - //DLS - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(TWINS_FIRST_ARTIST_READER)) { - SearchRequest searchRequest = new SearchRequest("*".concat(FIRST_INDEX_NAME)); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_TWINS)); - - searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); - searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); - } } @Test @@ -575,23 +539,6 @@ public void searchForDocumentsViaAlias() throws IOException { assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, song.getArtist())); assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_STARS, song.getStars())); } - - //DLS - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(TWINS_FIRST_ARTIST_READER)) { - SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_TWINS)); - - searchRequest = new SearchRequest(SECOND_INDEX_ALIAS); - searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); - } } @Test @@ -612,22 +559,6 @@ public void searchForDocumentsViaFilteredAlias() throws IOException { assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, VALUE_TO_MASKED_VALUE.apply(song.getArtist()))); assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_STARS, song.getStars())); } - - //DLS - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(TWINS_FIRST_ARTIST_READER)) { - SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS_FILTERED_BY_TWINS_ARTIST); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_TWINS)); - - searchRequest = new SearchRequest(FIRST_INDEX_ALIAS_FILTERED_BY_FIRST_ARTIST); - searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(0)); - } } @Test @@ -663,17 +594,6 @@ public void searchForDocumentsViaAllIndicesAlias() throws IOException { assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, VALUE_TO_MASKED_VALUE.apply(song.getArtist()))); assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_STARS, song.getStars())); } - - //DLS - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(ALL_INDICES_STRING_ARTIST_READER)) { - SearchRequest searchRequest = new SearchRequest(ALL_INDICES_ALIAS); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(2)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_STRING)); - assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); - } } @Test @@ -701,23 +621,6 @@ public void scrollOverSearchResults() throws IOException { assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, VALUE_TO_MASKED_VALUE.apply(song.getArtist()))); assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_STARS, song.getStars())); } - - //DLS - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(TWINS_FIRST_ARTIST_READER)) { - SearchRequest searchRequest = searchRequestWithScroll(FIRST_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(searchResponse, numberOfTotalHitsIsEqualTo(1)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_TWINS)); - } } @Test @@ -739,33 +642,6 @@ public void aggregateDataAndComputeAverage() throws IOException { assertThat(actualAggregation, instanceOf(ParsedAvg.class)); assertThat(((ParsedAvg) actualAggregation).getValue(), is(expectedValue)); } - - //DLS - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(TWINS_FIRST_ARTIST_READER)) { - String aggregationName = "averageStars"; - Song song = FIRST_INDEX_SONGS_BY_ID.get(FIND_ID_OF_SONG_WITH_ARTIST.apply(FIRST_INDEX_SONGS_BY_ID, ARTIST_TWINS)); - - SearchRequest searchRequest = averageAggregationRequest(FIRST_INDEX_NAME, aggregationName, FIELD_STARS); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, containAggregationWithNameAndType(aggregationName, "avg")); - Aggregation actualAggregation = searchResponse.getAggregations().get(aggregationName); - assertThat(actualAggregation, instanceOf(ParsedAvg.class)); - assertThat(((ParsedAvg) actualAggregation).getValue(), is(song.getStars()*1.0)); - } - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(ALL_INDICES_STARS_LESS_THAN_ZERO_READER)) { - String aggregationName = "averageStars"; - SearchRequest searchRequest = averageAggregationRequest(FIRST_INDEX_NAME, aggregationName, FIELD_STARS); - - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, containAggregationWithNameAndType(aggregationName, "avg")); - Aggregation actualAggregation = searchResponse.getAggregations().get(aggregationName); - assertThat(actualAggregation, instanceOf(ParsedAvg.class)); - assertThat(((ParsedAvg) actualAggregation).getValue(), is(Double.POSITIVE_INFINITY)); - } } @Test @@ -792,21 +668,6 @@ public void getDocument() throws IOException { assertThat(response, documentContainField(FIELD_ARTIST, song.getArtist())); assertThat(response, documentContainField(FIELD_STARS, song.getStars())); } - - //DLS - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(TWINS_FIRST_ARTIST_READER)) { - String songId = FIND_ID_OF_SONG_WITH_ARTIST.apply(FIRST_INDEX_SONGS_BY_ID, ARTIST_TWINS); - - GetResponse response = restHighLevelClient.get(new GetRequest(FIRST_INDEX_NAME, songId), DEFAULT); - - assertThat(response, containDocument(FIRST_INDEX_NAME, songId)); - - songId = FIND_ID_OF_SONG_WITH_ARTIST.apply(FIRST_INDEX_SONGS_BY_ID, ARTIST_STRING); - - response = restHighLevelClient.get(new GetRequest(FIRST_INDEX_NAME, songId), DEFAULT); - - assertThat(response, not(containDocument(FIRST_INDEX_NAME, songId))); - } } @Test @@ -848,32 +709,6 @@ public void multiGetDocuments() throws IOException { )); } } - - //DLS - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(TWINS_FIRST_ARTIST_READER)) { - List indicesToCheck = List.of(FIRST_INDEX_NAME, FIRST_INDEX_ALIAS); - String firstSongId = FIND_ID_OF_SONG_WITH_ARTIST.apply(FIRST_INDEX_SONGS_BY_ID, ARTIST_NO); - String secondSongId = FIND_ID_OF_SONG_WITH_ARTIST.apply(FIRST_INDEX_SONGS_BY_ID, ARTIST_STRING); - - for(String index : indicesToCheck) { - MultiGetRequest request = new MultiGetRequest(); - request.add(new MultiGetRequest.Item(index, firstSongId)); - request.add(new MultiGetRequest.Item(index, secondSongId)); - - MultiGetResponse response = restHighLevelClient.mget(request, DEFAULT); - - assertThat(response, isSuccessfulMultiGetResponse()); - assertThat(response, numberOfGetItemResponsesIsEqualTo(2)); - - MultiGetItemResponse[] responses = response.getResponses(); - assertThat(responses[0].getResponse(), allOf( - not(containDocument(FIRST_INDEX_NAME, firstSongId))) - ); - assertThat(responses[1].getResponse(), allOf( - not(containDocument(FIRST_INDEX_NAME, secondSongId))) - ); - } - } } @Test @@ -916,33 +751,6 @@ public void multiSearchDocuments() throws IOException { )); } } - - //DLS - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(TWINS_FIRST_ARTIST_READER)) { - List> indicesToCheck = List.of( - List.of(FIRST_INDEX_NAME, SECOND_INDEX_NAME), - List.of(FIRST_INDEX_ALIAS, SECOND_INDEX_ALIAS) - ); - String firstSongId = FIND_ID_OF_SONG_WITH_ARTIST.apply(FIRST_INDEX_SONGS_BY_ID, ARTIST_TWINS); - String secondSongId = FIND_ID_OF_SONG_WITH_ARTIST.apply(SECOND_INDEX_SONGS_BY_ID, ARTIST_FIRST); - - for (List indices : indicesToCheck) { - MultiSearchRequest request = new MultiSearchRequest(); - indices.forEach(index -> request.add(new SearchRequest(index))); - - MultiSearchResponse response = restHighLevelClient.msearch(request, DEFAULT); - - assertThat(response, isSuccessfulMultiSearchResponse()); - assertThat(response, numberOfSearchItemResponsesIsEqualTo(2)); - - MultiSearchResponse.Item[] responses = response.getResponses(); - - assertThat(responses[0].getResponse(), searchHitsContainDocumentWithId(0, FIRST_INDEX_NAME, firstSongId)); - assertThat(responses[0].getResponse(), searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_TWINS)); - assertThat(responses[1].getResponse(), searchHitsContainDocumentWithId(0, SECOND_INDEX_NAME, secondSongId)); - assertThat(responses[1].getResponse(), searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); - } - } } @Test @@ -958,18 +766,6 @@ public void getFieldCapabilities() throws IOException { assertThat(response, containsFieldWithNameAndType(FIELD_TITLE, "text")); assertThat(response, containsFieldWithNameAndType(FIELD_LYRICS, "text")); } - - //DLS - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(TWINS_FIRST_ARTIST_READER)) { - FieldCapabilitiesRequest request = new FieldCapabilitiesRequest().indices(FIRST_INDEX_NAME).fields(FIELD_ARTIST, FIELD_TITLE, FIELD_LYRICS); - FieldCapabilitiesResponse response = restHighLevelClient.fieldCaps(request, DEFAULT); - - assertThat(response, containsExactlyIndices(FIRST_INDEX_NAME)); - assertThat(response, numberOfFieldsIsEqualTo(3)); - assertThat(response, containsFieldWithNameAndType(FIELD_ARTIST, "text")); - assertThat(response, containsFieldWithNameAndType(FIELD_TITLE, "text")); - assertThat(response, containsFieldWithNameAndType(FIELD_LYRICS, "text")); - } } } From 6446268bdf4fd9f39d0e669aafa227b582dbf4e6 Mon Sep 17 00:00:00 2001 From: Andrey Pleskach Date: Thu, 6 Apr 2023 22:58:45 +0200 Subject: [PATCH 06/16] Separate config option to enable restapi: permissions (#2605) Added config settings plugins.security.restapi.admin.enabled which enables/disables :resapi permissions. Default is false Signed-off-by: Andrey Pleskach --- .../security/OpenSearchSecurityPlugin.java | 3 +- .../dlic/rest/api/AbstractApiAction.java | 6 ++- .../api/RestApiAdminPrivilegesEvaluator.java | 33 +++++++++---- .../dlic/rest/api/SecuritySSLCertsAction.java | 4 -- .../security/support/ConfigConstants.java | 2 +- .../dlic/rest/api/ActionGroupsApiTest.java | 7 +-- .../dlic/rest/api/AllowlistApiTest.java | 5 +- .../dlic/rest/api/NodesDnApiTest.java | 6 ++- .../security/dlic/rest/api/RolesApiTest.java | 15 +++--- .../dlic/rest/api/RolesMappingApiTest.java | 5 +- .../dlic/rest/api/SslCertsApiTest.java | 47 +++++++++---------- .../security/dlic/rest/api/UserApiTest.java | 5 +- 12 files changed, 83 insertions(+), 55 deletions(-) diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index ce64299f13..af089584a9 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -1027,7 +1027,8 @@ public List> getSettings() { // OpenSearch Security - REST API settings.add(Setting.listSetting(ConfigConstants.SECURITY_RESTAPI_ROLES_ENABLED, Collections.emptyList(), Function.identity(), Property.NodeScope)); //not filtered here settings.add(Setting.groupSetting(ConfigConstants.SECURITY_RESTAPI_ENDPOINTS_DISABLED + ".", Property.NodeScope)); - + settings.add(Setting.boolSetting(ConfigConstants.SECURITY_RESTAPI_ADMIN_ENABLED, false, Property.NodeScope, Property.Filtered)); + settings.add(Setting.simpleString(ConfigConstants.SECURITY_RESTAPI_PASSWORD_VALIDATION_REGEX, Property.NodeScope, Property.Filtered)); settings.add(Setting.simpleString(ConfigConstants.SECURITY_RESTAPI_PASSWORD_VALIDATION_ERROR_MESSAGE, Property.NodeScope, Property.Filtered)); diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index 0e98124b6f..fa69be0ad4 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -66,6 +66,8 @@ import org.opensearch.security.user.User; import org.opensearch.threadpool.ThreadPool; +import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ADMIN_ENABLED; + public abstract class AbstractApiAction extends BaseRestHandler { protected final Logger log = LogManager.getLogger(this.getClass()); @@ -94,7 +96,9 @@ protected AbstractApiAction(final Settings settings, final Path configPath, fina this.restApiPrivilegesEvaluator = new RestApiPrivilegesEvaluator(settings, adminDNs, evaluator, principalExtractor, configPath, threadPool); this.restApiAdminPrivilegesEvaluator = - new RestApiAdminPrivilegesEvaluator(threadPool.getThreadContext(), evaluator, adminDNs); + new RestApiAdminPrivilegesEvaluator( + threadPool.getThreadContext(), evaluator, adminDNs, + settings.getAsBoolean(SECURITY_RESTAPI_ADMIN_ENABLED, false)); this.auditLog = auditLog; } diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiAdminPrivilegesEvaluator.java b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiAdminPrivilegesEvaluator.java index c3449e99bb..c8e44ee4ca 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiAdminPrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiAdminPrivilegesEvaluator.java @@ -29,6 +29,8 @@ import org.opensearch.security.support.WildcardMatcher; import org.opensearch.security.user.User; +import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ADMIN_ENABLED; + public class RestApiAdminPrivilegesEvaluator { protected final Logger logger = LogManager.getLogger(RestApiAdminPrivilegesEvaluator.class); @@ -85,13 +87,17 @@ default String build() { private final AdminDNs adminDNs; + private final boolean restapiAdminEnabled; + public RestApiAdminPrivilegesEvaluator( final ThreadContext threadContext, final PrivilegesEvaluator privilegesEvaluator, - final AdminDNs adminDNs) { + final AdminDNs adminDNs, + final boolean restapiAdminEnabled) { this.threadContext = threadContext; this.privilegesEvaluator = privilegesEvaluator; this.adminDNs = adminDNs; + this.restapiAdminEnabled = restapiAdminEnabled; } public boolean isCurrentUserRestApiAdminFor(final Endpoint endpoint, final String action) { @@ -108,20 +114,31 @@ public boolean isCurrentUserRestApiAdminFor(final Endpoint endpoint, final Strin return true; } if (!ENDPOINTS_WITH_PERMISSIONS.containsKey(endpoint)) { - if (logger.isDebugEnabled()) { - logger.debug("No permission found for {} endpoint", endpoint); - } + logger.debug("No permission found for {} endpoint", endpoint); return false; } final String permission = ENDPOINTS_WITH_PERMISSIONS.get(endpoint).build(action); - if (logger.isDebugEnabled()) { - logger.debug("Checking permission {} for endpoint {}", permission, endpoint); - } - return privilegesEvaluator.hasRestAdminPermissions( + final boolean hasAccess = privilegesEvaluator.hasRestAdminPermissions( userAndRemoteAddress.getLeft(), userAndRemoteAddress.getRight(), permission ); + if (logger.isDebugEnabled()) { + logger.debug( + "User {} with permission {} {} access to endpoint {}", + userAndRemoteAddress.getLeft().getName(), + permission, + hasAccess ? "has" : "has no", + endpoint + ); + logger.debug( + "{} set to {}. {} use access decision", + SECURITY_RESTAPI_ADMIN_ENABLED, + restapiAdminEnabled, + restapiAdminEnabled ? "Will" : "Will not" + ); + } + return hasAccess && restapiAdminEnabled; } public boolean containsRestApiAdminPermissions(final Object configObject) { diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/SecuritySSLCertsAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/SecuritySSLCertsAction.java index 4168bf4109..1c1fe9b815 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/SecuritySSLCertsAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/SecuritySSLCertsAction.java @@ -72,8 +72,6 @@ public class SecuritySSLCertsAction extends AbstractApiAction { private final boolean certificatesReloadEnabled; - private final RestApiAdminPrivilegesEvaluator restApiAdminPrivilegesEvaluator; - private final boolean httpsEnabled; public SecuritySSLCertsAction(final Settings settings, @@ -91,8 +89,6 @@ public SecuritySSLCertsAction(final Settings settings, final boolean certificatesReloadEnabled) { super(settings, configPath, controller, client, adminDNs, cl, cs, principalExtractor, privilegesEvaluator, threadPool, auditLog); this.securityKeyStore = securityKeyStore; - this.restApiAdminPrivilegesEvaluator = - new RestApiAdminPrivilegesEvaluator(threadPool.getThreadContext(), privilegesEvaluator, adminDNs); this.certificatesReloadEnabled = certificatesReloadEnabled; this.httpsEnabled = settings.getAsBoolean(SSLConfigConstants.SECURITY_SSL_HTTP_ENABLED, true); } diff --git a/src/main/java/org/opensearch/security/support/ConfigConstants.java b/src/main/java/org/opensearch/security/support/ConfigConstants.java index ee83284ca4..375b22b65f 100644 --- a/src/main/java/org/opensearch/security/support/ConfigConstants.java +++ b/src/main/java/org/opensearch/security/support/ConfigConstants.java @@ -248,11 +248,11 @@ public enum RolesMappingResolution { public static final String SECURITY_DLS_MODE = "plugins.security.dls.mode"; // REST API public static final String SECURITY_RESTAPI_ROLES_ENABLED = "plugins.security.restapi.roles_enabled"; + public static final String SECURITY_RESTAPI_ADMIN_ENABLED = "plugins.security.restapi.admin.enabled"; public static final String SECURITY_RESTAPI_ENDPOINTS_DISABLED = "plugins.security.restapi.endpoints_disabled"; public static final String SECURITY_RESTAPI_PASSWORD_VALIDATION_REGEX = "plugins.security.restapi.password_validation_regex"; public static final String SECURITY_RESTAPI_PASSWORD_VALIDATION_ERROR_MESSAGE = "plugins.security.restapi.password_validation_error_message"; - // Illegal Opcodes from here on public static final String SECURITY_UNSUPPORTED_DISABLE_REST_AUTH_INITIALLY = "plugins.security.unsupported.disable_rest_auth_initially"; public static final String SECURITY_UNSUPPORTED_DISABLE_INTERTRANSPORT_AUTH_INITIALLY = "plugins.security.unsupported.disable_intertransport_auth_initially"; public static final String SECURITY_UNSUPPORTED_PASSIVE_INTERTRANSPORT_AUTH_INITIALLY = "plugins.security.unsupported.passive_intertransport_auth_initially"; diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/ActionGroupsApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/ActionGroupsApiTest.java index a0d1ece77a..abb45df268 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/ActionGroupsApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/ActionGroupsApiTest.java @@ -29,6 +29,7 @@ import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse; import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX; +import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ADMIN_ENABLED; public class ActionGroupsApiTest extends AbstractRestApiUnitTest { private final String ENDPOINT; @@ -362,7 +363,7 @@ void verifyPatchForSuperAdmin(final Header[] header, final boolean userAdminCert @Test public void testActionGroupsApiForRestAdmin() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); rh.sendAdminCertificate = false; // create index setupStarfleetIndex(); @@ -380,7 +381,7 @@ public void testActionGroupsApiForRestAdmin() throws Exception { @Test public void testActionGroupsApiForActionGroupsRestApiAdmin() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); rh.sendAdminCertificate = false; // create index setupStarfleetIndex(); @@ -398,7 +399,7 @@ public void testActionGroupsApiForActionGroupsRestApiAdmin() throws Exception { @Test public void testCreateActionGroupWithRestAdminPermissionsForbidden() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); rh.sendAdminCertificate = false; final Header restApiAdminHeader = encodeBasicHeader("rest_api_admin_user", "rest_api_admin_user"); final Header restApiAdminActionGroupsHeader = encodeBasicHeader("rest_api_admin_actiongroups", "rest_api_admin_actiongroups"); diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/AllowlistApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/AllowlistApiTest.java index 05739cc4ab..50090fcfcc 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/AllowlistApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/AllowlistApiTest.java @@ -37,6 +37,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ADMIN_ENABLED; /** * Testing class to verify that {@link AllowlistApiAction} works correctly. @@ -158,7 +159,7 @@ public void testAllowlistApi() throws Exception { @Test public void testAllowlistApiWithPermissions() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); final Header restApiAdminHeader = encodeBasicHeader("rest_api_admin_user", "rest_api_admin_user"); final Header restApiAllowlistHeader = encodeBasicHeader("rest_api_admin_allowlist", "rest_api_admin_allowlist"); @@ -170,7 +171,7 @@ public void testAllowlistApiWithPermissions() throws Exception { @Test public void testAllowlistApiWithAllowListPermissions() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); final Header restApiAllowlistHeader = encodeBasicHeader("rest_api_admin_allowlist", "rest_api_admin_allowlist"); final Header restApiUserHeader = encodeBasicHeader("test", "test"); diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/NodesDnApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/NodesDnApiTest.java index 03d16ee78d..ef1042682b 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/NodesDnApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/NodesDnApiTest.java @@ -37,6 +37,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX; +import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ADMIN_ENABLED; public class NodesDnApiTest extends AbstractRestApiUnitTest { private HttpResponse response; @@ -184,7 +185,10 @@ public void testNodesDnApi() throws Exception { @Test public void testNodesDnApiWithPermissions() throws Exception { - Settings settings = Settings.builder().put(ConfigConstants.SECURITY_NODES_DN_DYNAMIC_CONFIG_ENABLED, true) + Settings settings = + Settings.builder() + .put(ConfigConstants.SECURITY_NODES_DN_DYNAMIC_CONFIG_ENABLED, true) + .put(SECURITY_RESTAPI_ADMIN_ENABLED, true) .build(); setupWithRestRoles(settings); final Header restApiAdminHeader = encodeBasicHeader("rest_api_admin_user", "rest_api_admin_user"); diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/RolesApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/RolesApiTest.java index 529658940a..5a6d1f297c 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/RolesApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/RolesApiTest.java @@ -31,6 +31,7 @@ import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse; import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX; +import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ADMIN_ENABLED; public class RolesApiTest extends AbstractRestApiUnitTest { private final String ENDPOINT; @@ -77,15 +78,17 @@ public void testAllRolesForSuperAdmin() throws Exception { @Test public void testAllRolesForRestAdmin() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); final Header restApiAdminHeader = encodeBasicHeader("rest_api_admin_user", "rest_api_admin_user"); + rh.sendAdminCertificate = false; checkSuperAdminRoles(new Header[]{restApiAdminHeader}); } @Test public void testAllRolesForRolesRestAdmin() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); final Header restApiAdminRolesHeader = encodeBasicHeader("rest_api_admin_roles", "rest_api_admin_roles"); + rh.sendAdminCertificate = false; checkSuperAdminRoles(new Header[]{restApiAdminRolesHeader}); } @@ -519,7 +522,7 @@ void verifyPatchForSuperAdmin(final Header[] header, final boolean sendAdminCert @Test public void testRolesApiWithAllRestApiPermissions() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); final Header restApiAdminHeader = encodeBasicHeader("rest_api_admin_user", "rest_api_admin_user"); @@ -539,7 +542,7 @@ public void testRolesApiWithAllRestApiPermissions() throws Exception { @Test public void testRolesApiWithRestApiRolePermission() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); final Header restApiRolesHeader = encodeBasicHeader("rest_api_admin_roles", "rest_api_admin_roles"); @@ -560,7 +563,7 @@ public void testRolesApiWithRestApiRolePermission() throws Exception { @Test public void testCreateOrUpdateRestApiAdminRoleForbiddenForNonSuperAdmin() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); rh.sendAdminCertificate = false; final Header restApiAdminHeader = encodeBasicHeader("rest_api_admin_user", "rest_api_admin_user"); @@ -632,7 +635,7 @@ public void testCreateOrUpdateRestApiAdminRoleForbiddenForNonSuperAdmin() throws @Test public void testDeleteRestApiAdminRoleForbiddenForNonSuperAdmin() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); rh.sendAdminCertificate = false; final Header restApiAdminHeader = encodeBasicHeader("rest_api_admin_user", "rest_api_admin_user"); diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/RolesMappingApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/RolesMappingApiTest.java index f6405e984a..44e160e151 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/RolesMappingApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/RolesMappingApiTest.java @@ -29,6 +29,7 @@ import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse; import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX; +import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ADMIN_ENABLED; public class RolesMappingApiTest extends AbstractRestApiUnitTest { private final String ENDPOINT; @@ -98,7 +99,7 @@ public void testRolesMappingApi() throws Exception { @Test public void testRolesMappingApiWithFullPermissions() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); rh.sendAdminCertificate = false; final Header restApiAdminHeader = encodeBasicHeader("rest_api_admin_user", "rest_api_admin_user"); @@ -466,7 +467,7 @@ void verifyNonSuperAdminUser(final Header[] header) throws Exception { @Test public void testChangeRestApiAdminRoleMappingForbiddenForNonSuperAdmin() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); rh.sendAdminCertificate = false; final Header restApiAdminHeader = encodeBasicHeader("rest_api_admin_user", "rest_api_admin_user"); diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/SslCertsApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/SslCertsApiTest.java index 2df1fdfaf7..425c2dca50 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/SslCertsApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/SslCertsApiTest.java @@ -28,6 +28,7 @@ import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse; import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX; +import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ADMIN_ENABLED; public class SslCertsApiTest extends AbstractRestApiUnitTest { @@ -83,9 +84,7 @@ public String certsReloadEndpoint(final String certType) { return String.format("%s/api/ssl/%s/reloadcerts", PLUGINS_PREFIX, certType); } - @Test - public void testCertsInfo() throws Exception { - setupWithRestRoles(); + private void verifyHasNoAccess() throws Exception { final Header adminCredsHeader = encodeBasicHeader("admin", "admin"); // No creds, no admin certificate - UNAUTHORIZED rh.sendAdminCertificate = false; @@ -96,17 +95,28 @@ public void testCertsInfo() throws Exception { response = rh.executeGetRequest(certsInfoEndpoint(), adminCredsHeader); Assert.assertEquals(response.getBody(), HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + response = rh.executeGetRequest(certsInfoEndpoint(), restApiHeader); + Assert.assertEquals(response.getBody(), HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + } + + @Test + public void testCertsInfo() throws Exception { + setup(); + verifyHasNoAccess(); sendAdminCert(); - response = rh.executeGetRequest(certsInfoEndpoint()); + HttpResponse response = rh.executeGetRequest(certsInfoEndpoint()); Assert.assertEquals(response.getBody(), HttpStatus.SC_OK, response.getStatusCode()); Assert.assertEquals(EXPECTED_CERTIFICATES_BY_TYPE, response.getBody()); + } + + @Test + public void testCertsInfoRestAdmin() throws Exception { + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); + verifyHasNoAccess(); rh.sendAdminCertificate = false; Assert.assertEquals(EXPECTED_CERTIFICATES_BY_TYPE, loadCerts(restApiAdminHeader)); Assert.assertEquals(EXPECTED_CERTIFICATES_BY_TYPE, loadCerts(restApiCertsInfoAdminHeader)); - - response = rh.executeGetRequest(certsInfoEndpoint(), restApiHeader); - Assert.assertEquals(response.getBody(), HttpStatus.SC_FORBIDDEN, response.getStatusCode()); } private String loadCerts(final Header... header) throws Exception { @@ -120,23 +130,18 @@ public void testReloadCertsNotAvailableByDefault() throws Exception { setupWithRestRoles(); sendAdminCert(); - verifyReloadCertsNotAvailable(); + verifyReloadCertsNotAvailable(HttpStatus.SC_BAD_REQUEST); rh.sendAdminCertificate = false; - verifyReloadCertsNotAvailable(restApiAdminHeader); - verifyReloadCertsNotAvailable(restApiReloadCertsAdminHeader); - - HttpResponse response = rh.executePutRequest(certsReloadEndpoint(HTTP_CERTS), "{}", restApiHeader); - Assert.assertEquals(response.getBody(), HttpStatus.SC_FORBIDDEN, response.getStatusCode()); - response = rh.executePutRequest(certsReloadEndpoint(TRANSPORT_CERTS), "{}", restApiHeader); - Assert.assertEquals(response.getBody(), HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + verifyReloadCertsNotAvailable(HttpStatus.SC_FORBIDDEN, restApiAdminHeader); + verifyReloadCertsNotAvailable(HttpStatus.SC_FORBIDDEN, restApiReloadCertsAdminHeader); } - private void verifyReloadCertsNotAvailable(final Header... header) { + private void verifyReloadCertsNotAvailable(final int expectedStatus, final Header... header) { HttpResponse response = rh.executePutRequest(certsReloadEndpoint(HTTP_CERTS), "{}", header); - Assert.assertEquals(response.getBody(), HttpStatus.SC_BAD_REQUEST, response.getStatusCode()); + Assert.assertEquals(response.getBody(), expectedStatus, response.getStatusCode()); response = rh.executePutRequest(certsReloadEndpoint(TRANSPORT_CERTS), "{}", header); - Assert.assertEquals(response.getBody(), HttpStatus.SC_BAD_REQUEST, response.getStatusCode()); + Assert.assertEquals(response.getBody(), expectedStatus, response.getStatusCode()); } @Test @@ -154,12 +159,6 @@ public void testReloadCertsWrongCertsType() throws Exception { } - @Test - public void testReloadCerts() throws Exception { - setupWithRestRoles(reloadEnabled()); - } - - private void sendAdminCert() { rh.keystore = "restapi/kirk-keystore.jks"; rh.sendAdminCertificate = true; diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java index 88eab72766..1ecd96e148 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java @@ -33,6 +33,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX; import static org.opensearch.security.dlic.rest.api.InternalUsersApiAction.RESTRICTED_FROM_USERNAME; +import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ADMIN_ENABLED; public class UserApiTest extends AbstractRestApiUnitTest { @@ -424,7 +425,7 @@ private void verifyRoles(final boolean sendAdminCert, Header... header) throws E @Test public void testUserApiWithRestAdminPermissions() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); rh.sendAdminCertificate = false; final Header restApiAdminHeader = encodeBasicHeader("rest_api_admin_user", "rest_api_admin_user"); // initial configuration @@ -442,7 +443,7 @@ public void testUserApiWithRestAdminPermissions() throws Exception { @Test public void testUserApiWithRestInternalUsersAdminPermissions() throws Exception { - setupWithRestRoles(); + setupWithRestRoles(Settings.builder().put(SECURITY_RESTAPI_ADMIN_ENABLED, true).build()); rh.sendAdminCertificate = false; final Header restApiInternalUsersAdminHeader = encodeBasicHeader("rest_api_admin_internalusers", "rest_api_admin_internalusers"); // initial configuration From 24bffc93c8f09bf6eee6cf8d6701fa2edcece4a8 Mon Sep 17 00:00:00 2001 From: Vamsi Manohar Date: Thu, 6 Apr 2023 13:59:39 -0700 Subject: [PATCH 07/16] Adding new system index for ppl/sql datasource configurations (#2650) Signed-off-by: vamsi-amazon --- tools/install_demo_configuration.bat | 2 +- tools/install_demo_configuration.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/install_demo_configuration.bat b/tools/install_demo_configuration.bat index 06fbf5ec51..474014536c 100755 --- a/tools/install_demo_configuration.bat +++ b/tools/install_demo_configuration.bat @@ -315,7 +315,7 @@ echo plugins.security.enable_snapshot_restore_privilege: true >> "%OPENSEARCH_CO echo plugins.security.check_snapshot_restore_write_privileges: true >> "%OPENSEARCH_CONF_FILE%" echo plugins.security.restapi.roles_enabled: ["all_access", "security_rest_api_access"] >> "%OPENSEARCH_CONF_FILE%" echo plugins.security.system_indices.enabled: true >> "%OPENSEARCH_CONF_FILE%" -echo plugins.security.system_indices.indices: [".plugins-ml-model", ".plugins-ml-task", ".opendistro-alerting-config", ".opendistro-alerting-alert*", ".opendistro-anomaly-results*", ".opendistro-anomaly-detector*", ".opendistro-anomaly-checkpoints", ".opendistro-anomaly-detection-state", ".opendistro-reports-*", ".opensearch-notifications-*", ".opensearch-notebooks", ".opensearch-observability", ".opendistro-asynchronous-search-response*", ".replication-metadata-store", ".opensearch-knn-models"] >> "%OPENSEARCH_CONF_FILE%" +echo plugins.security.system_indices.indices: [".plugins-ml-model", ".plugins-ml-task", ".opendistro-alerting-config", ".opendistro-alerting-alert*", ".opendistro-anomaly-results*", ".opendistro-anomaly-detector*", ".opendistro-anomaly-checkpoints", ".opendistro-anomaly-detection-state", ".opendistro-reports-*", ".opensearch-notifications-*", ".opensearch-notebooks", ".opensearch-observability", ".ql-datasources", ".opendistro-asynchronous-search-response*", ".replication-metadata-store", ".opensearch-knn-models"] >> "%OPENSEARCH_CONF_FILE%" :: network.host >nul findstr /b /c:"network.host" "%OPENSEARCH_CONF_FILE%" && ( diff --git a/tools/install_demo_configuration.sh b/tools/install_demo_configuration.sh index ccd620b528..6d6203124a 100755 --- a/tools/install_demo_configuration.sh +++ b/tools/install_demo_configuration.sh @@ -383,7 +383,7 @@ echo "plugins.security.enable_snapshot_restore_privilege: true" | $SUDO_CMD tee echo "plugins.security.check_snapshot_restore_write_privileges: true" | $SUDO_CMD tee -a "$OPENSEARCH_CONF_FILE" > /dev/null echo 'plugins.security.restapi.roles_enabled: ["all_access", "security_rest_api_access"]' | $SUDO_CMD tee -a "$OPENSEARCH_CONF_FILE" > /dev/null echo 'plugins.security.system_indices.enabled: true' | $SUDO_CMD tee -a "$OPENSEARCH_CONF_FILE" > /dev/null -echo 'plugins.security.system_indices.indices: [".plugins-ml-model", ".plugins-ml-task", ".opendistro-alerting-config", ".opendistro-alerting-alert*", ".opendistro-anomaly-results*", ".opendistro-anomaly-detector*", ".opendistro-anomaly-checkpoints", ".opendistro-anomaly-detection-state", ".opendistro-reports-*", ".opensearch-notifications-*", ".opensearch-notebooks", ".opensearch-observability", ".opendistro-asynchronous-search-response*", ".replication-metadata-store", ".opensearch-knn-models"]' | $SUDO_CMD tee -a "$OPENSEARCH_CONF_FILE" > /dev/null +echo 'plugins.security.system_indices.indices: [".plugins-ml-model", ".plugins-ml-task", ".opendistro-alerting-config", ".opendistro-alerting-alert*", ".opendistro-anomaly-results*", ".opendistro-anomaly-detector*", ".opendistro-anomaly-checkpoints", ".opendistro-anomaly-detection-state", ".opendistro-reports-*", ".opensearch-notifications-*", ".opensearch-notebooks", ".opensearch-observability", ".ql-datasources", ".opendistro-asynchronous-search-response*", ".replication-metadata-store", ".opensearch-knn-models"]' | $SUDO_CMD tee -a "$OPENSEARCH_CONF_FILE" > /dev/null #network.host if $SUDO_CMD grep --quiet -i "^network.host" "$OPENSEARCH_CONF_FILE"; then From f9439c52b90401f44c297f27d29eafa8f4ecf99d Mon Sep 17 00:00:00 2001 From: Stephen Crawford <65832608+scrawfor99@users.noreply.github.com> Date: Thu, 6 Apr 2023 17:00:18 -0400 Subject: [PATCH 08/16] Update README.md to add slack badge and announcement (#2653) * Update README.md Add slack workspace announcement at top of README for a couple weeks. * Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index eb5ccb4fa4..f0f6321d9d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ [![CI](https://github.com/opensearch-project/security/workflows/CI/badge.svg?branch=main)](https://github.com/opensearch-project/security/actions) [![](https://img.shields.io/github/issues/opensearch-project/security/untriaged?labelColor=red)](https://github.com/opensearch-project/security/issues?q=is%3Aissue+is%3Aopen+label%3A"untriaged") [![](https://img.shields.io/github/issues/opensearch-project/security/security%20vulnerability?labelColor=red)](https://github.com/opensearch-project/security/issues?q=is%3Aissue+is%3Aopen+label%3A"security%20vulnerability") [![](https://img.shields.io/github/issues/opensearch-project/security)](https://github.com/opensearch-project/security/issues) [![](https://img.shields.io/github/issues-pr/opensearch-project/security)](https://github.com/opensearch-project/security/pulls) [![](https://img.shields.io/codecov/c/gh/opensearch-project/security)](https://app.codecov.io/gh/opensearch-project/security) [![](https://img.shields.io/github/issues/opensearch-project/security/v2.4.0)](https://github.com/opensearch-project/security/issues?q=is%3Aissue+is%3Aopen+label%3A"v2.4.0") [![](https://img.shields.io/github/issues/opensearch-project/security/v3.0.0)](https://github.com/opensearch-project/security/issues?q=is%3Aissue+is%3Aopen+label%3A"v3.0.0") +[![Slack](https://img.shields.io/badge/Slack-4A154B?&logo=slack&logoColor=white)](https://opensearch.slack.com/archives/C051Y637FKK) + + + +## Announcement: The Slack workspace is live! Please join the [conversation](https://opensearch.slack.com/archives/C051Y637FKK). From 9fca0dae5c1e3fe4746381d9f87c4d4abb0f0fda Mon Sep 17 00:00:00 2001 From: Abhi Kalra <99718513+abhivka7@users.noreply.github.com> Date: Fri, 7 Apr 2023 21:51:26 +0530 Subject: [PATCH 09/16] Dynamic_Tenancy_Configurations changes (#2607) Signed-off-by: Abhi Kalra Co-authored-by: Abhi Kalra --- config/config.yml | 2 + legacy/securityconfig_v6/config.yml | 1 + .../security/OpenSearchSecurityPlugin.java | 10 ++ .../security/action/tenancy/EmptyRequest.java | 35 ++++ .../tenancy/TenancyConfigRestHandler.java | 65 ++++++++ .../tenancy/TenancyConfigRetrieveActions.java | 24 +++ .../TenancyConfigRetrieveResponse.java | 70 ++++++++ .../TenancyConfigRetrieveTransportAction.java | 63 +++++++ .../tenancy/TenancyConfigUpdateAction.java | 26 +++ .../tenancy/TenancyConfigUpdateRequest.java | 69 ++++++++ .../TenancyConfigUpdateTransportAction.java | 155 ++++++++++++++++++ .../action/tenancy/TenancyConfigs.java | 18 ++ .../PrivilegesInterceptorImpl.java | 7 + .../dlic/rest/api/AbstractApiAction.java | 18 +- .../dlic/rest/api/AccountApiAction.java | 2 +- .../dlic/rest/api/AllowlistApiAction.java | 2 +- .../dlic/rest/api/InternalUsersApiAction.java | 2 +- .../dlic/rest/api/MigrateApiAction.java | 10 +- .../rest/api/PatchableResourceApiAction.java | 4 +- .../dlic/rest/api/RolesMappingApiAction.java | 2 +- .../privileges/PrivilegesEvaluator.java | 9 + .../security/rest/DashboardsInfoAction.java | 3 + .../securityconf/DynamicConfigModel.java | 2 + .../securityconf/DynamicConfigModelV6.java | 6 + .../securityconf/DynamicConfigModelV7.java | 6 + .../securityconf/impl/v6/ConfigV6.java | 4 + .../securityconf/impl/v7/ConfigV7.java | 10 +- .../security/support/ConfigConstants.java | 4 + .../test/TenancyDefaultTenantTests.java | 96 +++++++++++ .../test/TenancyMultitenancyEnabledTests.java | 89 ++++++++++ .../TenancyPrivateTenantEnabledTests.java | 101 ++++++++++++ .../security/test/helper/rest/RestHelper.java | 14 +- src/test/resources/auditlog/config.yml | 2 + src/test/resources/cache/config.yml | 2 + src/test/resources/composite_config.yml | 2 + src/test/resources/config.yml | 2 + src/test/resources/config_anon.yml | 2 + src/test/resources/config_clientcert.yml | 2 + src/test/resources/config_disable_all.yml | 2 + src/test/resources/config_dnfof.yml | 2 + src/test/resources/config_invalidlic.yml | 2 + src/test/resources/config_lic.yml | 2 + src/test/resources/config_lic_rk.yml | 2 + src/test/resources/config_multirolespan.yml | 2 + .../resources/config_protected_indices.yml | 2 + src/test/resources/config_proxy.yml | 2 + src/test/resources/config_proxy_custom.yml | 2 + .../config_respect_indices_options.yml | 2 + .../resources/config_rest_impersonation.yml | 2 + src/test/resources/config_system_indices.yml | 2 + .../resources/config_transport_username.yml | 2 + src/test/resources/config_xff.yml | 2 + src/test/resources/dlsfls/config.yml | 2 + src/test/resources/ldap/config.yml | 2 + src/test/resources/ldap/config_ldap2.yml | 2 + src/test/resources/multitenancy/config.yml | 2 + .../multitenancy/config_anonymous.yml | 2 + .../multitenancy/config_basic_auth.yml | 2 + .../resources/multitenancy/config_nodnfof.yml | 2 + src/test/resources/restapi/config.yml | 2 + .../resources/restapi/invalid_config.json | 2 + .../resources/restapi/security_config.json | 2 + .../resources/restapi/securityconfig.json | 2 + .../restapi/securityconfig_nondefault.json | 2 + .../resources/security_passive/config.yml | 2 + 65 files changed, 965 insertions(+), 30 deletions(-) create mode 100644 src/main/java/org/opensearch/security/action/tenancy/EmptyRequest.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRestHandler.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveResponse.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveTransportAction.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateRequest.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateTransportAction.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigs.java create mode 100644 src/test/java/org/opensearch/security/multitenancy/test/TenancyDefaultTenantTests.java create mode 100644 src/test/java/org/opensearch/security/multitenancy/test/TenancyMultitenancyEnabledTests.java create mode 100644 src/test/java/org/opensearch/security/multitenancy/test/TenancyPrivateTenantEnabledTests.java diff --git a/config/config.yml b/config/config.yml index 0537ff8406..1493a0d7f1 100644 --- a/config/config.yml +++ b/config/config.yml @@ -68,6 +68,8 @@ config: #kibana: # Kibana multitenancy #multitenancy_enabled: true + #private_tenant_enabled: true + #default_tenant: "" #server_username: kibanaserver #index: '.kibana' http: diff --git a/legacy/securityconfig_v6/config.yml b/legacy/securityconfig_v6/config.yml index da2be1e38d..15d5ee9973 100644 --- a/legacy/securityconfig_v6/config.yml +++ b/legacy/securityconfig_v6/config.yml @@ -60,6 +60,7 @@ opendistro_security: #filtered_alias_mode: warn #kibana: #multitenancy_enabled: true + #server_username: kibanaserver #index: '.kibana' #do_not_fail_on_forbidden: false diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index af089584a9..ffd7f730ed 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -115,6 +115,11 @@ import org.opensearch.search.query.QuerySearchResult; import org.opensearch.security.action.configupdate.ConfigUpdateAction; import org.opensearch.security.action.configupdate.TransportConfigUpdateAction; +import org.opensearch.security.action.tenancy.TenancyConfigRestHandler; +import org.opensearch.security.action.tenancy.TenancyConfigRetrieveActions; +import org.opensearch.security.action.tenancy.TenancyConfigRetrieveTransportAction; +import org.opensearch.security.action.tenancy.TenancyConfigUpdateAction; +import org.opensearch.security.action.tenancy.TenancyConfigUpdateTransportAction; import org.opensearch.security.action.whoami.TransportWhoAmIAction; import org.opensearch.security.action.whoami.WhoAmIAction; import org.opensearch.security.auditlog.AuditLog; @@ -469,6 +474,7 @@ public List getRestHandlers(Settings settings, RestController restC Objects.requireNonNull(cs), Objects.requireNonNull(adminDns), Objects.requireNonNull(cr))); handlers.add(new SecurityConfigUpdateAction(settings, restController, Objects.requireNonNull(threadPool), adminDns, configPath, principalExtractor)); handlers.add(new SecurityWhoAmIAction(settings, restController, Objects.requireNonNull(threadPool), adminDns, configPath, principalExtractor)); + handlers.add(new TenancyConfigRestHandler()); handlers.addAll( SecurityRestApiActions.getHandler( settings, @@ -505,6 +511,10 @@ public UnaryOperator getRestHandlerWrapper(final ThreadContext thre if(!disabled && !SSLConfig.isSslOnlyMode()) { actions.add(new ActionHandler<>(ConfigUpdateAction.INSTANCE, TransportConfigUpdateAction.class)); actions.add(new ActionHandler<>(WhoAmIAction.INSTANCE, TransportWhoAmIAction.class)); + + actions.add(new ActionHandler<>(TenancyConfigRetrieveActions.INSTANCE, TenancyConfigRetrieveTransportAction.class)); + actions.add(new ActionHandler<>(TenancyConfigUpdateAction.INSTANCE, TenancyConfigUpdateTransportAction.class)); + } return actions; } diff --git a/src/main/java/org/opensearch/security/action/tenancy/EmptyRequest.java b/src/main/java/org/opensearch/security/action/tenancy/EmptyRequest.java new file mode 100644 index 0000000000..607216a8c3 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/EmptyRequest.java @@ -0,0 +1,35 @@ +/* + * 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.security.action.tenancy; + +import java.io.IOException; + +import org.opensearch.action.ActionRequest; +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.common.io.stream.StreamInput; + +public class EmptyRequest extends ActionRequest { + + public EmptyRequest(final StreamInput in) throws IOException { + super(in); + } + + public EmptyRequest() throws IOException { + super(); + } + + @Override + public ActionRequestValidationException validate() + { + return null; + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRestHandler.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRestHandler.java new file mode 100644 index 0000000000..0a00d16694 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRestHandler.java @@ -0,0 +1,65 @@ +/* + * 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.security.action.tenancy; + +import java.io.IOException; +import java.util.List; + +import com.google.common.collect.ImmutableList; + +import org.opensearch.client.node.NodeClient; +import org.opensearch.rest.BaseRestHandler; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.action.RestToXContentListener; + +import static org.opensearch.rest.RestRequest.Method.GET; +import static org.opensearch.rest.RestRequest.Method.PUT; + +public class TenancyConfigRestHandler extends BaseRestHandler { + + public TenancyConfigRestHandler() { + super(); + } + + @Override + public String getName() { + return "Multi Tenancy actions to Retrieve / Update configs."; + } + + @Override + public List routes() { + return ImmutableList.of( + new Route(GET, "/_plugins/_security/api/tenancy/config"), + new Route(PUT, "/_plugins/_security/api/tenancy/config") + ); + } + + @Override + protected RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient nodeClient) throws IOException { + + switch (request.method()) { + case GET: + return channel -> nodeClient.execute( + TenancyConfigRetrieveActions.INSTANCE, + new EmptyRequest(), + new RestToXContentListener<>(channel)); + case PUT: + return channel -> nodeClient.execute( + TenancyConfigUpdateAction.INSTANCE, + TenancyConfigUpdateRequest.fromXContent(request.contentParser()), + new RestToXContentListener<>(channel)); + default: + throw new RuntimeException("Not implemented"); + } + } + +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java new file mode 100644 index 0000000000..796f233f13 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java @@ -0,0 +1,24 @@ +/* + * 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.security.action.tenancy; + +import org.opensearch.action.ActionType; + +public class TenancyConfigRetrieveActions extends ActionType { + + public static final TenancyConfigRetrieveActions INSTANCE = new TenancyConfigRetrieveActions(); + public static final String NAME = "cluster:feature/tenancy/config/read"; + + protected TenancyConfigRetrieveActions() { + super(NAME, TenancyConfigRetrieveResponse::new); + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveResponse.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveResponse.java new file mode 100644 index 0000000000..463cc7d831 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveResponse.java @@ -0,0 +1,70 @@ +/* + * 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.security.action.tenancy; + +import java.io.IOException; + +import org.opensearch.action.ActionResponse; +import org.opensearch.common.Strings; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.common.io.stream.StreamOutput; +import org.opensearch.common.xcontent.XContentType; +import org.opensearch.core.xcontent.ToXContentObject; +import org.opensearch.core.xcontent.XContentBuilder; + +public class TenancyConfigRetrieveResponse extends ActionResponse implements ToXContentObject { + + public TenancyConfigs tenancyConfigs = new TenancyConfigs(); + + public TenancyConfigRetrieveResponse(final StreamInput in) throws IOException { + super(in); + this.tenancyConfigs.multitenancy_enabled = in.readOptionalBoolean(); + this.tenancyConfigs.private_tenant_enabled = in.readOptionalBoolean(); + this.tenancyConfigs.default_tenant = in.readOptionalString(); + } + + public TenancyConfigRetrieveResponse(final TenancyConfigs tenancyConfigs) { + this.tenancyConfigs = tenancyConfigs; + } + + public TenancyConfigs getMultitenancyConfig() { + return tenancyConfigs; + } + + public Boolean getMultitenancyEnabled() { return tenancyConfigs.multitenancy_enabled; } + + public Boolean getPrivateTenantEnabled() { return tenancyConfigs.private_tenant_enabled; } + + public String getDefaultTenant() { return tenancyConfigs.default_tenant; } + + @Override + public void writeTo(final StreamOutput out) throws IOException { + out.writeBoolean(getMultitenancyEnabled()); + out.writeBoolean(getPrivateTenantEnabled()); + out.writeString(getDefaultTenant()); + } + + @Override + public String toString() { + return Strings.toString(XContentType.JSON, this, true, true); + } + + @Override + public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException { + builder.startObject(); + builder.field("multitenancy_enabled", getMultitenancyEnabled()); + builder.field("private_tenant_enabled", getPrivateTenantEnabled()); + builder.field("default_tenant", getDefaultTenant()); + builder.endObject(); + return builder; + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveTransportAction.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveTransportAction.java new file mode 100644 index 0000000000..a68bbae85e --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveTransportAction.java @@ -0,0 +1,63 @@ +/* + * 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.security.action.tenancy; + +import java.util.Collections; + +import org.opensearch.action.ActionListener; +import org.opensearch.action.support.ActionFilters; +import org.opensearch.action.support.HandledTransportAction; +import org.opensearch.common.inject.Inject; +import org.opensearch.common.settings.Settings; +import org.opensearch.security.configuration.ConfigurationRepository; +import org.opensearch.security.securityconf.impl.CType; +import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.security.securityconf.impl.v7.ConfigV7; +import org.opensearch.tasks.Task; +import org.opensearch.transport.TransportService; + +public class TenancyConfigRetrieveTransportAction + extends HandledTransportAction { + + private final ConfigurationRepository config; + + @Inject + public TenancyConfigRetrieveTransportAction(final Settings settings, + final TransportService transportService, + final ActionFilters actionFilters, + final ConfigurationRepository config) { + super(TenancyConfigRetrieveActions.NAME, transportService, actionFilters, EmptyRequest::new); + + this.config = config; + } + + /** Load the configuration from the security index and return a copy */ + protected final SecurityDynamicConfiguration load() { + return config.getConfigurationsFromIndex(Collections.singleton(CType.CONFIG), false).get(CType.CONFIG).deepClone(); + } + + @Override + protected void doExecute(final Task task, final EmptyRequest request, final ActionListener listener) { + + // Get the security configuration and lookup the config setting state + final SecurityDynamicConfiguration dynamicConfig = load(); + ConfigV7 config = (ConfigV7)dynamicConfig.getCEntry("config"); + + final TenancyConfigs tenancyConfigs= new TenancyConfigs(); + + tenancyConfigs.multitenancy_enabled = config.dynamic.kibana.multitenancy_enabled; + tenancyConfigs.private_tenant_enabled = config.dynamic.kibana.private_tenant_enabled; + tenancyConfigs.default_tenant = config.dynamic.kibana.default_tenant; + + listener.onResponse(new TenancyConfigRetrieveResponse(tenancyConfigs)); + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java new file mode 100644 index 0000000000..73d515b7d8 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java @@ -0,0 +1,26 @@ +/* + * 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.security.action.tenancy; + +import org.opensearch.action.ActionType; + +public class TenancyConfigUpdateAction extends ActionType { + + public static final TenancyConfigUpdateAction INSTANCE = new TenancyConfigUpdateAction(); + public static final String NAME = "cluster:feature/tenancy/config/update"; + + + protected TenancyConfigUpdateAction() + { + super(NAME, TenancyConfigRetrieveResponse::new); + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateRequest.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateRequest.java new file mode 100644 index 0000000000..2d03f698a6 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateRequest.java @@ -0,0 +1,69 @@ +/* + * 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.security.action.tenancy; +import java.io.IOException; + +import org.opensearch.action.ActionRequest; +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.core.ParseField; +import org.opensearch.core.xcontent.ConstructingObjectParser; +import org.opensearch.core.xcontent.XContentParser; + +public class TenancyConfigUpdateRequest extends ActionRequest { + + private TenancyConfigs tenancyConfigs = new TenancyConfigs(); + + public TenancyConfigUpdateRequest(final StreamInput in) throws IOException { + super(in); + in.readOptionalBoolean(); + in.readOptionalBoolean(); + in.readOptionalString(); + } + + public TenancyConfigUpdateRequest(final Boolean multitenancy_enabled, final Boolean private_tenant_enabled, final String default_tenant) { + super(); + this.tenancyConfigs.multitenancy_enabled = multitenancy_enabled; + this.tenancyConfigs.private_tenant_enabled = private_tenant_enabled; + this.tenancyConfigs.default_tenant = default_tenant; + } + + public TenancyConfigs getTenancyConfigs() { + return tenancyConfigs; + } + + @Override + public ActionRequestValidationException validate() { + if (getTenancyConfigs() == null) { + final ActionRequestValidationException validationException = new ActionRequestValidationException(); + validationException.addValidationError("Missing tenancy configs"); + return validationException; + } + return null; + } + + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + TenancyConfigUpdateRequest.class.getName(), + args -> new TenancyConfigUpdateRequest((Boolean)args[0], (Boolean) args[1], (String) args[2]) + ); + + static { + PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), new ParseField("multitenancy_enabled")); + PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), new ParseField("private_tenant_enabled")); + PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), new ParseField("default_tenant")); + + } + + public static TenancyConfigUpdateRequest fromXContent(final XContentParser parser) { + return PARSER.apply(parser, null); + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateTransportAction.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateTransportAction.java new file mode 100644 index 0000000000..1d4b563ca4 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateTransportAction.java @@ -0,0 +1,155 @@ +/* + * 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.security.action.tenancy; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import org.opensearch.action.ActionListener; +import org.opensearch.action.index.IndexResponse; +import org.opensearch.action.support.ActionFilters; +import org.opensearch.action.support.HandledTransportAction; +import org.opensearch.client.Client; +import org.opensearch.common.inject.Inject; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.security.configuration.ConfigurationRepository; +import org.opensearch.security.dlic.rest.api.AbstractApiAction; +import org.opensearch.security.securityconf.impl.CType; +import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.security.securityconf.impl.v7.ConfigV7; +import org.opensearch.security.support.ConfigConstants; +import org.opensearch.tasks.Task; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.TransportService; + +public class TenancyConfigUpdateTransportAction extends HandledTransportAction { + + private static final Logger log = LogManager.getLogger(TenancyConfigUpdateTransportAction.class); + + private final String securityIndex; + private final ConfigurationRepository config; + private final Client client; + private final ThreadPool pool; + + @Inject + public TenancyConfigUpdateTransportAction(final Settings settings, + final TransportService transportService, + final ActionFilters actionFilters, + final ConfigurationRepository config, + final ThreadPool pool, + final Client client) { + super(TenancyConfigUpdateAction.NAME, transportService, actionFilters, TenancyConfigUpdateRequest::new); + + this.securityIndex = settings.get(ConfigConstants.SECURITY_CONFIG_INDEX_NAME, ConfigConstants.OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX); + + this.config = config; + this.client = client; + this.pool = pool; + } + + /** Load the configuration from the security index and return a copy */ + protected final SecurityDynamicConfiguration load() { + return config.getConfigurationsFromIndex(Collections.singleton(CType.CONFIG), false).get(CType.CONFIG).deepClone(); + } + + private Set getAcceptableDefaultTenants() { + Set acceptableDefaultTenants = new HashSet(); + acceptableDefaultTenants.add(ConfigConstants.TENANCY_GLOBAL_TENANT_DEFAULT_NAME); + acceptableDefaultTenants.add(ConfigConstants.TENANCY_GLOBAL_TENANT_NAME); + acceptableDefaultTenants.add(ConfigConstants.TENANCY_PRIVATE_TENANT_NAME); + return acceptableDefaultTenants; + } + + private Set getAllConfiguredTenantNames() { + + return this.config.getConfiguration(CType.TENANTS).getCEntries().keySet(); + } + + protected void validate(ConfigV7 updatedConfig) { + if(!updatedConfig.dynamic.kibana.private_tenant_enabled && (updatedConfig.dynamic.kibana.default_tenant).equals(ConfigConstants.TENANCY_PRIVATE_TENANT_NAME)) { + throw new IllegalArgumentException("Private tenant can not be disabled if it is the default tenant."); + } + + Set acceptableDefaultTenants = getAcceptableDefaultTenants(); + + if(acceptableDefaultTenants.contains(updatedConfig.dynamic.kibana.default_tenant)) { + return; + } + + Set availableTenants = getAllConfiguredTenantNames(); + + if(!availableTenants.contains(updatedConfig.dynamic.kibana.default_tenant)){ + throw new IllegalArgumentException(updatedConfig.dynamic.kibana.default_tenant + " can not be set to default tenant. Default tenant should be selected from one of the available tenants."); + } + + } + + @Override + protected void doExecute(final Task task, final TenancyConfigUpdateRequest request, final ActionListener listener) { + + // Get the current security config and prepare the config with the updated value + final SecurityDynamicConfiguration dynamicConfig = load(); + final ConfigV7 config = (ConfigV7)dynamicConfig.getCEntry("config"); + + final TenancyConfigs tenancyConfigs = request.getTenancyConfigs(); + if(tenancyConfigs.multitenancy_enabled != null) + { + config.dynamic.kibana.multitenancy_enabled = tenancyConfigs.multitenancy_enabled; + } + + if(tenancyConfigs.private_tenant_enabled != null) + { + config.dynamic.kibana.private_tenant_enabled = tenancyConfigs.private_tenant_enabled; + } + + if(tenancyConfigs.default_tenant != null) + { + config.dynamic.kibana.default_tenant = tenancyConfigs.default_tenant; + } + + validate(config); + + dynamicConfig.putCEntry("config", config); + + // When performing an update to the configuration run as admin + try (final ThreadContext.StoredContext stashedContext = pool.getThreadContext().stashContext()) { + // Update the security configuration and make sure the cluster has fully refreshed + AbstractApiAction.saveAndUpdateConfigs(this.securityIndex, this.client, CType.CONFIG, dynamicConfig, new ActionListener(){ + + @Override + public void onResponse(final IndexResponse response) { + // After processing the request, restore the user context + stashedContext.close(); + try { + // Lookup the current value and notify the listener + client.execute(TenancyConfigRetrieveActions.INSTANCE, new EmptyRequest(), listener); + } catch (IOException ioe) { + log.error(ioe); + listener.onFailure(ioe); + } + } + + @Override + public void onFailure(Exception e) { + log.error(e); + listener.onFailure(e); + } + }); + } + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigs.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigs.java new file mode 100644 index 0000000000..4e8fc41ef4 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigs.java @@ -0,0 +1,18 @@ +/* + * 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.security.action.tenancy; + +public class TenancyConfigs { + public Boolean multitenancy_enabled; + public Boolean private_tenant_enabled; + public String default_tenant; +} diff --git a/src/main/java/org/opensearch/security/configuration/PrivilegesInterceptorImpl.java b/src/main/java/org/opensearch/security/configuration/PrivilegesInterceptorImpl.java index 262aadf424..e2f10dfcae 100644 --- a/src/main/java/org/opensearch/security/configuration/PrivilegesInterceptorImpl.java +++ b/src/main/java/org/opensearch/security/configuration/PrivilegesInterceptorImpl.java @@ -108,6 +108,13 @@ public ReplaceResult replaceDashboardsIndex(final ActionRequest request, final S final String dashboardsIndexName = config.getDashboardsIndexname();//config.dynamic.kibana.index; String requestedTenant = user.getRequestedTenant(); + if(USER_TENANT.equals(requestedTenant)) { + final boolean private_tenant_enabled = config.isDashboardsPrivateTenantEnabled(); + if(!private_tenant_enabled) { + return ACCESS_DENIED_REPLACE_RESULT; + } + } + final boolean isDebugEnabled = log.isDebugEnabled(); if (isDebugEnabled) { log.debug("raw requestedTenant: '" + requestedTenant + "'"); diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index fa69be0ad4..a73b174ee2 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -75,7 +75,7 @@ public abstract class AbstractApiAction extends BaseRestHandler { protected final ConfigurationRepository cl; protected final ClusterService cs; final ThreadPool threadPool; - protected String opendistroIndex; + protected String securityIndexName; private final RestApiPrivilegesEvaluator restApiPrivilegesEvaluator; protected final RestApiAdminPrivilegesEvaluator restApiAdminPrivilegesEvaluator; protected final AuditLog auditLog; @@ -87,7 +87,7 @@ protected AbstractApiAction(final Settings settings, final Path configPath, fina ThreadPool threadPool, AuditLog auditLog) { super(); this.settings = settings; - this.opendistroIndex = settings.get(ConfigConstants.SECURITY_CONFIG_INDEX_NAME, + this.securityIndexName = settings.get(ConfigConstants.SECURITY_CONFIG_INDEX_NAME, ConfigConstants.OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX); this.cl = cl; @@ -157,7 +157,7 @@ protected void handleDelete(final RestChannel channel, final RestRequest request existingConfiguration.remove(name); if (existed) { - saveAnUpdateConfigs(client, request, getConfigName(), existingConfiguration, new OnSucessActionListener(channel) { + AbstractApiAction.saveAndUpdateConfigs(this.securityIndexName, client, getConfigName(), existingConfiguration, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { @@ -207,7 +207,7 @@ protected void handlePut(final RestChannel channel, final RestRequest request, f } existingConfiguration.putCObject(name, newContent); - saveAnUpdateConfigs(client, request, getConfigName(), existingConfiguration, new OnSucessActionListener(channel) { + AbstractApiAction.saveAndUpdateConfigs(this.securityIndexName, client, getConfigName(), existingConfiguration, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { @@ -270,7 +270,7 @@ protected final SecurityDynamicConfiguration load(final CType config, boolean } protected boolean ensureIndexExists() { - if (!cs.state().metadata().hasConcreteIndex(this.opendistroIndex)) { + if (!cs.state().metadata().hasConcreteIndex(this.securityIndexName)) { return false; } return true; @@ -313,11 +313,8 @@ public final void onFailure(Exception e) { } - protected void saveAnUpdateConfigs(final Client client, final RestRequest request, final CType cType, - final SecurityDynamicConfiguration configuration, OnSucessActionListener actionListener) { - final IndexRequest ir = new IndexRequest(this.opendistroIndex); - - //final String type = "_doc"; + public static void saveAndUpdateConfigs(final String indexName, final Client client, final CType cType, final SecurityDynamicConfiguration configuration, final ActionListener actionListener) { + final IndexRequest ir = new IndexRequest(indexName); final String id = cType.toLCString(); configuration.removeStatic(); @@ -485,6 +482,7 @@ protected void successResponse(RestChannel channel) { try { final XContentBuilder builder = channel.newBuilder(); builder.startObject(); + builder.endObject(); channel.sendResponse( new BytesRestResponse(RestStatus.OK, builder)); } catch (IOException e) { diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java index 885a5476af..5e4799d655 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java @@ -224,7 +224,7 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C internalUserEntry.setHash(hash); - saveAnUpdateConfigs(client, request, CType.INTERNALUSERS, internalUser, new OnSucessActionListener(channel) { + AccountApiAction.saveAndUpdateConfigs(this.securityIndexName, client, CType.INTERNALUSERS, internalUser, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { successResponse(channel, "'" + username + "' updated."); diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AllowlistApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AllowlistApiAction.java index b37375a461..cefaeb5c6c 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AllowlistApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AllowlistApiAction.java @@ -141,7 +141,7 @@ protected void handlePut(final RestChannel channel, final RestRequest request, f boolean existed = existingConfiguration.exists(name); existingConfiguration.putCObject(name, DefaultObjectMapper.readTree(content, existingConfiguration.getImplementingClass())); - saveAnUpdateConfigs(client, request, getConfigName(), existingConfiguration, new OnSucessActionListener(channel) { + saveAndUpdateConfigs(this.securityIndexName,client, getConfigName(), existingConfiguration, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index 417465e353..646e1f81d6 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -172,7 +172,7 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C // checks complete, create or update the user internalUsersConfiguration.putCObject(username, DefaultObjectMapper.readTree(contentAsNode, internalUsersConfiguration.getImplementingClass())); - saveAnUpdateConfigs(client, request, CType.INTERNALUSERS, internalUsersConfiguration, new OnSucessActionListener(channel) { + saveAndUpdateConfigs(this.securityIndexName,client, CType.INTERNALUSERS, internalUsersConfiguration, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/MigrateApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/MigrateApiAction.java index 1a1092e2fb..d252515f72 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/MigrateApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/MigrateApiAction.java @@ -140,8 +140,8 @@ protected void handlePost(RestChannel channel, RestRequest request, Client clien final SecurityDynamicConfiguration auditConfigV7 = Migration.migrateAudit(auditConfigV6); builder.add(auditConfigV7); - final int replicas = cs.state().metadata().index(opendistroIndex).getNumberOfReplicas(); - final String autoExpandReplicas = cs.state().metadata().index(opendistroIndex).getSettings().get(IndexMetadata.SETTING_AUTO_EXPAND_REPLICAS); + final int replicas = cs.state().metadata().index(securityIndexName).getNumberOfReplicas(); + final String autoExpandReplicas = cs.state().metadata().index(securityIndexName).getSettings().get(IndexMetadata.SETTING_AUTO_EXPAND_REPLICAS); final Builder securityIndexSettings = Settings.builder(); @@ -153,7 +153,7 @@ protected void handlePost(RestChannel channel, RestRequest request, Client clien securityIndexSettings.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1); - client.admin().indices().prepareDelete(this.opendistroIndex).execute(new ActionListener() { + client.admin().indices().prepareDelete(this.securityIndexName).execute(new ActionListener() { @Override public void onResponse(AcknowledgedResponse response) { @@ -161,14 +161,14 @@ public void onResponse(AcknowledgedResponse response) { if (response.isAcknowledged()) { log.debug("opendistro_security index deleted successfully"); - client.admin().indices().prepareCreate(opendistroIndex).setSettings(securityIndexSettings) + client.admin().indices().prepareCreate(securityIndexName).setSettings(securityIndexSettings) .execute(new ActionListener() { @Override public void onResponse(CreateIndexResponse response) { final List> dynamicConfigurations = builder.build(); final ImmutableList.Builder cTypes = ImmutableList.builderWithExpectedSize(dynamicConfigurations.size()); - final BulkRequestBuilder br = client.prepareBulk(opendistroIndex); + final BulkRequestBuilder br = client.prepareBulk(securityIndexName); br.setRefreshPolicy(RefreshPolicy.IMMEDIATE); try { for (SecurityDynamicConfiguration dynamicConfiguration : dynamicConfigurations) { diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/PatchableResourceApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/PatchableResourceApiAction.java index 6d644c1eae..deb56a69c7 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/PatchableResourceApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/PatchableResourceApiAction.java @@ -162,7 +162,7 @@ private void handleSinglePatch(RestChannel channel, RestRequest request, Client } } - saveAnUpdateConfigs(client, request, getConfigName(), mdc, new OnSucessActionListener(channel){ + saveAndUpdateConfigs(this.securityIndexName,client, getConfigName(), mdc, new OnSucessActionListener(channel){ @Override public void onResponse(IndexResponse response) { @@ -244,7 +244,7 @@ private void handleBulkPatch(RestChannel channel, RestRequest request, Client cl } } - saveAnUpdateConfigs(client, request, getConfigName(), mdc, new OnSucessActionListener(channel) { + saveAndUpdateConfigs(this.securityIndexName,client, getConfigName(), mdc, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/RolesMappingApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/RolesMappingApiAction.java index b056a25ad2..72928cd0ad 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/RolesMappingApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/RolesMappingApiAction.java @@ -82,7 +82,7 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C } rolesMappingConfiguration.putCObject(name, DefaultObjectMapper.readTree(content, rolesMappingConfiguration.getImplementingClass())); - saveAnUpdateConfigs(client, request, getConfigName(), rolesMappingConfiguration, new OnSucessActionListener(channel) { + saveAndUpdateConfigs(this.securityIndexName,client, getConfigName(), rolesMappingConfiguration, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index cceaeb4cb0..2c0e7ac7c0 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -525,6 +525,15 @@ public boolean multitenancyEnabled() { && dcm.isDashboardsMultitenancyEnabled(); } + public boolean privateTenantEnabled() { + return privilegesInterceptor.getClass() != PrivilegesInterceptor.class + && dcm.isDashboardsPrivateTenantEnabled(); + } + + public String dashboardsDefaultTenant() { + return dcm.getDashboardsDefaultTenant(); + } + public boolean notFailOnForbiddenEnabled() { return privilegesInterceptor.getClass() != PrivilegesInterceptor.class && dcm.isDnfofEnabled(); diff --git a/src/main/java/org/opensearch/security/rest/DashboardsInfoAction.java b/src/main/java/org/opensearch/security/rest/DashboardsInfoAction.java index aa714ebcbb..0fd88e7565 100644 --- a/src/main/java/org/opensearch/security/rest/DashboardsInfoAction.java +++ b/src/main/java/org/opensearch/security/rest/DashboardsInfoAction.java @@ -103,6 +103,9 @@ public void accept(RestChannel channel) throws Exception { builder.field("opensearch_dashboards_mt_enabled", evaluator.multitenancyEnabled()); builder.field("opensearch_dashboards_index", evaluator.dashboardsIndex()); builder.field("opensearch_dashboards_server_user", evaluator.dashboardsServerUsername()); + builder.field("multitenancy_enabled", evaluator.multitenancyEnabled()); + builder.field("private_tenant_enabled", evaluator.privateTenantEnabled()); + builder.field("default_tenant", evaluator.dashboardsDefaultTenant()); builder.endObject(); response = new BytesRestResponse(RestStatus.OK, builder); diff --git a/src/main/java/org/opensearch/security/securityconf/DynamicConfigModel.java b/src/main/java/org/opensearch/security/securityconf/DynamicConfigModel.java index 87bcf5241d..f91e768283 100644 --- a/src/main/java/org/opensearch/security/securityconf/DynamicConfigModel.java +++ b/src/main/java/org/opensearch/security/securityconf/DynamicConfigModel.java @@ -68,6 +68,8 @@ public abstract class DynamicConfigModel { public abstract String getDashboardsOpenSearchRole(); public abstract String getDashboardsIndexname(); public abstract boolean isDashboardsMultitenancyEnabled(); + public abstract boolean isDashboardsPrivateTenantEnabled(); + public abstract String getDashboardsDefaultTenant(); public abstract boolean isDnfofEnabled(); public abstract boolean isMultiRolespanEnabled(); public abstract String getFilteredAliasMode(); diff --git a/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV6.java b/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV6.java index c9738c7e70..40b3e3319a 100644 --- a/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV6.java +++ b/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV6.java @@ -141,6 +141,12 @@ public boolean isDashboardsMultitenancyEnabled() { return config.dynamic.kibana.multitenancy_enabled; } @Override + public boolean isDashboardsPrivateTenantEnabled() { + return config.dynamic.kibana.private_tenant_enabled; + } + @Override + public String getDashboardsDefaultTenant() { return config.dynamic.kibana.default_tenant; } + @Override public boolean isDnfofEnabled() { return config.dynamic.do_not_fail_on_forbidden || config.dynamic.kibana.do_not_fail_on_forbidden; } diff --git a/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV7.java b/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV7.java index f2ec110cbd..6db5fba0a7 100644 --- a/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV7.java +++ b/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV7.java @@ -141,6 +141,12 @@ public boolean isDashboardsMultitenancyEnabled() { return config.dynamic.kibana.multitenancy_enabled; } @Override + public boolean isDashboardsPrivateTenantEnabled() { + return config.dynamic.kibana.private_tenant_enabled; + } + @Override + public String getDashboardsDefaultTenant() { return config.dynamic.kibana.default_tenant; } + @Override public boolean isDnfofEnabled() { return config.dynamic.do_not_fail_on_forbidden; } diff --git a/src/main/java/org/opensearch/security/securityconf/impl/v6/ConfigV6.java b/src/main/java/org/opensearch/security/securityconf/impl/v6/ConfigV6.java index f9da5ea314..6599942d34 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/v6/ConfigV6.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/v6/ConfigV6.java @@ -83,6 +83,10 @@ public static class Kibana { @JsonInclude(JsonInclude.Include.NON_NULL) public boolean multitenancy_enabled = true; + @JsonInclude(JsonInclude.Include.NON_NULL) + public boolean private_tenant_enabled = true; + @JsonInclude(JsonInclude.Include.NON_NULL) + public String default_tenant = ""; public String server_username = "kibanaserver"; public String opendistro_role = null; public String index = ".kibana"; diff --git a/src/main/java/org/opensearch/security/securityconf/impl/v7/ConfigV7.java b/src/main/java/org/opensearch/security/securityconf/impl/v7/ConfigV7.java index 0e83590d3e..3029b42abf 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/v7/ConfigV7.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/v7/ConfigV7.java @@ -69,6 +69,8 @@ public ConfigV7(ConfigV6 c6) { dynamic.kibana.index = c6.dynamic.kibana.index; dynamic.kibana.multitenancy_enabled = c6.dynamic.kibana.multitenancy_enabled; + dynamic.kibana.private_tenant_enabled = true; + dynamic.kibana.default_tenant = ""; dynamic.kibana.server_username = c6.dynamic.kibana.server_username; dynamic.http = new Http(); @@ -135,12 +137,18 @@ public static class Kibana { @JsonInclude(JsonInclude.Include.NON_NULL) public boolean multitenancy_enabled = true; + @JsonInclude(JsonInclude.Include.NON_NULL) + public boolean private_tenant_enabled = true; + @JsonInclude(JsonInclude.Include.NON_NULL) + public String default_tenant = ""; public String server_username = "kibanaserver"; public String opendistro_role = null; public String index = ".kibana"; @Override public String toString() { - return "Kibana [multitenancy_enabled=" + multitenancy_enabled + ", server_username=" + server_username + ", opendistro_role=" + opendistro_role + return "Kibana [multitenancy_enabled=" + multitenancy_enabled + ", private_tenant_enabled=" + + private_tenant_enabled + ", default_tenant=" + default_tenant + ", server_username=" + + server_username + ", opendistro_role=" + opendistro_role + ", index=" + index + "]"; } diff --git a/src/main/java/org/opensearch/security/support/ConfigConstants.java b/src/main/java/org/opensearch/security/support/ConfigConstants.java index 375b22b65f..f81d89810b 100644 --- a/src/main/java/org/opensearch/security/support/ConfigConstants.java +++ b/src/main/java/org/opensearch/security/support/ConfigConstants.java @@ -287,6 +287,10 @@ public enum RolesMappingResolution { public static final String SECURITY_SYSTEM_INDICES_KEY = "plugins.security.system_indices.indices"; public static final List SECURITY_SYSTEM_INDICES_DEFAULT = Collections.emptyList(); + public static final String TENANCY_PRIVATE_TENANT_NAME = "Private"; + public static final String TENANCY_GLOBAL_TENANT_NAME = "Global"; + public static final String TENANCY_GLOBAL_TENANT_DEFAULT_NAME = ""; + public static Set getSettingAsSet(final Settings settings, final String key, final List defaultList, final boolean ignoreCaseForNone) { final List list = settings.getAsList(key, defaultList); if (list.size() == 1 && "NONE".equals(ignoreCaseForNone? list.get(0).toUpperCase() : list.get(0))) { diff --git a/src/test/java/org/opensearch/security/multitenancy/test/TenancyDefaultTenantTests.java b/src/test/java/org/opensearch/security/multitenancy/test/TenancyDefaultTenantTests.java new file mode 100644 index 0000000000..b4d6aa4b59 --- /dev/null +++ b/src/test/java/org/opensearch/security/multitenancy/test/TenancyDefaultTenantTests.java @@ -0,0 +1,96 @@ +/* + * 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.security.multitenancy.test; + +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpStatus; +import org.junit.Test; + +import org.opensearch.security.support.ConfigConstants; +import org.opensearch.security.test.SingleClusterTest; +import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.StringContains.containsString; + +public class TenancyDefaultTenantTests extends SingleClusterTest { + private final Header asAdminUser = encodeBasicHeader("admin", "admin"); + private final Header asUser = encodeBasicHeader("kirk", "kirk"); + + @Override + protected String getResourceFolder() { + return "multitenancy"; + } + + @Test + public void testDefaultTenantUpdate() throws Exception { + setup(); + + final HttpResponse getSettingResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asAdminUser); + assertThat(getSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(getSettingResponse.findValueInJson("default_tenant"), equalTo(ConfigConstants.TENANCY_GLOBAL_TENANT_DEFAULT_NAME)); + + HttpResponse getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(getDashboardsinfoResponse.findValueInJson("default_tenant"), equalTo(ConfigConstants.TENANCY_GLOBAL_TENANT_DEFAULT_NAME)); + + final HttpResponse setPrivateTenantAsDefaultResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"default_tenant\": \"Private\"}", asAdminUser); + assertThat(setPrivateTenantAsDefaultResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(getDashboardsinfoResponse.findValueInJson("default_tenant"), equalTo(ConfigConstants.TENANCY_PRIVATE_TENANT_NAME)); + } + + @Test + public void testDefaultTenant_UpdateFailed() throws Exception { + setup(); + + final HttpResponse disablePrivateTenantResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"private_tenant_enabled\":false}", asAdminUser); + assertThat(disablePrivateTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + + + final HttpResponse setPrivateTenantAsDefaultFailResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"default_tenant\": \"Private\"}", asAdminUser); + assertThat(setPrivateTenantAsDefaultFailResponse.getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST)); + assertThat(setPrivateTenantAsDefaultFailResponse.findValueInJson("error.reason"), containsString("Private tenant can not be disabled if it is the default tenant.")); + + final HttpResponse enablePrivateTenantResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"private_tenant_enabled\":true}", asAdminUser); + assertThat(enablePrivateTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + + final HttpResponse setPrivateTenantAsDefaultResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"default_tenant\": \"Private\"}", asAdminUser); + assertThat(setPrivateTenantAsDefaultResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + + final HttpResponse getSettingResponseAfterUpdate = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asAdminUser); + assertThat(getSettingResponseAfterUpdate.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(getSettingResponseAfterUpdate.findValueInJson("default_tenant"), equalTo(ConfigConstants.TENANCY_PRIVATE_TENANT_NAME)); + + HttpResponse getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.findValueInJson("default_tenant"),equalTo(ConfigConstants.TENANCY_PRIVATE_TENANT_NAME)); + + final HttpResponse setRandomStringAsDefaultTenant = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"default_tenant\": \"NonExistentTenant\"}", asAdminUser); + assertThat(setRandomStringAsDefaultTenant.getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST)); + assertThat(setRandomStringAsDefaultTenant.findValueInJson("error.reason"), containsString("Default tenant should be selected from one of the available tenants.")); + + } + @Test + public void testForbiddenAccess() throws Exception { + setup(); + + final HttpResponse getSettingResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asUser); + assertThat(getSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(getSettingResponse.findValueInJson("error.reason"), containsString("no permissions for [cluster:feature/tenancy/config/read]")); + + final HttpResponse updateSettingResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"default_tenant\": \"Private\"}", asUser); + assertThat(updateSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(updateSettingResponse.findValueInJson("error.reason"), containsString("no permissions for [cluster:feature/tenancy/config/update]")); + } +} diff --git a/src/test/java/org/opensearch/security/multitenancy/test/TenancyMultitenancyEnabledTests.java b/src/test/java/org/opensearch/security/multitenancy/test/TenancyMultitenancyEnabledTests.java new file mode 100644 index 0000000000..033d38ed41 --- /dev/null +++ b/src/test/java/org/opensearch/security/multitenancy/test/TenancyMultitenancyEnabledTests.java @@ -0,0 +1,89 @@ +/* + * 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.security.multitenancy.test; + +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.message.BasicHeader; +import org.junit.Test; + +import org.opensearch.security.test.SingleClusterTest; +import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.StringContains.containsString; + +public class TenancyMultitenancyEnabledTests extends SingleClusterTest { + private final Header asAdminUser = encodeBasicHeader("admin", "admin"); + private final Header asUser = encodeBasicHeader("kirk", "kirk"); + private final Header onUserTenant = new BasicHeader("securitytenant", "__user__"); + + private static String createIndexPatternDoc(final String title) { + return "{"+ + "\"type\" : \"index-pattern\","+ + "\"updated_at\" : \"2018-09-29T08:56:59.066Z\","+ + "\"index-pattern\" : {"+ + "\"title\" : \"" + title + "\""+ + "}}"; + } + + @Override + protected String getResourceFolder() { + return "multitenancy"; + } + + @Test + public void testMultitenancyDisabled_endToEndTest() throws Exception { + setup(); + + final HttpResponse getSettingResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asAdminUser); + assertThat(getSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(getSettingResponse.findValueInJson("multitenancy_enabled"), equalTo("true")); + + HttpResponse getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.findValueInJson("multitenancy_enabled"),equalTo("true")); + + final HttpResponse createDocInGlobalTenantResponse = nonSslRestHelper().executePostRequest(".kibana/_doc?refresh=true", createIndexPatternDoc("globalIndex"), asAdminUser); + assertThat(createDocInGlobalTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_CREATED)); + final HttpResponse createDocInUserTenantResponse = nonSslRestHelper().executePostRequest(".kibana/_doc?refresh=true", createIndexPatternDoc("userIndex"), onUserTenant, asAdminUser); + assertThat(createDocInUserTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_CREATED)); + + final HttpResponse searchInUserTenantWithMutlitenancyEnabled = nonSslRestHelper().executeGetRequest(".kibana/_search", onUserTenant, asAdminUser); + assertThat(searchInUserTenantWithMutlitenancyEnabled.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(searchInUserTenantWithMutlitenancyEnabled.findValueInJson("hits.hits[0]._source.index-pattern.title"), equalTo("userIndex")); + + final HttpResponse updateMutlitenancyToDisabled = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"multitenancy_enabled\": \"false\"}", asAdminUser); + assertThat(updateMutlitenancyToDisabled.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(updateMutlitenancyToDisabled.findValueInJson("multitenancy_enabled"), equalTo("false")); + + getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.findValueInJson("multitenancy_enabled"),equalTo("false")); + + final HttpResponse searchInUserTenantWithMutlitenancyDisabled = nonSslRestHelper().executeGetRequest(".kibana/_search", onUserTenant, asAdminUser); + assertThat(searchInUserTenantWithMutlitenancyDisabled.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(searchInUserTenantWithMutlitenancyDisabled.findValueInJson("hits.hits[0]._source.index-pattern.title"), equalTo("globalIndex")); + } + + @Test + public void testForbiddenAccess() throws Exception { + setup(); + + final HttpResponse getSettingResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asUser); + assertThat(getSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(getSettingResponse.findValueInJson("error.reason"), containsString("no permissions for [cluster:feature/tenancy/config/read]")); + + final HttpResponse updateSettingResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"multitenancy_enabled\": \"false\"}", asUser); + assertThat(updateSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(updateSettingResponse.findValueInJson("error.reason"), containsString("no permissions for [cluster:feature/tenancy/config/update]")); + } +} diff --git a/src/test/java/org/opensearch/security/multitenancy/test/TenancyPrivateTenantEnabledTests.java b/src/test/java/org/opensearch/security/multitenancy/test/TenancyPrivateTenantEnabledTests.java new file mode 100644 index 0000000000..c6927dbbf8 --- /dev/null +++ b/src/test/java/org/opensearch/security/multitenancy/test/TenancyPrivateTenantEnabledTests.java @@ -0,0 +1,101 @@ +/* + * 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.security.multitenancy.test; + +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.message.BasicHeader; +import org.junit.Test; + +import org.opensearch.security.test.SingleClusterTest; +import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.StringContains.containsString; + +public class TenancyPrivateTenantEnabledTests extends SingleClusterTest { + private final Header asAdminUser = encodeBasicHeader("admin", "admin"); + private final Header asUser = encodeBasicHeader("kirk", "kirk"); + private final Header onUserTenant = new BasicHeader("securitytenant", "__user__"); + + private static String createIndexPatternDoc(final String title) { + return "{"+ + "\"type\" : \"index-pattern\","+ + "\"updated_at\" : \"2018-09-29T08:56:59.066Z\","+ + "\"index-pattern\" : {"+ + "\"title\" : \"" + title + "\""+ + "}}"; + } + + @Override + protected String getResourceFolder() { + return "multitenancy"; + } + + @Test + public void testPrivateTenantDisabled_Update() throws Exception { + setup(); + + final HttpResponse getSettingResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asAdminUser); + assertThat(getSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(getSettingResponse.findValueInJson("private_tenant_enabled"), equalTo("true")); + + HttpResponse getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.findValueInJson("private_tenant_enabled"), equalTo("true")); + + final HttpResponse createDocInGlobalTenantResponse = nonSslRestHelper().executePostRequest(".kibana/_doc?refresh=true", createIndexPatternDoc("globalIndex"), asAdminUser); + assertThat(createDocInGlobalTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_CREATED)); + final HttpResponse createDocInUserTenantResponse = nonSslRestHelper().executePostRequest(".kibana/_doc?refresh=true", createIndexPatternDoc("userIndex"), onUserTenant, asUser); + assertThat(createDocInUserTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_CREATED)); + + final HttpResponse searchInUserTenantWithPrivateTenantEnabled = nonSslRestHelper().executeGetRequest(".kibana/_search", onUserTenant, asUser); + assertThat(searchInUserTenantWithPrivateTenantEnabled.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(searchInUserTenantWithPrivateTenantEnabled.findValueInJson("hits.hits[0]._source.index-pattern.title"), equalTo("userIndex")); + + final HttpResponse disablePrivateTenantResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"private_tenant_enabled\": \"false\"}", asAdminUser); + assertThat(disablePrivateTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(disablePrivateTenantResponse.findValueInJson("private_tenant_enabled"), equalTo("false")); + + getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.findValueInJson("private_tenant_enabled"),equalTo("false")); + + final HttpResponse searchInUserTenantWithPrivateTenantDisabled = nonSslRestHelper().executeGetRequest(".kibana/_search", onUserTenant, asUser); + assertThat(searchInUserTenantWithPrivateTenantDisabled.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(searchInUserTenantWithPrivateTenantDisabled.findValueInJson("error.reason"), containsString("no permissions for [indices:data/read/search] and User")); + + } + + @Test + public void testPrivateTenantDisabled_UpdateFailed() throws Exception { + setup(); + + final HttpResponse setPrivateTenantAsDefaultResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"default_tenant\": \"Private\"}", asAdminUser); + assertThat(setPrivateTenantAsDefaultResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + final HttpResponse updateSettingResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"private_tenant_enabled\":false}", asAdminUser); + assertThat(updateSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST)); + assertThat(updateSettingResponse.findValueInJson("error.reason"), containsString("Private tenant can not be disabled if it is the default tenant.")); + } + + @Test + public void testForbiddenAccess() throws Exception { + setup(); + + final HttpResponse getSettingResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asUser); + assertThat(getSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(getSettingResponse.findValueInJson("error.reason"), containsString("no permissions for [cluster:feature/tenancy/config/read]")); + + final HttpResponse updateSettingResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"private_tenant_enabled\": false}", asUser); + assertThat(updateSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(updateSettingResponse.findValueInJson("error.reason"), containsString("no permissions for [cluster:feature/tenancy/config/update]")); + } +} diff --git a/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java b/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java index ff9a5b536b..367332f160 100644 --- a/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java +++ b/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java @@ -92,8 +92,6 @@ import org.opensearch.security.test.helper.cluster.ClusterInfo; import org.opensearch.security.test.helper.file.FileHelper; -import static org.junit.jupiter.api.Assertions.fail; - public class RestHelper { protected final Logger log = LogManager.getLogger(RestHelper.class); @@ -480,7 +478,7 @@ public String toString() { public String findValueInJson(final String jsonDotPath) { // Make sure its json / then parse it if (!isJsonContentType()) { - fail("Response was expected to be JSON, body was: \n" + body); + throw new RuntimeException("Response was expected to be JSON, body was: \n" + body); } JsonNode currentNode = null; try { @@ -492,7 +490,7 @@ public String findValueInJson(final String jsonDotPath) { // Break the path into parts, and scan into the json object try (final Scanner jsonPathScanner = new Scanner(jsonDotPath).useDelimiter("\\.")) { if (!jsonPathScanner.hasNext()) { - fail("Invalid json dot path '" + jsonDotPath + "', rewrite with '.' characters between path elements."); + throw new RuntimeException("Invalid json dot path '" + jsonDotPath + "', rewrite with '.' characters between path elements."); } do { String pathEntry = jsonPathScanner.next(); @@ -510,23 +508,23 @@ public String findValueInJson(final String jsonDotPath) { } if (!currentNode.has(pathEntry)) { - fail("Unable to resolve '" + jsonDotPath + "', on path entry '" + pathEntry + "' from available fields " + currentNode.toPrettyString()); + throw new RuntimeException("Unable to resolve '" + jsonDotPath + "', on path entry '" + pathEntry + "' from available fields " + currentNode.toPrettyString()); } currentNode = currentNode.get(pathEntry); // if it's an Array lookup we get the requested index item if (arrayEntryIdx > -1) { if(!currentNode.isArray()) { - fail("Unable to resolve '" + jsonDotPath + "', the '" + pathEntry + "' field is not an array " + currentNode.toPrettyString()); + throw new RuntimeException("Unable to resolve '" + jsonDotPath + "', the '" + pathEntry + "' field is not an array " + currentNode.toPrettyString()); } else if (!currentNode.has(arrayEntryIdx)) { - fail("Unable to resolve '" + jsonDotPath + "', index '" + arrayEntryIdx + "' is out of bounds for array '" + pathEntry + "' \n" + currentNode.toPrettyString()); + throw new RuntimeException("Unable to resolve '" + jsonDotPath + "', index '" + arrayEntryIdx + "' is out of bounds for array '" + pathEntry + "' \n" + currentNode.toPrettyString()); } currentNode = currentNode.get(arrayEntryIdx); } } while (jsonPathScanner.hasNext()); if (!currentNode.isValueNode()) { - fail("Unexpected value note, index directly to the object to reference, object\n" + currentNode.toPrettyString()); + throw new RuntimeException("Unexpected value note, index directly to the object to reference, object\n" + currentNode.toPrettyString()); } return currentNode.asText(); } diff --git a/src/test/resources/auditlog/config.yml b/src/test/resources/auditlog/config.yml index 938a38cd38..c1d0c63174 100644 --- a/src/test/resources/auditlog/config.yml +++ b/src/test/resources/auditlog/config.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/cache/config.yml b/src/test/resources/cache/config.yml index 2a48434203..1a5e86fc2f 100644 --- a/src/test/resources/cache/config.yml +++ b/src/test/resources/cache/config.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/composite_config.yml b/src/test/resources/composite_config.yml index f636d823e0..3f6eb78627 100644 --- a/src/test/resources/composite_config.yml +++ b/src/test/resources/composite_config.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config.yml b/src/test/resources/config.yml index 34f4aff093..3663b3c706 100644 --- a/src/test/resources/config.yml +++ b/src/test/resources/config.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_anon.yml b/src/test/resources/config_anon.yml index 7c8a037f25..0c2c5ccbcc 100644 --- a/src/test/resources/config_anon.yml +++ b/src/test/resources/config_anon.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_clientcert.yml b/src/test/resources/config_clientcert.yml index 441f6c9e5f..c50d770c26 100644 --- a/src/test/resources/config_clientcert.yml +++ b/src/test/resources/config_clientcert.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_disable_all.yml b/src/test/resources/config_disable_all.yml index 8f8e414672..fef8297b7f 100644 --- a/src/test/resources/config_disable_all.yml +++ b/src/test/resources/config_disable_all.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_dnfof.yml b/src/test/resources/config_dnfof.yml index 84c71d231a..6e0a2dcd93 100644 --- a/src/test/resources/config_dnfof.yml +++ b/src/test/resources/config_dnfof.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_invalidlic.yml b/src/test/resources/config_invalidlic.yml index 34f4aff093..3663b3c706 100644 --- a/src/test/resources/config_invalidlic.yml +++ b/src/test/resources/config_invalidlic.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_lic.yml b/src/test/resources/config_lic.yml index 34f4aff093..3663b3c706 100644 --- a/src/test/resources/config_lic.yml +++ b/src/test/resources/config_lic.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_lic_rk.yml b/src/test/resources/config_lic_rk.yml index 34f4aff093..3663b3c706 100644 --- a/src/test/resources/config_lic_rk.yml +++ b/src/test/resources/config_lic_rk.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_multirolespan.yml b/src/test/resources/config_multirolespan.yml index dee3d042b1..388cba2903 100644 --- a/src/test/resources/config_multirolespan.yml +++ b/src/test/resources/config_multirolespan.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_protected_indices.yml b/src/test/resources/config_protected_indices.yml index 791656523d..86b01d197c 100644 --- a/src/test/resources/config_protected_indices.yml +++ b/src/test/resources/config_protected_indices.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_proxy.yml b/src/test/resources/config_proxy.yml index 52f5880806..b3151d9748 100644 --- a/src/test/resources/config_proxy.yml +++ b/src/test/resources/config_proxy.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_proxy_custom.yml b/src/test/resources/config_proxy_custom.yml index 78e0aa70f3..cf03610e4b 100644 --- a/src/test/resources/config_proxy_custom.yml +++ b/src/test/resources/config_proxy_custom.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_respect_indices_options.yml b/src/test/resources/config_respect_indices_options.yml index 9508c12b34..86e9e6487b 100644 --- a/src/test/resources/config_respect_indices_options.yml +++ b/src/test/resources/config_respect_indices_options.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_rest_impersonation.yml b/src/test/resources/config_rest_impersonation.yml index 36c1b09cf1..a34232ff77 100644 --- a/src/test/resources/config_rest_impersonation.yml +++ b/src/test/resources/config_rest_impersonation.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_system_indices.yml b/src/test/resources/config_system_indices.yml index 791656523d..86b01d197c 100644 --- a/src/test/resources/config_system_indices.yml +++ b/src/test/resources/config_system_indices.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_transport_username.yml b/src/test/resources/config_transport_username.yml index 0cd5204005..f473a47320 100644 --- a/src/test/resources/config_transport_username.yml +++ b/src/test/resources/config_transport_username.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_xff.yml b/src/test/resources/config_xff.yml index 85ceca5e21..ed93efc2b1 100644 --- a/src/test/resources/config_xff.yml +++ b/src/test/resources/config_xff.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/dlsfls/config.yml b/src/test/resources/dlsfls/config.yml index 1288ebeea2..cf110efda5 100644 --- a/src/test/resources/dlsfls/config.yml +++ b/src/test/resources/dlsfls/config.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/ldap/config.yml b/src/test/resources/ldap/config.yml index ea8271c6df..9257fa5b50 100644 --- a/src/test/resources/ldap/config.yml +++ b/src/test/resources/ldap/config.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/ldap/config_ldap2.yml b/src/test/resources/ldap/config_ldap2.yml index 51956d4cfc..a9b477fcec 100644 --- a/src/test/resources/ldap/config_ldap2.yml +++ b/src/test/resources/ldap/config_ldap2.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/multitenancy/config.yml b/src/test/resources/multitenancy/config.yml index 704937b9ee..d1514e9cb2 100644 --- a/src/test/resources/multitenancy/config.yml +++ b/src/test/resources/multitenancy/config.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/multitenancy/config_anonymous.yml b/src/test/resources/multitenancy/config_anonymous.yml index 97a43b20a8..1ae5e145fe 100644 --- a/src/test/resources/multitenancy/config_anonymous.yml +++ b/src/test/resources/multitenancy/config_anonymous.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/multitenancy/config_basic_auth.yml b/src/test/resources/multitenancy/config_basic_auth.yml index 289eb19cd2..f60caab0b7 100644 --- a/src/test/resources/multitenancy/config_basic_auth.yml +++ b/src/test/resources/multitenancy/config_basic_auth.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/multitenancy/config_nodnfof.yml b/src/test/resources/multitenancy/config_nodnfof.yml index 462e3e9e64..f4afce87d4 100644 --- a/src/test/resources/multitenancy/config_nodnfof.yml +++ b/src/test/resources/multitenancy/config_nodnfof.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/restapi/config.yml b/src/test/resources/restapi/config.yml index 899a17a1fc..2ed865657a 100644 --- a/src/test/resources/restapi/config.yml +++ b/src/test/resources/restapi/config.yml @@ -10,6 +10,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/restapi/invalid_config.json b/src/test/resources/restapi/invalid_config.json index 76ac5e7c0f..7bbbf2201f 100644 --- a/src/test/resources/restapi/invalid_config.json +++ b/src/test/resources/restapi/invalid_config.json @@ -7,6 +7,8 @@ "respect_request_indices_options":false, "kibana":{ "multitenancy_enabled":true, + "private_tenant_enabled" : true, + "default_tenant" : "", "server_username":"kibanaserver", "index":".kibana" }, diff --git a/src/test/resources/restapi/security_config.json b/src/test/resources/restapi/security_config.json index 8a230f283c..e8acc0a22a 100644 --- a/src/test/resources/restapi/security_config.json +++ b/src/test/resources/restapi/security_config.json @@ -7,6 +7,8 @@ "respect_request_indices_options":false, "kibana":{ "multitenancy_enabled":true, + "private_tenant_enabled" : true, + "default_tenant" : "", "server_username":"kibanaserver", "index":".kibana" }, diff --git a/src/test/resources/restapi/securityconfig.json b/src/test/resources/restapi/securityconfig.json index 9e7fb32342..4e4b1bba63 100644 --- a/src/test/resources/restapi/securityconfig.json +++ b/src/test/resources/restapi/securityconfig.json @@ -7,6 +7,8 @@ "respect_request_indices_options":false, "kibana":{ "multitenancy_enabled":true, + "private_tenant_enabled" : true, + "default_tenant" : "", "server_username":"kibanaserver", "index":".kibana" }, diff --git a/src/test/resources/restapi/securityconfig_nondefault.json b/src/test/resources/restapi/securityconfig_nondefault.json index c9e6aaec5e..6fb297be37 100644 --- a/src/test/resources/restapi/securityconfig_nondefault.json +++ b/src/test/resources/restapi/securityconfig_nondefault.json @@ -6,6 +6,8 @@ "respect_request_indices_options" : false, "kibana" : { "multitenancy_enabled" : true, + "private_tenant_enabled" : true, + "default_tenant" : "", "server_username" : "kibanaserver", "index" : ".kibana" }, diff --git a/src/test/resources/security_passive/config.yml b/src/test/resources/security_passive/config.yml index 34f4aff093..3663b3c706 100644 --- a/src/test/resources/security_passive/config.yml +++ b/src/test/resources/security_passive/config.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: From 09995422f516e77aae87ff0211e97d969792a0ad Mon Sep 17 00:00:00 2001 From: Andriy Redko Date: Wed, 12 Apr 2023 10:57:05 -0400 Subject: [PATCH 10/16] Gradle plugin updates (spotless, ospackage) (#2670) Signed-off-by: Andriy Redko --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 916f1ec5e3..64798b957e 100644 --- a/build.gradle +++ b/build.gradle @@ -52,9 +52,9 @@ plugins { id 'idea' id 'jacoco' id 'maven-publish' - id 'com.diffplug.spotless' version '6.16.0' + id 'com.diffplug.spotless' version '6.18.0' id 'checkstyle' - id 'com.netflix.nebula.ospackage' version "11.0.0" + id 'com.netflix.nebula.ospackage' version "11.1.0" id "org.gradle.test-retry" version "1.5.2" id 'eclipse' id "com.github.spotbugs" version "5.0.14" From bbd43ec56cf1d7913bbe49547b09558ac37bc89f Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 14 Apr 2023 14:34:42 -0400 Subject: [PATCH 11/16] Update certs for SecuritySSLReloadCertsActionTests (#2679) * Update certs for SecuritySSLReloadCertsActionTests Signed-off-by: Craig Perkins * Add otherName back in Signed-off-by: Craig Perkins * Ensure files end in new line Signed-off-by: Craig Perkins --------- Signed-off-by: Craig Perkins --- .../SecuritySSLReloadCertsActionTests.java | 10 +- .../resources/ssl/reload/kirk-keystore.jks | Bin 5579 -> 4315 bytes .../resources/ssl/reload/node-new.crt.pem | 116 ++++++++------- .../resources/ssl/reload/node-new.key.pem | 52 +++---- .../resources/ssl/reload/node-wrong.crt.pem | 116 ++++++++------- .../resources/ssl/reload/node-wrong.key.pem | 52 +++---- src/test/resources/ssl/reload/node.crt.pem | 140 +++++++++--------- src/test/resources/ssl/reload/node.key.pem | 52 +++---- src/test/resources/ssl/reload/root-ca.pem | 44 +++--- .../resources/ssl/reload/spock-keystore.jks | Bin 5581 -> 5302 bytes src/test/resources/ssl/reload/truststore.jks | Bin 1338 -> 1398 bytes 11 files changed, 303 insertions(+), 279 deletions(-) diff --git a/src/test/java/org/opensearch/security/ssl/SecuritySSLReloadCertsActionTests.java b/src/test/java/org/opensearch/security/ssl/SecuritySSLReloadCertsActionTests.java index f7684a9c51..e1c8ec7282 100644 --- a/src/test/java/org/opensearch/security/ssl/SecuritySSLReloadCertsActionTests.java +++ b/src/test/java/org/opensearch/security/ssl/SecuritySSLReloadCertsActionTests.java @@ -53,8 +53,8 @@ public class SecuritySSLReloadCertsActionTests extends SingleClusterTest { "issuer_dn", "CN=Example Com Inc. Signing CA,OU=Example Com Inc. Signing CA,O=Example Com Inc.,DC=example,DC=com", "subject_dn", "CN=node-1.example.com,OU=SSL,O=Test,L=Test,C=DE", "san", "[[8, 1.2.3.4.5.5], [0, [2.5.4.3, node-1.example.com]], [2, node-1.example.com], [2, localhost], [7, 127.0.0.1]]", - "not_before", "2021-04-12T00:07:08Z", - "not_after", "2023-04-12T00:07:08Z" + "not_before", "2023-04-14T13:22:53Z", + "not_after", "2033-04-11T13:22:53Z" )); private final List> NEW_NODE_CERT_DETAILS = ImmutableList.of( @@ -62,8 +62,8 @@ public class SecuritySSLReloadCertsActionTests extends SingleClusterTest { "issuer_dn", "CN=Example Com Inc. Signing CA,OU=Example Com Inc. Signing CA,O=Example Com Inc.,DC=example,DC=com", "subject_dn", "CN=node-1.example.com,OU=SSL,O=Test,L=Test,C=DE", "san", "[[8, 1.2.3.4.5.5], [0, [2.5.4.3, node-1.example.com]], [2, node-1.example.com], [2, localhost], [7, 127.0.0.1]]", - "not_before", "2021-04-12T00:09:00Z", - "not_after", "2023-04-12T00:09:00Z" + "not_before", "2023-04-14T13:23:00Z", + "not_after", "2033-04-11T13:23:00Z" ) ); @@ -264,7 +264,7 @@ private void initClusterWithTestCerts() throws Exception { private void initTestCluster(final String transportPemCertFilePath, final String transportPemKeyFilePath, final String httpPemCertFilePath, final String httpPemKeyFilePath, final boolean sslCertReload) throws Exception { final Settings settings = Settings.builder() .putList(ConfigConstants.SECURITY_AUTHCZ_ADMIN_DN, "CN=kirk,OU=client,O=client,L=Test,C=DE") - .putList(ConfigConstants.SECURITY_NODES_DN, "C=DE,L=Test,O=Test,OU=SSL,CN=node-1.example.com") + .putList(ConfigConstants.SECURITY_NODES_DN, "CN=node-1.example.com,OU=SSL,O=Test,L=Test,C=DE") .put(SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENABLED, true) .put(SSLConfigConstants.SECURITY_SSL_HTTP_ENABLED, true) .put(SSLConfigConstants.SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION, false) diff --git a/src/test/resources/ssl/reload/kirk-keystore.jks b/src/test/resources/ssl/reload/kirk-keystore.jks index 6a7daa435e8d2a066237ecd9d12b455b05ccaa91..c4171431d6cd4d57230d292e36491afc41fd2c59 100644 GIT binary patch literal 4315 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 HQX~Br2}ARH literal 5579 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 Dve<%E diff --git a/src/test/resources/ssl/reload/node-new.crt.pem b/src/test/resources/ssl/reload/node-new.crt.pem index dbf6fa430c..2a3596076e 100644 --- a/src/test/resources/ssl/reload/node-new.crt.pem +++ b/src/test/resources/ssl/reload/node-new.crt.pem @@ -1,56 +1,72 @@ -----BEGIN CERTIFICATE----- -MIIE5DCCA8ygAwIBAgIGAXjDaPfJMA0GCSqGSIb3DQEBCwUAMIGVMRMwEQYKCZIm +MIIEEjCCAvqgAwIBAgIUZ60uH7iyqLpaETXOtCGy95Kwu+YwDQYJKoZIhvcNAQEL +BQAwgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFt +cGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQwIgYDVQQLDBtFeGFtcGxl +IENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAiBgNVBAMMG0V4YW1wbGUgQ29tIEluYy4g +U2lnbmluZyBDQTAeFw0yMzA0MTQxMzIzMDBaFw0zMzA0MTExMzIzMDBaMFYxCzAJ +BgNVBAYTAkRFMQ0wCwYDVQQHDARUZXN0MQ0wCwYDVQQKDARUZXN0MQwwCgYDVQQL +DANTU0wxGzAZBgNVBAMMEm5vZGUtMS5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALuHvhm9ox8mJYXLnvPcV8fFzDOojmvGkTkz08/Z +XaKIaBEG6scJ3qI54+o5e3NyHe3wAGHwTD3TYrLkuvLTGE5XTCGpYTixk8aITfuO +aNNptT38RGYjHMXOkYYFPjU2x/nurS7TSO0UEqy/hTsvPPKisExJhqQ/rNhSppx6 +pZqPKM3vAECy9db+KMzdpesW1z/BZa8GnR6OVjY8Gkl+ooImJoe1IWrzGDhy7wgT +L+DXFTnbKkxL25HpyOBVKj7QWhV9x8EE0r//M8AzDYbRDfHzDmXSOWywlMJ4MbYM +lOcMy4BVkK9DNDVxWm2pzWcvWA7AttwtOWqxCs7hn3+/uMECAwEAAaOBlzCBlDBS +BgNVHREESzBJiAUqAwQFBaAbBgNVBAOgFAwSbm9kZS0xLmV4YW1wbGUuY29tghJu +b2RlLTEuZXhhbXBsZS5jb22CCWxvY2FsaG9zdIcEfwAAATAdBgNVHQ4EFgQUI1aO +IhN1AZ4s+8klOL3Tv1Z3sskwHwYDVR0jBBgwFoAUGXJktco87q1v0BfhouzpDY+j +rlowDQYJKoZIhvcNAQELBQADggEBACFCK5rVc7pk7HXMxa6QDDmdoo5y6+WV2/Ot +s5Eiil4O8fneQapEc4ZRDA+iUS0ANFv+5iXIYysa7O0U7e4MGquwsVg61TSLPXvI +CHLEwG2yqcL+vK3oG3owC+5flPg6VhljxE7FMHJv0Ts6GkxUpgSnouU671fCblN7 +XzM2jf4HDy+17K3xDf9qMG+MkWWZxw69gQDMaT+WmhC8GSCe8lfzcecgUv/HoXhL +Y643y/jQN0xguK2kpQvC6pkCMj+xGhY+alEV/tfSJ8aYr+uUegClGsR7LVkMXiX8 +T3m4rBA4MKI449cWIqc0rHdKS3vGo6QVphSa6wt+nLnoXTiBF5s= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEBzCCAu+gAwIBAgIUf8RhLrREqQU02WxnXl87059YCKswDQYJKoZIhvcNAQEL +BQAwgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFt +cGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEwHwYDVQQLDBhFeGFtcGxl +IENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1wbGUgQ29tIEluYy4gUm9v +dCBDQTAeFw0yMzA0MTIyMTAwNDNaFw0zMzA0MDkyMTAwNDNaMIGVMRMwEQYKCZIm iZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEZMBcGA1UECgwQ RXhhbXBsZSBDb20gSW5jLjEkMCIGA1UECwwbRXhhbXBsZSBDb20gSW5jLiBTaWdu -aW5nIENBMSQwIgYDVQQDDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0EwHhcN -MjEwNDEyMDAwOTAwWhcNMjMwNDEyMDAwOTAwWjBWMQswCQYDVQQGEwJERTENMAsG -A1UEBwwEVGVzdDENMAsGA1UECgwEVGVzdDEMMAoGA1UECwwDU1NMMRswGQYDVQQD -DBJub2RlLTEuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQC+PKQOneEPtQIt4G8yeqrAhFGXUkFDID5bnAb7mk5ALX5B8bWYQa7hER6x -QpP+a7CdPLDm+PLTGkGPT0S7HpcOYli3qtED0zkk8yaCL8ztk3oyLuV97u8x4A+r -OXoO2nmrG9ck8/XZN0ktu8Q87l0EaSMsCwuRJ+A/vFeKIEijzfjhBPjn7smYUpN0 -LprrM+o//OHPsQEXsRHOpjIM7KC8a+luRxAlrxotHO0lWEA05pNHya5fqkhdYQ1M -gR0cb8zTxBB+DAfmHCgzw4rf4kSd11LJbk5CITeSd98xV28TanaDli8BHfDbk3TM -iASv3LJyq5UX/1yD1CG41UH6vpoRAgMBAAGjggF2MIIBcjCBvAYDVR0jBIG0MIGx -gBTS02Hh6adcYFVpsHSBAGZYMvoGRKGBlaSBkjCBjzETMBEGCgmSJomT8ixkARkW -A2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1wbGUg -Q29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEhMB8G -A1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBggECMB0GA1UdDgQWBBRQWhAY -IPA14V/TdxjMqcvwbdG/UTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIF4DAg -BgNVHSUBAf8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwUgYDVR0RBEswSYgFKgME -BQWgGwYDVQQDoBQMEm5vZGUtMS5leGFtcGxlLmNvbYISbm9kZS0xLmV4YW1wbGUu -Y29tgglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggEBAJVsT7kQ5JYS -dfZfo7Oq6DJfNPPPSUiGNuN8epcEF7jvEYbvZzaxAYZFqGOh7k8jG2/ISjYm6IW/ -8g8sOraYfjY1+An+UFq1Z9ykemYVyzySpHMKn8PqtIdcBzaX0fA8hO6Q0Gsm6V9G -/KpN3696rAUHhgGFSE01fVcq2B5Keuk/RDFLhfGAcDT4XO4ZyT5ouHZzVuXatkgx -OJQCsxtyvEajvXDMFQYddubBZwptM+uoFOe1G3cLYc39tRk+O/RTAcfAWN0VyBfD -/etGwf7991oIOCaNtCzHgGiOr5fjGJ+AvUU1plSVsoArxpHiRBxMG/Fvyb/uN9g+ -o1yGUF5oYqA= +aW5nIENBMSQwIgYDVQQDDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCS3PraJ5Dk0vm33qiG0Cal+S+W +PifErAFaakmgHq2rIjMIVjr9luLSRbrXwRqebuIO4AvVg8LMiwecOWbTVJqXarBP +236AHeBv566GKRGbmVHL4QpvenaIHIXP15tGJjcrneELl2vd7Hgztmx5teo5KHu0 +rCmTJAUsL4GmA7sGJEacuI2TMHKmtPOgQPJ7csdAhRiSnIkAhc8cZQioBi5/IxnT +benJ5GpS2pZ1+FJOr7V9WBtUpa20ycXde+5ciiaQJ7TZNyk0Meyz5/l4GKQ5HwqB +qomNGlIQIZa/w7OeGLaU178O+dikN2aM0mcmS22lFnS5Uy6pUxip8+A1kCZlAgMB +AAGjUzBRMB0GA1UdDgQWBBQZcmS1yjzurW/QF+Gi7OkNj6OuWjAfBgNVHSMEGDAW +gBSio+c9cv0rKRGnHryWwo097Opa/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQAXptCbI4ejahr1TC4FRwd0YaeYPsnIR3wcujtPW9/vygzGZSBB +KrKijITWY2+SW5fX4nhZeOjD7kv45s4n6FIRtE5ah9Y/bFZecojqwD+1VCAYy0JU +BW3Uvtf+9gbR5iP3Xemyowh89upO388jcI/4kkC6F1TdJh4AoFjOOWUYLkk/v89h +SQ9wjB/fmcwrgzVd7DLvh2KZtM6bXk09zYE7C1TB0sb0L+61fJVbMoFKYo/QW/tM +MmRWGqL/9eXzB882H9lyX2pykXuETpbQirPDnYz5PZYWqJ2xK3aB0lwZ4Ln8zdMY ++svQsZlwymCgT6rngOwMNMN0BCQKuPZsg2zb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -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 +HUzAD6zg6DKj2NaBf5DzROVlZSCz -----END CERTIFICATE----- diff --git a/src/test/resources/ssl/reload/node-new.key.pem b/src/test/resources/ssl/reload/node-new.key.pem index 467b5b01c1..5a9c818430 100644 --- a/src/test/resources/ssl/reload/node-new.key.pem +++ b/src/test/resources/ssl/reload/node-new.key.pem @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+PKQOneEPtQIt -4G8yeqrAhFGXUkFDID5bnAb7mk5ALX5B8bWYQa7hER6xQpP+a7CdPLDm+PLTGkGP -T0S7HpcOYli3qtED0zkk8yaCL8ztk3oyLuV97u8x4A+rOXoO2nmrG9ck8/XZN0kt -u8Q87l0EaSMsCwuRJ+A/vFeKIEijzfjhBPjn7smYUpN0LprrM+o//OHPsQEXsRHO -pjIM7KC8a+luRxAlrxotHO0lWEA05pNHya5fqkhdYQ1MgR0cb8zTxBB+DAfmHCgz -w4rf4kSd11LJbk5CITeSd98xV28TanaDli8BHfDbk3TMiASv3LJyq5UX/1yD1CG4 -1UH6vpoRAgMBAAECggEAAacCsMrPxeRnWrEonhphKc9sawFQpk3dJMwP5ncSZ23N -uzJnhqVJaNSOfPEsWmkijVcV3Ue7yjgf6igA25Q6MSqLBTtjWeJnjGndQ4O5RrYB -eXadUTD2XGtLD4xuAjuFE4aoIX7J+6NGjDJlk7bpUWy9XLhS1yWuxbbz1rQNlXik -a82FOoQiOxjMCBhgRO+zU1x3Cqz5Keb1UWekMUodXgVBx47P4ziYLV3+E0mkyz/D -2uJWawnmn0nL3RdyQd6WBEvRT7o1FzZy45zCaMFn0C9NgzUqmSpvKpp4iQU54ptq -nTQl7+O56QSrt95zEKS+7sjH3sX3rix/GagWj5Z57QKBgQD6SinskXjpd+VdrGAs -TLxu3P2t524XeOsQV9t9kBlW9jQU0tRgEu81z9UGXFPqiERpFRlyoYlvxOJNgAIJ -IOZzA5Vu66cQJZWZOapMmrzHdxO0SCgk3fUyyhe6W/3C7DPHJTFfoVJFY/ZhhZ5w -ZclIupKTszeZj7t786MDCuteLQKBgQDCk7vkLywfqFcdxOy8gQYmBo/xLH+yP7dn -RgQcvXIxF3K4eI3OwFj0Aly6Bmq4b1VUSqlaCqlDF80LLSh2qlIzFA0UOpRFBsaY -19p/lZ3BsTlbCwf2picltRaqZw19AhbErRab3WrYqoHfp4aPMDCcL6AwBvmzX/K/ -j17lBvf99QKBgQCf8TTJUE0MJOoV6kmrBX6E+gPCVdosdcEBOKOyoZsPz1WI2RGO -M4tZv+5Jmkal4V6WKD2S21eQbSiQjfS/EJ8zcF7V+xFPaDUpLYh+W4O3k4ir9FBy -/sPqKOrw1Ehdf8O2xzW9/sEsRqzztQeCnAj8yP1SFXy6TPdqRk8tapTuIQKBgFYp -j3FrRjG6nOEs29xZkjxyeXlFyEJJntCXm6iSZ6e/h2iS0dD1Mi7TgPZLcyS7AGE0 -MqwRvoRcXMsPMzThFUdTILuNeSzb5EO4iiQnP9WOwiRDzUH2r60t9Jx+x+VMcIKl -VzasJO1PC/XbPGXZ5By1pky+OgKpgVg8h7wJivWlAoGBAJ4aOb2iXoNDSchKjXEA -u4odkRpCu7+QLMR053ixLFr25zOOy92SU6F/A+PsYvl/YmjCXqv3CQ3HMUtEWN8N -fQegX9wPz8zoaz20nk6blXHaa93xNHQhTVmgfGYDMLt3xXXy1Obkpd+DoSByJfXz -soIMoVWCKJKYXtyXCDL736ld +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7h74ZvaMfJiWF +y57z3FfHxcwzqI5rxpE5M9PP2V2iiGgRBurHCd6iOePqOXtzch3t8ABh8Ew902Ky +5Lry0xhOV0whqWE4sZPGiE37jmjTabU9/ERmIxzFzpGGBT41Nsf57q0u00jtFBKs +v4U7LzzyorBMSYakP6zYUqaceqWajyjN7wBAsvXW/ijM3aXrFtc/wWWvBp0ejlY2 +PBpJfqKCJiaHtSFq8xg4cu8IEy/g1xU52ypMS9uR6cjgVSo+0FoVfcfBBNK//zPA +Mw2G0Q3x8w5l0jlssJTCeDG2DJTnDMuAVZCvQzQ1cVptqc1nL1gOwLbcLTlqsQrO +4Z9/v7jBAgMBAAECggEAVaAxaMdyB/L/BwxmU6q0Wf8yshOwk/1iqd/EQw9Y9bGa +8stZv+/9u8z7CCOe/qOIjvAa/J0f8srmMhDGW8GPQ5YQqP4R6jUK6IesM8RekMmf +e+IHySsXJCqhv7P9J4cP4ErewJawoa+cp0v7pX54McGfBfY8iBqa7VsvwBswKlWS +fH4VflFrJvAXaqJLW+VRgsLHxBQVzkrhd6xWO2A9QPpRURoyYAl/CjmN6rYutds1 +ZwIL4NNEr1lD5f4rlIBsN3OuGhYPwOkH8zYoqm6SRVFc6PEGqfvVp3us1LgcPwtF +daywuh/rm+K3S6JzfA5Cg8NC/leTLAlg7vMXge/a0QKBgQDzFql+SW6Z01Dl9zWJ +VR0L5fdhSoQloj7M9LLyAMmteVcnsklEKSKfGa+InDHL120mdvayVNFcoBv8a5rp +TaQaecv5uN2vPvBAJL2G8TW0B/XllZhpXPi852zTo8huR5GRUIaoVJ3WzngoBArX +LBeLJJZuIlZ13VvANLGMqSfFUwKBgQDFfaPemJbrdi74EyKrtZ+cz5JsFswXlKti +f0DVit4EC+0fp9gs1XDNRQQkpfNyX+fVn/ViAdH7yoCsVGf5rFJ3Uce5/35rESb3 +eNg3oj2VFNXj1x8ooZxm3fEVc/2Ut014hw0H2L2/t9DBgCgxEV0kd2kFIK6t5OXC +kywmx5xTGwKBgQDo2ednsf2A2fufHSsqLt6Q/Cr4BgIJbp3LhAY5bGnDgvzqaIxn +/yNL1bXgHQZSJTxH4SK0dizKFhBYvdZ47sdoGQ07W0r2yEool0j5DusLVajEz4Rc +QRN/GAuVu0iN4n5c/Q7QBaXgEozkf+LGdFTlExoJy1iYtH5j4dXFUG9pQwKBgEmX +QMoAqDRDjMsKLmA3xKtlOdWnRRQAZUDF1H3+Si7N1uV14PsL6gXDkwCpCidzj2su +OPz1Wq7tzbbpmPkTeoNV6QvpJc11zcRntoI8pZ/47J8DGWxFlIdMarqoxzR0fZzN +DlD/Ne3L7DE+tTtbkg61pF+xxwWrhuZTex9UQG9DAoGASr3b8Ot21zIYyr8BwtFY +k7lcSpEBTmCcXhiAZTgGO0LvdjVl+vwIuJaSH2zAPcrjFOEG0EgVP0HlUTuXq0rf +wGTn9DsqE0tY7MjuiJepaJvk0/AvaOMo4iNgGMf7e51NIQALuYVMaIeZbORxivOX +94w1NTsD3mH6yHYTX4Qm/zs= -----END PRIVATE KEY----- diff --git a/src/test/resources/ssl/reload/node-wrong.crt.pem b/src/test/resources/ssl/reload/node-wrong.crt.pem index e9b670f2f4..d87097bc87 100644 --- a/src/test/resources/ssl/reload/node-wrong.crt.pem +++ b/src/test/resources/ssl/reload/node-wrong.crt.pem @@ -1,56 +1,72 @@ -----BEGIN CERTIFICATE----- -MIIE5DCCA8ygAwIBAgIGAXjDaPfLMA0GCSqGSIb3DQEBCwUAMIGVMRMwEQYKCZIm +MIIEEjCCAvqgAwIBAgIUciADWUgJQl06xdaDRO/xF3WeSLwwDQYJKoZIhvcNAQEL +BQAwgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFt +cGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQwIgYDVQQLDBtFeGFtcGxl +IENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAiBgNVBAMMG0V4YW1wbGUgQ29tIEluYy4g +U2lnbmluZyBDQTAeFw0yMzA0MTQxMzIzMDZaFw0zMzA0MTExMzIzMDZaMFYxCzAJ +BgNVBAYTAkRFMQ0wCwYDVQQHDARUZXN0MQ0wCwYDVQQKDARUZXN0MQwwCgYDVQQL +DANTU0wxGzAZBgNVBAMMEm5vZGUtMi5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAJbhPUMpfA0UEaRZO9w2Bydn9rClz+sBueaSXfUZ +FWPpk4orTb958RG3DIxJ5LxRnMXYYxEbVHIAGrrH+s06nJU8iMjP8zki6tqTn3VI +G4DeLaCRmweG832nbd3VkRE0K3CvQoIQoYTe4uoUNtpvs1a7b0keWJfvhxeNpSGF +iZQhZg9hu+jL3MGWQVTH3QVp6rTABU7W+DZjozuG+0OlxBVnmPWu23WG7E+LhWFU +ULyjAg2LCaClLpRHRc1jXdavvVjik+RTvPkETLfhwy2HDBlSkv4Dk9SjiUlhEfpO +Y9HN2rP3yXAvBi47BDPr7hC1oUPbXD7/2x3oxgDUuV0S8N8CAwEAAaOBlzCBlDBS +BgNVHREESzBJiAUqAwQFBaAbBgNVBAOgFAwSbm9kZS0xLmV4YW1wbGUuY29tghJu +b2RlLTIuZXhhbXBsZS5jb22CCWxvY2FsaG9zdIcEfwAAATAdBgNVHQ4EFgQU0tED +HwNuDesU72iN+ZtGavIzKTQwHwYDVR0jBBgwFoAUGXJktco87q1v0BfhouzpDY+j +rlowDQYJKoZIhvcNAQELBQADggEBACavMia/iS7+gOyIXl9d8fUjtwVhCeISahZs +7C1spcwnWtum4yLUKwA7XeG+9k8KmJCxa1A9KjfQ3GiWB15Sa+XCtg3alhEqoNiT +5XiH5vAeSDG+BQrDTWb2hVC2vCiqwR1zszGyXThjYPig0DCxfr4zhAR8Zwe71zgE +Iz5Ydq77m9MGzxqNvofxXo3e85fBaEczkHShxLUid9eOJSN+TK/GxPqIhxNFEcwr +1bNunTf/9YCcQcCPw4cSVbmRjadqJdDNfFQoQGi6L1+JCKMEefpnvaxorSRs0mu/ +hO0hRg5K5Hdb++upzeMaVikl9IYuLRD6kABTyrVphKd2ksO0CBU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEBzCCAu+gAwIBAgIUf8RhLrREqQU02WxnXl87059YCKswDQYJKoZIhvcNAQEL +BQAwgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFt +cGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEwHwYDVQQLDBhFeGFtcGxl +IENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1wbGUgQ29tIEluYy4gUm9v +dCBDQTAeFw0yMzA0MTIyMTAwNDNaFw0zMzA0MDkyMTAwNDNaMIGVMRMwEQYKCZIm iZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEZMBcGA1UECgwQ RXhhbXBsZSBDb20gSW5jLjEkMCIGA1UECwwbRXhhbXBsZSBDb20gSW5jLiBTaWdu -aW5nIENBMSQwIgYDVQQDDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0EwHhcN -MjEwNDEyMDAwOTAyWhcNMjMwNDEyMDAwOTAyWjBWMQswCQYDVQQGEwJERTENMAsG -A1UEBwwEVGVzdDENMAsGA1UECgwEVGVzdDEMMAoGA1UECwwDU1NMMRswGQYDVQQD -DBJub2RlLTIuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQCdtnQNK63dqK46DDuiww+wjXISHGDM143iE4UgrpnC5DtqmljwQPCKq4Em -QyLQdjNA37LDobINOtcDr9CQwthMMJeopbSFf1Qk97E4Z8DM9PF5AuNAQBoAkFsk -eq2JSLNuCE4lw8RSFjdO+5aCv2kIvcTtP8xiG2k6M98kLYRPES9nBzfiCa1TrDyV -HVIrcdF3bGLyXxUL/Bbbk2lwl5MDQ5FsM5CDAWJUMhKc9ijbyVUqACeebCBWPweF -iLCHVksXT6B1HNl/mLPNIc0HbpCkJ+gASWZTQ7vbOidxR3eJJZs5zmNBbDuwSjYO -pn1D/rAmzwb/YiLIvwFa602ZUgVlAgMBAAGjggF2MIIBcjCBvAYDVR0jBIG0MIGx -gBTS02Hh6adcYFVpsHSBAGZYMvoGRKGBlaSBkjCBjzETMBEGCgmSJomT8ixkARkW -A2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1wbGUg -Q29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEhMB8G -A1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBggECMB0GA1UdDgQWBBT4Fkad -SpmiN20n0xcPgz0apTcDQjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIF4DAg -BgNVHSUBAf8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwUgYDVR0RBEswSYgFKgME -BQWgGwYDVQQDoBQMEm5vZGUtMi5leGFtcGxlLmNvbYISbm9kZS0yLmV4YW1wbGUu -Y29tgglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggEBABkamc5q63pY -oRKgB4HjUttPSC7iWnLSa6bticyyfF34QO5fLpuRKv99u7GGTUDXtcoQ1ZYUHkhM -6G3E2OWgwAPs9Ag/HjFmR63I1JA0fsPOjMEP9ySHdO4eyCDwjAQLCnJ3XceOVSLW -pqhIKM1696Gc4CtrvZ/5RMe+7VozQ0rm7rkviDhYvsy7LbSmXwKcvFMHohOxvnJE -IWHq/uSzE4CVnS8Go7OOciQq4QY69GNVY5U5XiM9SbscPy+Lx/ayUst/xWPwIgPV -/4gC2UpKn/KhG3Llr8C+4LzehPRC4MSbq52aC3QsGCpm+oJU5ULscl+Apwj3ByhL -YjHbo/j+hxE= +aW5nIENBMSQwIgYDVQQDDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCS3PraJ5Dk0vm33qiG0Cal+S+W +PifErAFaakmgHq2rIjMIVjr9luLSRbrXwRqebuIO4AvVg8LMiwecOWbTVJqXarBP +236AHeBv566GKRGbmVHL4QpvenaIHIXP15tGJjcrneELl2vd7Hgztmx5teo5KHu0 +rCmTJAUsL4GmA7sGJEacuI2TMHKmtPOgQPJ7csdAhRiSnIkAhc8cZQioBi5/IxnT +benJ5GpS2pZ1+FJOr7V9WBtUpa20ycXde+5ciiaQJ7TZNyk0Meyz5/l4GKQ5HwqB +qomNGlIQIZa/w7OeGLaU178O+dikN2aM0mcmS22lFnS5Uy6pUxip8+A1kCZlAgMB +AAGjUzBRMB0GA1UdDgQWBBQZcmS1yjzurW/QF+Gi7OkNj6OuWjAfBgNVHSMEGDAW +gBSio+c9cv0rKRGnHryWwo097Opa/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQAXptCbI4ejahr1TC4FRwd0YaeYPsnIR3wcujtPW9/vygzGZSBB +KrKijITWY2+SW5fX4nhZeOjD7kv45s4n6FIRtE5ah9Y/bFZecojqwD+1VCAYy0JU +BW3Uvtf+9gbR5iP3Xemyowh89upO388jcI/4kkC6F1TdJh4AoFjOOWUYLkk/v89h +SQ9wjB/fmcwrgzVd7DLvh2KZtM6bXk09zYE7C1TB0sb0L+61fJVbMoFKYo/QW/tM +MmRWGqL/9eXzB882H9lyX2pykXuETpbQirPDnYz5PZYWqJ2xK3aB0lwZ4Ln8zdMY ++svQsZlwymCgT6rngOwMNMN0BCQKuPZsg2zb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -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 +HUzAD6zg6DKj2NaBf5DzROVlZSCz -----END CERTIFICATE----- diff --git a/src/test/resources/ssl/reload/node-wrong.key.pem b/src/test/resources/ssl/reload/node-wrong.key.pem index 3cabf06abf..b8fa1875b5 100644 --- a/src/test/resources/ssl/reload/node-wrong.key.pem +++ b/src/test/resources/ssl/reload/node-wrong.key.pem @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCdtnQNK63dqK46 -DDuiww+wjXISHGDM143iE4UgrpnC5DtqmljwQPCKq4EmQyLQdjNA37LDobINOtcD -r9CQwthMMJeopbSFf1Qk97E4Z8DM9PF5AuNAQBoAkFskeq2JSLNuCE4lw8RSFjdO -+5aCv2kIvcTtP8xiG2k6M98kLYRPES9nBzfiCa1TrDyVHVIrcdF3bGLyXxUL/Bbb -k2lwl5MDQ5FsM5CDAWJUMhKc9ijbyVUqACeebCBWPweFiLCHVksXT6B1HNl/mLPN -Ic0HbpCkJ+gASWZTQ7vbOidxR3eJJZs5zmNBbDuwSjYOpn1D/rAmzwb/YiLIvwFa -602ZUgVlAgMBAAECggEAJ4yR9J2P96ZtrnPT3qCAxjrqMJ16LtQdKeTQPR5bw7I9 -LiHvjKwURgn1FJXAXLtPZgTSzNk3D7dCJRQJPswFtrF2zp1jNBj2jmCoyebGw/7m -sPxm5X1Np/eLS44SB3u6Ny0Q/8pkaFtW2lEf8MC0Q7Nm90HI7I9IJ4bLfcSGSdc2 -H4i4m0bM5XEiRvhiaD7V/wE9MFwCCt+Lwv8gN0ii2fI7b8EY1YfVpmbj9fp+8fOP -yHMuWeiHxbrjGDwFCZwDBD4IyJzuKfX8eHnIjZei6lAiE9kz45lqUbOnYPdidt5O -VfkkHjTMBU4mgthUnyHm2anyi2Ud9WeE2sksVSGn3wKBgQDJS77gC241MSpduscj -ZVBLomhuabu+UORZAFuW6DtW4VdJ3r8Cf8Mh6MWqZAFFsBgdNGfjtgdPP92PPCrV -cXBinVYT13afaE8iyUTXlLscFq5aBieOBoT4saZxcEPkIvVZgPxxyWdkQNIRe5LV -k5G2Lq8qxy86OnC0o7NA7FgECwKBgQDIkprQM6RuXz3Tqr8WfMZuvd9Gs2jNT//k -ItfBfCxxTaNzfNeHj9KmmdmcmiZebqRdKjDoQlpOqEG6CQAv6HOSMQrk03Tp5QCk -1GFo0ilfek58ZhOMoT7eZ5zedJ1OX6RXTqvLNNI0e6Pa0Usx/3CJOtIKyhUmnz8F -vAIouaASTwKBgQCxqGFpOY1l8uOSX9N7wOIyLr9+m2DwolI23uL2+DXPAwjYEHiC -iyI8XkV+kc6xo65UsDj0t2YSIqq3zQF86ianUndzAZoXLKeTaxGQNxtAuh/dIkts -xQI8wAXHXq78vYHPIdEr1/ahe7grZ+X7C8fxg5hj5/IdsRBhzYzaQv2XawKBgGvx -Kkv+XvHfY+C0NZ6ejBQxLyZXi4FjGm3mqoLAlxJrHBodB8k3B8ENb2WuOBP+K4rQ -F/4HJ57JQoYiLe2ahggZSKmZe4Qc8FnEyp+k6wstQWwFa2P1q2X6ERxPWhFBu6oY -9q+nv7DrEWXD2VoRBLl15HBWDUf5z+sAIZFVROZVAoGAXC4p6KMwzCgrlk5Egnl0 -Bd7lcENmjf7LLGhMMCb0LkEgD69tS+mSg1rnlRUgI5N633TriDPcSClpfly+rFnB -ZH/nklLLSfz7lPrbvmSdljrUJrbCtpEs9r6ios9CqkFm7OFnQA+evmSXkitNuUrn -aRMW20eKmflRMwbpysV27ds= +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCW4T1DKXwNFBGk +WTvcNgcnZ/awpc/rAbnmkl31GRVj6ZOKK02/efERtwyMSeS8UZzF2GMRG1RyABq6 +x/rNOpyVPIjIz/M5Iurak591SBuA3i2gkZsHhvN9p23d1ZERNCtwr0KCEKGE3uLq +FDbab7NWu29JHliX74cXjaUhhYmUIWYPYbvoy9zBlkFUx90Faeq0wAVO1vg2Y6M7 +hvtDpcQVZ5j1rtt1huxPi4VhVFC8owINiwmgpS6UR0XNY13Wr71Y4pPkU7z5BEy3 +4cMthwwZUpL+A5PUo4lJYRH6TmPRzdqz98lwLwYuOwQz6+4QtaFD21w+/9sd6MYA +1LldEvDfAgMBAAECggEAAgAolMxnBbFfboN0ZL4eqCobvknkkOQr99+2+ToE65c8 +Spe6ZzCRvr9jnjSYoNqgLoto/OAU5ZIUyKdALxp42w27bpY7TmWlIZLViXOUUcgg +aMGlgZsLfX4L2eYsD0NW1B6uzhS0X5OpBJuSAqF6ikrf9eM+H32gl/Jb3y7rHRiz +DlBrD78zQjduzHiIR1+dkX8j490AQTPPgMGwZ3E1wZjTNCQswk3nq1kx6VNUmSfA +yKVQJivmSguSb3YLlpFjMb62r6zuWU+rpnrY3Gnia4pf4YIXjZLtEiwCW6sayinT +fNFt4L6E/QlcnNwlHlzAHqYxIDgCYqT7CY5psYw9qQKBgQDQCBYGlSKxjBezgvns +XdbnJV/ufqn1sXUxB1Oxt1JVfD+MNuUAV2YCHjR/2pDv+2YoJ/PxWwAc3G1Yl9eU +X1Ey6RTJXZ9EmVVRXkPH2cScUlukaTmBn/xuvV8LqCy01LV78VGmF0gZeIiUWL6I +GvpDMNNpbnA6gCLXOFmn3hRy8wKBgQC5q4nBpqiT9fQXbBKnVDxrz/oL6YrzI/3a +BxI+53fnJJ8fm+pKVQWGi9HKKQMIO/qWBfd8lcJkg7/caF5nxp8gWEOALKw25zCd +CVd5VeWKwSIc3dsjr1s0JcLTc5QlCncJbwJvTQBWmVAljcVp70oaM1gkxjXkxNiV +8/KZUHfNZQKBgDbvC7HtS94Kmm+i1JBgL1GWgwCdng/tLn8l6inxuOIuDzHdhRdT +/PHuO/rPIprcjhtogXhoiV0VsCJG5nydtvl0pzKNcHNS8j6sX8W0ccC91slRqAfc +0XIEu8Z+QF/4E3yJOwBbAYUIWTijPpz+UrvPduROb4BjOdAPZ012zXuVAoGAVnZK +bVKl2FlF9Q5P1XpFtNMiFyAHo9hT4489cOuri4kjTL33qevT6eb8qA7XKaN8uxZG +PM8kulgcJZC4vczh11ci//JNtDePDOIHySo1/ZqYvyaVYRXM/AjFpGCDUYiBDHSU +hq4uBSXaC9LsZruXH4JffqiK+mCsl5AFnl25nH0CgYB3X5VEMgyIx/fooCHOsLAf +Mnsp7vDnk0U8Vpc8r2XvSl3XwSWCdQtikVkc9gm/i4QZVntBofv9SieVbVCn11bG +8bQC56Q3OZTWDMtEzrCYBH3QGgnMzJIGYg8O9BVJdaeLQ/710vDofwPS3WsItTTV +Xw9ZoalN0xV6jf6DfUAWmg== -----END PRIVATE KEY----- diff --git a/src/test/resources/ssl/reload/node.crt.pem b/src/test/resources/ssl/reload/node.crt.pem index 975321099f..8896288ff7 100644 --- a/src/test/resources/ssl/reload/node.crt.pem +++ b/src/test/resources/ssl/reload/node.crt.pem @@ -1,80 +1,72 @@ -----BEGIN CERTIFICATE----- -MIIE5DCCA8ygAwIBAgIGAXjDZzwdMA0GCSqGSIb3DQEBCwUAMIGVMRMwEQYKCZIm -iZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEZMBcGA1UECgwQ -RXhhbXBsZSBDb20gSW5jLjEkMCIGA1UECwwbRXhhbXBsZSBDb20gSW5jLiBTaWdu -aW5nIENBMSQwIgYDVQQDDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0EwHhcN -MjEwNDEyMDAwNzA4WhcNMjMwNDEyMDAwNzA4WjBWMQswCQYDVQQGEwJERTENMAsG -A1UEBwwEVGVzdDENMAsGA1UECgwEVGVzdDEMMAoGA1UECwwDU1NMMRswGQYDVQQD -DBJub2RlLTEuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQCtbAX3oYQvfgvwQ587eEvnvVC1z8Dd63DRQiJ4d0jWgePj3a5NXo01Ok+a -5CqEZBAXqO3L7sd5xWHjO6Dg29RD8zvMmcHHQgtW+mOS1mPdeM1/yWg2MvxxmHqK -UI5BOxJRK4KVc4jyYvnp/Bns9AEvGKb/Ko79YZOOjs0sx2iNxKIPkvOTtRE8/ta3 -H1G3+e8NdDN5suuaXV36BHA857sqg8kxBxXPwMF36Dh0L6tCUB8oxLSPqAgY6eQN -hC6cprZl8rQlechTrOswOAVTpS0thav5ZFrX6I1MD57O6EosAaE6C3D4pY/FsXyO -hxOuAvo+H8K4O5ddAyQ8MeEvnsMFAgMBAAGjggF2MIIBcjCBvAYDVR0jBIG0MIGx -gBTS02Hh6adcYFVpsHSBAGZYMvoGRKGBlaSBkjCBjzETMBEGCgmSJomT8ixkARkW -A2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1wbGUg -Q29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEhMB8G -A1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBggECMB0GA1UdDgQWBBQlLRJJ -7EdLiEJVwbNM15af7SW3FzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIF4DAg -BgNVHSUBAf8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwUgYDVR0RBEswSYgFKgME -BQWgGwYDVQQDoBQMEm5vZGUtMS5leGFtcGxlLmNvbYISbm9kZS0xLmV4YW1wbGUu -Y29tgglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggEBABGqJNfowZpb -r9CifL/GJ5jwZZPAmacg29dz14TOwcv1NY6lD/TDMkN7OXoJQ2iktFJUMCzWlKef -5aYxom2DV5hsSAsPnoTCzXStMbyJAx+DJihhU8HJaQBemZvXBdp9CECJ8PSBm3Uh -k1RYFvJo0VP37sLO9G1mEjhdDo1uWD0XzUkRTlrJ9oW0+T19UdAOCGDgwlJAma8l -yjuHGHTT3XMjQJxUfqSLzeb/E7dmE0zyLp3B5OHu1tm2HJDi72eNNl3CDWN/Kr2o -8soT6flpSIpRKVl3c+wV1aGxCCPsBV4RWe7hrN0/P6/UNdAlbZbZk7XeNvha2b9I -gYHPuTdfjHI= +MIIEEjCCAvqgAwIBAgIUZs7ImPhUL2uB+n01yxn3arZYgtQwDQYJKoZIhvcNAQEL +BQAwgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFt +cGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQwIgYDVQQLDBtFeGFtcGxl +IENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAiBgNVBAMMG0V4YW1wbGUgQ29tIEluYy4g +U2lnbmluZyBDQTAeFw0yMzA0MTQxMzIyNTNaFw0zMzA0MTExMzIyNTNaMFYxCzAJ +BgNVBAYTAkRFMQ0wCwYDVQQHDARUZXN0MQ0wCwYDVQQKDARUZXN0MQwwCgYDVQQL +DANTU0wxGzAZBgNVBAMMEm5vZGUtMS5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBANkMv71J5KlVPv5M2jCibgpLSHHyQvvPbYNcwpkt +Yz+/UwpYySTWkn1mMAfVJuh/kAADSE0RlcEJGIuccrAMVw9g6Nq4Usm/z/wSI5Ew +52SlHEQxSMt9WcFSMQHutxAoeXpCLL0OvFCqGdzQWinDqPKJluH8m98y7VjcwLz4 +FX5p5Dn8dt38OqGhJrTrew6xRjhwtbr+LugbCVUqc5pY7na0SpA6INwXAuga2ZDa +TwJTlVJE30xSfeJtnuDLsw83Y4RHe4XiBd7yDT/IH3yoQmZshBlI2Iojjt73etbP +97e3crlhzyO9EVF0kSp2knqhKci++f8MRKo4HksHY/7cVV0CAwEAAaOBlzCBlDBS +BgNVHREESzBJiAUqAwQFBaAbBgNVBAOgFAwSbm9kZS0xLmV4YW1wbGUuY29tghJu +b2RlLTEuZXhhbXBsZS5jb22CCWxvY2FsaG9zdIcEfwAAATAdBgNVHQ4EFgQUGSHF +6V65gO9+v7PeH/zTkU+fvckwHwYDVR0jBBgwFoAUGXJktco87q1v0BfhouzpDY+j +rlowDQYJKoZIhvcNAQELBQADggEBAAxBs2+e5ALpgrgECmsU9eI7safjJnbo5Zj/ +H8cUaYQkQr+m+ORl63NG+oqvBVqAXT3H2ycXo4bpUZhIZHFWek9CqlAA+//B1n+D +HJ7sQ5760nK26zIoZ4qDE5tVYOJdC6e/+Y39WqqpLHWIPrJpBxzI68My572+g9tM +CL3w1dDTo3P1xYcKiLdJ+eZtLwOxpREQohlUCtd8GMl+lZNIbL93aTPhBzCOqfGc +rq1D1FKL7VNwa5l9F54htJe3x9y865zWhu3xk4q+BE3q7l2yMPDXcu9PCbjg6+ms +YFAMc4avejAa2qaWAN7JqyKbYAq/0OPFSnwyE7hV3sRPewcEuS8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIEqTCCA5GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk -ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w -bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh -MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTIxMDQxMjAwMDUx -M1oXDTMxMDQxMDAwMDUxM1owgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ -kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQw -IgYDVQQLDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAiBgNVBAMMG0V4 -YW1wbGUgQ29tIEluYy4gU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAJjVJ9Ipq0uCE7EE0RRBadkrIm7J8OGa2xeFCEpsw+hqQbmftrm0 -V5XFpRKznv7r9JxFQn4uUM/Tqxt/mZ9Qql6IGWiNeK4e0Hfh+Lc/VD+w+mDqxo52 -zv0afYyyM/1NiOyKV7hO0Akwj25zAfnqs2FbsZzVXtRpgOnfOdfKpUL6fKAxwjex -+0nOOaS5D+unS64sh0mTMVD32iag+tg6aiiW914Jmrkd4yDV3uoXh/FKafRRWHSq -pwO7Xilb+fLRMiQ1N09mTE8Um12G7mVdBaZpbluwtv2tiS52n8zzpKYbohS2m1ir -lJMASh6qEKzHUlzmERhq4Ib7V+p0E+gPadMCAwEAAaOCAQYwggECMBIGA1UdEwEB -/wQIMAYBAf8CAQAwgbwGA1UdIwSBtDCBsYAUrs3v6ngKiRF/4eiBW+3eCSjTVo+h -gZWkgZIwgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdl -eGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEwHwYDVQQLDBhFeGFt -cGxlIENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1wbGUgQ29tIEluYy4g -Um9vdCBDQYIBATAdBgNVHQ4EFgQU0tNh4emnXGBVabB0gQBmWDL6BkQwDgYDVR0P -AQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IBAQAmRbuLhYdGYjdndROJilIQ4DUD -HYYijortmkq6ZNQiB7I2teBZjra2xcKp0qaOkG9nJCzhHvGTw/URjWAxFZ5n5hhx -iBTJZTGY6bk2SWfJxdd3Zld6ybsoaQTO/ZnfuTE0SgxWx1e5q/mRBKvRwF02bJu3 -YNlJMJVuIDxurrUK2CXrgG/BOCYMyiHNmn1Spsh+x+6B9u28CE0M52+HtNJwyQw6 -qPMSNiovXRkqk7E40e7ZY3MS85Pr4L0Us048SswPEpf/+IjV/zTcDP22pQfcjMOX -DZpdAOGgvqhL9t7M1lcxJrI0cIcBNWOPVa3zsCDU7CXF+riL0Va6TvoChVtT +MIIEBzCCAu+gAwIBAgIUf8RhLrREqQU02WxnXl87059YCKswDQYJKoZIhvcNAQEL +BQAwgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFt +cGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEwHwYDVQQLDBhFeGFtcGxl +IENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1wbGUgQ29tIEluYy4gUm9v +dCBDQTAeFw0yMzA0MTIyMTAwNDNaFw0zMzA0MDkyMTAwNDNaMIGVMRMwEQYKCZIm +iZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEZMBcGA1UECgwQ +RXhhbXBsZSBDb20gSW5jLjEkMCIGA1UECwwbRXhhbXBsZSBDb20gSW5jLiBTaWdu +aW5nIENBMSQwIgYDVQQDDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCS3PraJ5Dk0vm33qiG0Cal+S+W +PifErAFaakmgHq2rIjMIVjr9luLSRbrXwRqebuIO4AvVg8LMiwecOWbTVJqXarBP +236AHeBv566GKRGbmVHL4QpvenaIHIXP15tGJjcrneELl2vd7Hgztmx5teo5KHu0 +rCmTJAUsL4GmA7sGJEacuI2TMHKmtPOgQPJ7csdAhRiSnIkAhc8cZQioBi5/IxnT +benJ5GpS2pZ1+FJOr7V9WBtUpa20ycXde+5ciiaQJ7TZNyk0Meyz5/l4GKQ5HwqB +qomNGlIQIZa/w7OeGLaU178O+dikN2aM0mcmS22lFnS5Uy6pUxip8+A1kCZlAgMB +AAGjUzBRMB0GA1UdDgQWBBQZcmS1yjzurW/QF+Gi7OkNj6OuWjAfBgNVHSMEGDAW +gBSio+c9cv0rKRGnHryWwo097Opa/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQAXptCbI4ejahr1TC4FRwd0YaeYPsnIR3wcujtPW9/vygzGZSBB +KrKijITWY2+SW5fX4nhZeOjD7kv45s4n6FIRtE5ah9Y/bFZecojqwD+1VCAYy0JU +BW3Uvtf+9gbR5iP3Xemyowh89upO388jcI/4kkC6F1TdJh4AoFjOOWUYLkk/v89h +SQ9wjB/fmcwrgzVd7DLvh2KZtM6bXk09zYE7C1TB0sb0L+61fJVbMoFKYo/QW/tM +MmRWGqL/9eXzB882H9lyX2pykXuETpbQirPDnYz5PZYWqJ2xK3aB0lwZ4Ln8zdMY ++svQsZlwymCgT6rngOwMNMN0BCQKuPZsg2zb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk -ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w -bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh -MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTIxMDQxMjAwMDUx -MloXDTMxMDQxMDAwMDUxMlowgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ -kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEw -HwYDVQQLDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1w -bGUgQ29tIEluYy4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBALebO2NTc/jFQwmnye/uWHP4YKkgnC1wL1ZxSsQlL6MPaFRJPKjbQyA4llOW -xnemfkyTDW8BjYOVVrnqXHR5yMAg1A2+bTmgzmSePhA549nA575UI+5XsgZAKl3E -EmEhHZ36g3fZRtXEyQ2Y7d4ZhxBrkH51SY5tor0QkPf44R1JYUCLjTcnFeaJhosp -XaMxnLBYGWzQlNx1VL4serRax/sbFC6Ue//bcp97t/RYpaS3L06pv7z4RmTqFeYD -RenZWqp8YNJ4NH1ff9ogLXtVr2voyAcw0Hrb7war/dPPWsG6etL975yKOvy3poAu -Gntp+bkE4yU4ThZDtyV5+PBbmmcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAf -BgNVHSMEGDAWgBSuze/qeAqJEX/h6IFb7d4JKNNWjzAdBgNVHQ4EFgQUrs3v6ngK -iRF/4eiBW+3eCSjTVo8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB -AQB8bZ91ofGDXW/6JuhWtLa+U3c2THrn6qa3cU5iXZo6Lco6rDLUs3jkhqpaHenA -joIBNtvI6IrZx12ARw3F48XG+TvsU7hroG6fPRBdhMpAvLN3JxshgI0ZoUQHrrOb -Jrk6JAacfrVc8KCPryISFx7jh32rkwbBo2CqLV0cRBnl146CSjq8H3tzMfFmku8b -uU+mFLt9hpqlU3yUTk3kS83NY7HimKSdtodMJRtBlh44KRr7Vt1zWTJ78l37epzs -1ZDRpPmNfZRFgQo/2b7DCLGkqHKB7RRNRt/MvTyE5bpr1atZvyFV1O8pM+Xknf6g -KgaBJN+uGgJhlZKPdLi1ROue +MIIEATCCAumgAwIBAgIUO5pwerTrIJkibcZoY8ZxK8KCDT4wDQYJKoZIhvcNAQEL +BQAwgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFt +cGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEwHwYDVQQLDBhFeGFtcGxl +IENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1wbGUgQ29tIEluYy4gUm9v +dCBDQTAeFw0yMzA0MTIyMTAwNDNaFw0zMzA0MDkyMTAwNDNaMIGPMRMwEQYKCZIm +iZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEZMBcGA1UECgwQ +RXhhbXBsZSBDb20gSW5jLjEhMB8GA1UECwwYRXhhbXBsZSBDb20gSW5jLiBSb290 +IENBMSEwHwYDVQQDDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgTyzX2ZRIvkAzJysKYCVialXIZkvYyRxu +rtqYawm60gvUKOqEmhDIc2p/ySLnvxcrUx5q20pFoSS6+9rtT3D5wapArOf2v6g8 ++c2f5l2GhiMhxg6rRkvuCUWpSC9rubg4X1rkhaK8pZiLtC9qKLi3ZIG9rNubALZn +XuDD3nQ03pEKG3iy+hUVF7c876J9iFlqJU5RZCTfGKNaRYAnCtm/wWiHVYwAV1Gf +awjLjBfrFwcrJTWJyLxqg8z2DuXWm5Lsb+D8+9rqYZF71BvqS4ej5QLPrGXEeds1 +MX38RRJPYN2SdlMDMomjxRZyDSubZV40mLe+4znmFcGuMhouyDSvAgMBAAGjUzBR +MB0GA1UdDgQWBBSio+c9cv0rKRGnHryWwo097Opa/jAfBgNVHSMEGDAWgBSio+c9 +cv0rKRGnHryWwo097Opa/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA +A4IBAQCdEXxctLUFE0IoO1HDfE6LtNs2+I488P3Cp+hbHvKhHJeeY/48r0Gi57hQ +sR+Bfut3RjmdmKw9RcYylTgtXXmWQ3E6HqXaaZSnaG1TCER3bboxU7HG2IbaZiGu +/25K92rtq9FY0YNhCGYodq3cEzYWhX0pj3yj4N4193aBXrAaxyAALNnQ2Kwi6bw4 +WtS780NIgNFsGeU6H2/0JwDYlZVdhyR0G9uMWJ78fFHKI9iPUw4LvG07coxoZmsU +2tjIuV77HGGH7qufQJQtEFo/aOBEbLZ4i1uef6nYasnsI6tV6jhFhcLvgj7KeJDK +HUzAD6zg6DKj2NaBf5DzROVlZSCz -----END CERTIFICATE----- diff --git a/src/test/resources/ssl/reload/node.key.pem b/src/test/resources/ssl/reload/node.key.pem index dc06639b50..4d256fa4cd 100644 --- a/src/test/resources/ssl/reload/node.key.pem +++ b/src/test/resources/ssl/reload/node.key.pem @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCtbAX3oYQvfgvw -Q587eEvnvVC1z8Dd63DRQiJ4d0jWgePj3a5NXo01Ok+a5CqEZBAXqO3L7sd5xWHj -O6Dg29RD8zvMmcHHQgtW+mOS1mPdeM1/yWg2MvxxmHqKUI5BOxJRK4KVc4jyYvnp -/Bns9AEvGKb/Ko79YZOOjs0sx2iNxKIPkvOTtRE8/ta3H1G3+e8NdDN5suuaXV36 -BHA857sqg8kxBxXPwMF36Dh0L6tCUB8oxLSPqAgY6eQNhC6cprZl8rQlechTrOsw -OAVTpS0thav5ZFrX6I1MD57O6EosAaE6C3D4pY/FsXyOhxOuAvo+H8K4O5ddAyQ8 -MeEvnsMFAgMBAAECggEADvlYk47t7bbdu4dvOJCUx0P0s9omLlM9uMfT16B/GMx6 -26pAulv7Z9jq1jY0yJ0mOZDDxZvOvAAzyU3VAI1iqOJX67zr+zND7OTuU5ew5Ebh -wZKnraRd4UYX8Jjvi4jY9krCOfrRnJI4v4Ad0fSopIMlqjsnwQ+bkM/aPe9S4wiu -j2bXKPPcpGfQ3z6I2nQjP/Go8G1TziG2OwRvcQfNrt1gzzg9OwR0hRv5hSwaC28u -39raDRe7/p9PbuqAI2z2/gbNRP+eKmoz7KZzThJCv4/RS3osXMt9DFeDZikdJ0Pp -RCGi4Op02wm1PI3A8piG9uUHrJ2Dl9lpLlDOEk3SMQKBgQDsf+oG93E2RQg7UHjs -EIYsfPQpNMT1/b8JDtld6kkfGLoBGZti/Vv6wcgMZaex18c6OyMykD55qkyVdkZ4 -wr4jRqYDG6sq+AqTX/Q+3tSDUZQBbDuBGxYJJpiYVcYGw3iUFfsrb3H59D9GeAfw -Y/l4lEsTdQTAnaQ7iRX1ZDS69QKBgQC7uKbIrUYxNLjah7xYYHXSDisyyewPZndA -OPBlx7kCNorsrLWccHD9PrRZSi95xVIJ2nkUP69bdBYD5rI75lJ2PLQP51QHxYA9 -VRUxEuy+LgdGT0AiM6DiUgXy+nNrnt2DK1Q1uOoJLfg+d86/kK4V8KGSbVABW7I9 -NVrPL9b90QKBgFE+uDTgeIH+QQ+vW3stSgqqem5VdHxVSXVhJoc+3xPRuMR7+YeO -JjUEsSahHXTY/dYhTrwmFXBScrC9ywPdUthngsx6itjeETQDuLKIdlUOh1vdxKtb -lLxcB/v9K2RTbm7hBkIrrOoDYGFjBscscR1dRFVQ0+sfvLW/KE3+uKapAoGBAI0A -M3aEgDaxjS/HyLbxLU5sChKKDN+8bVI18ovgqpx473y6dWdeJeByWvC+gk6K4gY4 -rb2B4GtnFKo1fCb153acPfu8HCgCN0LaR6KmvmBTHm+3U0rdULjuNz281Tk/CM9f -mk8H5/KhLtdtEkRdngUoy5O6u99pSsYi72S0YF4hAoGBAJDegbpbtJEe1MDVAlhF -zFf8/kj3Hd7qd5gDqG6kV2eCSXBeoq3jQajlOeSfykHm9jkGYPnmzfKKTNtOwiQ7 -lTY68VEEhSreUKeys6sfVR0S0xM8w0ty6G3HQdFSBqTHDdUSj74SwKJLUvqM9iUe -oTej+xnI8sKAJDPUv4EiAO7k +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDZDL+9SeSpVT7+ +TNowom4KS0hx8kL7z22DXMKZLWM/v1MKWMkk1pJ9ZjAH1Sbof5AAA0hNEZXBCRiL +nHKwDFcPYOjauFLJv8/8EiORMOdkpRxEMUjLfVnBUjEB7rcQKHl6Qiy9DrxQqhnc +0Fopw6jyiZbh/JvfMu1Y3MC8+BV+aeQ5/Hbd/DqhoSa063sOsUY4cLW6/i7oGwlV +KnOaWO52tEqQOiDcFwLoGtmQ2k8CU5VSRN9MUn3ibZ7gy7MPN2OER3uF4gXe8g0/ +yB98qEJmbIQZSNiKI47e93rWz/e3t3K5Yc8jvRFRdJEqdpJ6oSnIvvn/DESqOB5L +B2P+3FVdAgMBAAECggEADTPDp0LgYBW/ACmH4rTD7BJfigwfW5Zmuzp1h8BarMek +HcQAGs0xGeQ7qwOhxeXvH2ETu8RZueUmE2U6a0+aLWWf+aCD60ukiK5IcDjA9RPp +9T0+Mp/MSYBeBMJoFi6FZ79bXfXl1Hjpm88nPNUZk1nKeLKB1KtnWSQMVoeMic97 +D3wzS/RmcQGIEM5FHuYslTSR7kSqZg83+9ExRHMrvspE+EuoxhkVhBN8UM81a90g +komq1XPURTaqKjXD4/Zy2cstLe9Y//6C9NK0ZxYOpYgwm8glVxmlmAE/4fROBDZR +VZxzQ6A/Drd/r48YOhlroSdKhZ0JLrJv+368Z90bgQKBgQDi1jaz+u7x2BzCbDBd +kCuqdjpfLPBV8EppV6TkLU7DqWTBCDWPxqGgXfVtWrxK3pXWU1iyvNuMZVQsJyu7 +P8lf74RMogMI501WSK6FJ1+lPqlWmVHA3PIEbAdLyWZiygxBOY0Laqt/BAEWMtOX +WDAwUP6aZgciAUSTOZxgQNS5oQKBgQD09GuyZNvaTb8l3NIcSNu9EGvz3Cu7H6fS +SxDpNMxVMHbrTRwRC7/Gmsdm10C+enHq8YG3m/HgiDEvXfIIsjApSKOnNXBMqcFW +nVfRJarjAnYgdxNtQ+VaemBW62gruaakOKAnyxTd9JQZb4xjts+Q0UdGxblIsex0 +9aENCXnaPQKBgHswCF8vzGoMinnPlWiKbhxRvpuHZTHWoCKbVVIRhO/fY3ctRSFC +pu3XePydRRqHzOmrM8VFqRmSweaEk0xKdMsj4T5Y0bsZGjfcmuJ3Iosz/3SnKO3L +T6e1HzU6N984iPU3EvD7Sg1dmFV83soXO3xR0CL7e64s8BfgNptTOfNhAoGAPhra +U1iPBUJA/HCINPOkAsNvG1zvGXplKkQt/XKNe+vVusLKIug/rzL+62wX1jNlPpQM +t2iqYqslDUVcYCgNXeo00+gQmN9RTYyG/1f1g6jUGlcWbdWRCOeOFXuJ5cwkG+7f +bDdpCv0/r1NA3Oc0qRrmX2MyHuQ9d0nvk0abxmECgYABaDswOc7P6HKIdogr/V9/ +d32XKQlp/PME0FZKvNzy67vYrImKQWfaEj6ikXu8NurrNt8zSn8Y5Ijnrjav/jhe +Rq4oH3dRfE3d/yFq0F4DleKdhbDIshp9u68K2+PdAGu9ufbSyBfNftQlkzym0SZI +4aG1P5Bird3jKn9vPxmVew== -----END PRIVATE KEY----- diff --git a/src/test/resources/ssl/reload/root-ca.pem b/src/test/resources/ssl/reload/root-ca.pem index 063b12f65d..1f58a36a9e 100644 --- a/src/test/resources/ssl/reload/root-ca.pem +++ b/src/test/resources/ssl/reload/root-ca.pem @@ -1,24 +1,24 @@ -----BEGIN CERTIFICATE----- -MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk -ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w -bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh -MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTIxMDQxMjAwMDUx -MloXDTMxMDQxMDAwMDUxMlowgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ -kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEw -HwYDVQQLDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1w -bGUgQ29tIEluYy4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBALebO2NTc/jFQwmnye/uWHP4YKkgnC1wL1ZxSsQlL6MPaFRJPKjbQyA4llOW -xnemfkyTDW8BjYOVVrnqXHR5yMAg1A2+bTmgzmSePhA549nA575UI+5XsgZAKl3E -EmEhHZ36g3fZRtXEyQ2Y7d4ZhxBrkH51SY5tor0QkPf44R1JYUCLjTcnFeaJhosp -XaMxnLBYGWzQlNx1VL4serRax/sbFC6Ue//bcp97t/RYpaS3L06pv7z4RmTqFeYD -RenZWqp8YNJ4NH1ff9ogLXtVr2voyAcw0Hrb7war/dPPWsG6etL975yKOvy3poAu -Gntp+bkE4yU4ThZDtyV5+PBbmmcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAf -BgNVHSMEGDAWgBSuze/qeAqJEX/h6IFb7d4JKNNWjzAdBgNVHQ4EFgQUrs3v6ngK -iRF/4eiBW+3eCSjTVo8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB -AQB8bZ91ofGDXW/6JuhWtLa+U3c2THrn6qa3cU5iXZo6Lco6rDLUs3jkhqpaHenA -joIBNtvI6IrZx12ARw3F48XG+TvsU7hroG6fPRBdhMpAvLN3JxshgI0ZoUQHrrOb -Jrk6JAacfrVc8KCPryISFx7jh32rkwbBo2CqLV0cRBnl146CSjq8H3tzMfFmku8b -uU+mFLt9hpqlU3yUTk3kS83NY7HimKSdtodMJRtBlh44KRr7Vt1zWTJ78l37epzs -1ZDRpPmNfZRFgQo/2b7DCLGkqHKB7RRNRt/MvTyE5bpr1atZvyFV1O8pM+Xknf6g -KgaBJN+uGgJhlZKPdLi1ROue +MIIEATCCAumgAwIBAgIUO5pwerTrIJkibcZoY8ZxK8KCDT4wDQYJKoZIhvcNAQEL +BQAwgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFt +cGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEwHwYDVQQLDBhFeGFtcGxl +IENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1wbGUgQ29tIEluYy4gUm9v +dCBDQTAeFw0yMzA0MTIyMTAwNDNaFw0zMzA0MDkyMTAwNDNaMIGPMRMwEQYKCZIm +iZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEZMBcGA1UECgwQ +RXhhbXBsZSBDb20gSW5jLjEhMB8GA1UECwwYRXhhbXBsZSBDb20gSW5jLiBSb290 +IENBMSEwHwYDVQQDDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgTyzX2ZRIvkAzJysKYCVialXIZkvYyRxu +rtqYawm60gvUKOqEmhDIc2p/ySLnvxcrUx5q20pFoSS6+9rtT3D5wapArOf2v6g8 ++c2f5l2GhiMhxg6rRkvuCUWpSC9rubg4X1rkhaK8pZiLtC9qKLi3ZIG9rNubALZn +XuDD3nQ03pEKG3iy+hUVF7c876J9iFlqJU5RZCTfGKNaRYAnCtm/wWiHVYwAV1Gf +awjLjBfrFwcrJTWJyLxqg8z2DuXWm5Lsb+D8+9rqYZF71BvqS4ej5QLPrGXEeds1 +MX38RRJPYN2SdlMDMomjxRZyDSubZV40mLe+4znmFcGuMhouyDSvAgMBAAGjUzBR +MB0GA1UdDgQWBBSio+c9cv0rKRGnHryWwo097Opa/jAfBgNVHSMEGDAWgBSio+c9 +cv0rKRGnHryWwo097Opa/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA +A4IBAQCdEXxctLUFE0IoO1HDfE6LtNs2+I488P3Cp+hbHvKhHJeeY/48r0Gi57hQ +sR+Bfut3RjmdmKw9RcYylTgtXXmWQ3E6HqXaaZSnaG1TCER3bboxU7HG2IbaZiGu +/25K92rtq9FY0YNhCGYodq3cEzYWhX0pj3yj4N4193aBXrAaxyAALNnQ2Kwi6bw4 +WtS780NIgNFsGeU6H2/0JwDYlZVdhyR0G9uMWJ78fFHKI9iPUw4LvG07coxoZmsU +2tjIuV77HGGH7qufQJQtEFo/aOBEbLZ4i1uef6nYasnsI6tV6jhFhcLvgj7KeJDK +HUzAD6zg6DKj2NaBf5DzROVlZSCz -----END CERTIFICATE----- diff --git a/src/test/resources/ssl/reload/spock-keystore.jks b/src/test/resources/ssl/reload/spock-keystore.jks index e0a0855ce8a239a55bc7871d1c66b065baf29c41..52f27df4af6651c478cbb9bf47d51a91bc5082c5 100644 GIT binary patch literal 5302 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 nuZ%pT)SEwc;L;35obL;0TjnJQzXy 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 JIG8BNzW{JGZe0KX diff --git a/src/test/resources/ssl/reload/truststore.jks b/src/test/resources/ssl/reload/truststore.jks index 2928417daadc2604e54f1c43d834242d3438bc75..c750f9807aa22339c19d05e510990a57ceef4758 100644 GIT binary patch literal 1398 zcmV-+1&R7Ff(3E{0Ru3C1snzmDuzgg_YDCD0ic2f4FrM(2{3{M1u%jI0R{;whDe6@ z4FLxRpn?SQFoFc`0s#Opf&}LV2`Yw2hW8Bt2LUi<1_>&LNQU+thDZTr0|Wso1Q4`ciP@X6dj$*4Gp|%+mqUPp1aJVBZ45;CRpdiEMy8ut;a?1? zvZJ^gI826MxBEfH1AZ2jXeBUz9J{^*G+(rt~3KPTFaf%h#^J}_IcL`GsdSEm( z3LqB2_Kg)nuh=J!i+aHKaV;(z3K?f<#F}EJp@f=Am+tpJ` zh8=z2Us$nHpwQ%g7>zu*HbU_zspJ|K6Grpsj3}c=pbJ8GXhugda6pwmX+^%yH(H;P zEx#ae_nT6iteH|!qP(-g3b;0PIVidgGdFRJ=MnhC&SmBa;DqpVHP4x}30bDu%Urtl z`R2~uH7fCmKWmShH@qcMNG~GFvdzjgelvsYh)kK%%jj6pLx2O?=epf3){%i&BVfrq zjfTnpIh!F2(OvD@1&U8upq0Vx?}w?qh=${%OUjNB{qwIG=fYC7vQCeOSKg|YBDT^r zlShfFf$eZpR$Lo%Z@rK49}N{_$5D^X*ID5TG$Eep9HIN*K=1~?XnJfQldpTW)a@10Oqghu~aW>{y^apM7 z#lak6)jZ=7OR-KYh%e|qcW9p}6qF?5O%x(XbWQEzQ=pYA5eN2|7oWGgV5@Rfg^1|I z941ktx{@mpSj_tqOhk)mdHjP R>M;BsknAySs>aDsO_j(J{OE=mXZYF<#g`|7Wd zV}1@Uoptd(sLU%!>Ja%Dm^rgxZmXPj4qm_p=fC}7s;{??PX(k%9YpYSGAYgyel5=) zxnW(zZa#~jxFIn7)h150{p+gR<4fM1ta?K42VI3$_)lkIH1>Vitduu=o;V71SM^bK z557wGkDZ6BX@bUa_C2rs2FiSj!gt_0AoP=2!>1%8z$>aU(a%2x+mUE~0DHMzP?wx( z9;=((CImfxMDT+{C*hauz4fii;NYu*hOIyXTJQ8)_&q2M~ zcq{fThEDBQ@Jm6!Os52Vyz?zL8bEs9sJk#tFflL<1_@w>NC9O71OfpC00bakRL2M& z%MK;OJd)R%RX*;j)E6fEb8Q||=|UoL+M)<<|_X#+Q`PXYob E5Xppi#Q*>R literal 1338 zcmV-A1;zR>f(14L0Ru3C1n&k3Duzgg_YDCD0ic2e-~@sM+%SR!*f4?w)CLJEhDe6@ z4FLxRpn?R&FoFcZ0s#Opf&{t-2`Yw2hW8Bt2LUiC1_~;MNQU!X{ux{aM$F0j5^vmT5pcHFgVGH~K zhK$)9^5%9&rj;$09cRk5UGZ=RWs=&88aIXrNV;Q2jvw-E7-{G!@yT$>q>Z+e&~R=A zC;eT+UIuPHFXO;f%V3lT?eN5ebAG!4HB1*dK|7Z&GmBKFd7u63EQlO@v<(!0m7urD zQF$6RFv8i`!M)0FCuHXeMVM>6*(r6gVPpI}W05*4h?*t`tTS8~y=miIbSPm%x5MfM19qhw>`+a_C5%TrFs4oraId8WjUQ(GJXLcH``{mq#+kEFxD`XpOj0(&n& zp7=gh>(mhHX2UXGk8{3(GfvrprG~sH#%2pGEmn9XET>sETX4!|rhh$907Lx}wtE#; zm+vyynw@hQuF|hs_2)a(6JeZJ+*x^6f1|_easv#)e`7hRCs*56eUp6N2aFb6HPWoFEYH#_f$8pF?AVfgzzn!-{Vycy`2XoinBD zfq+wRRfbdYSk@LHC~;baUZA@x6RJZS4B7Z=2P-e3uM);jv1nP%x)N_8>0%3DJlGsv z6(MV%$#O`?0#%6fM=-j9%UZ`|0T-q{i9;teq``1Od!Nf`$9J_a!o1cJ28^Z)qG=aR zrdFb7)mE1CJ2*L!i3G{WE^l3c^(p_U_Jd+ z%+24(QB6%W>~$_Aiu_D{X-{te|0DcD45Q7W{;6D87nrQufYJYuZ63imE2c;J!%0jN zgJswFq`lSoDQXgJ9i5I-_}WX;jfP4!M+-a^izf!&{_tdP??Rj~OrehQL^G9{=(h^Y z51hxr6Np7BZrUMYmVATos@C@OhAgR{)vAGW8ge7R^)Nm#AutIB1uG5%0vZJX1Qb08 w$Vj}&z0Odz%~+~-Msht%(GUa_ Date: Mon, 17 Apr 2023 14:07:34 -0400 Subject: [PATCH 12/16] Fix NPE and add additional graceful error handling (#2687) * Fix NPE and add additional graceful error handling Signed-off-by: Craig Perkins * Add new lines at end of file Signed-off-by: Craig Perkins * Run spotlessApply Signed-off-by: Craig Perkins * Remove unused import Signed-off-by: Craig Perkins * volatile to final Signed-off-by: Craig Perkins --------- Signed-off-by: Craig Perkins --- .../security/OpenSearchSecurityPlugin.java | 14 +- .../GuardedSearchOperationWrapper.java | 85 ++++++++++ .../GuardedSearchOperationWrapperTest.java | 146 ++++++++++++++++++ 3 files changed, 239 insertions(+), 6 deletions(-) create mode 100644 src/main/java/org/opensearch/security/support/GuardedSearchOperationWrapper.java create mode 100644 src/test/java/org/opensearch/security/support/GuardedSearchOperationWrapperTest.java diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index ffd7f730ed..362a46843e 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -45,6 +45,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; @@ -98,7 +99,6 @@ import org.opensearch.index.Index; import org.opensearch.index.IndexModule; import org.opensearch.index.cache.query.QueryCache; -import org.opensearch.index.shard.SearchOperationListener; import org.opensearch.indices.IndicesService; import org.opensearch.indices.SystemIndexDescriptor; import org.opensearch.indices.breaker.CircuitBreakerService; @@ -165,6 +165,7 @@ import org.opensearch.security.ssl.transport.SecuritySSLNettyTransport; import org.opensearch.security.ssl.util.SSLConfigConstants; import org.opensearch.security.support.ConfigConstants; +import org.opensearch.security.support.GuardedSearchOperationWrapper; import org.opensearch.security.support.HeaderHelper; import org.opensearch.security.support.ModuleInfo; import org.opensearch.security.support.ReflectionHelper; @@ -215,7 +216,7 @@ public final class OpenSearchSecurityPlugin extends OpenSearchSecuritySSLPlugin private final List demoCertHashes = new ArrayList(3); private volatile SecurityFilter sf; private volatile IndexResolverReplacer irr; - private volatile NamedXContentRegistry namedXContentRegistry = null; + private final AtomicReference namedXContentRegistry = new AtomicReference<>(NamedXContentRegistry.EMPTY);; private volatile DlsFlsRequestValve dlsFlsValve = null; private volatile Salt salt; private volatile OpensearchDynamicSetting transportPassiveAuthSetting; @@ -569,11 +570,11 @@ public Weight doCache(Weight weight, QueryCachingPolicy policy) { } }); - indexModule.addSearchOperationListener(new SearchOperationListener() { + indexModule.addSearchOperationListener(new GuardedSearchOperationWrapper() { @Override public void onPreQueryPhase(SearchContext context) { - dlsFlsValve.handleSearchContext(context, threadPool, namedXContentRegistry); + dlsFlsValve.handleSearchContext(context, threadPool, namedXContentRegistry.get()); } @Override @@ -643,7 +644,7 @@ public void onQueryPhase(SearchContext searchContext, long tookInNanos) { } } } - }); + }.toListener()); } } @@ -798,6 +799,7 @@ public Collection createComponents(Client localClient, ClusterService cl final PrivilegesInterceptor privilegesInterceptor; + namedXContentRegistry.set(xContentRegistry); if (SSLConfig.isSslOnlyMode()) { dlsFlsValve = new DlsFlsRequestValve.NoopDlsFlsRequestValve(); auditLog = new NullAuditLog(); @@ -822,7 +824,7 @@ public Collection createComponents(Client localClient, ClusterService cl // DLS-FLS is enabled if not client and not disabled and not SSL only. final boolean dlsFlsEnabled = !SSLConfig.isSslOnlyMode(); evaluator = new PrivilegesEvaluator(clusterService, threadPool, cr, resolver, auditLog, - settings, privilegesInterceptor, cih, irr, dlsFlsEnabled, namedXContentRegistry); + settings, privilegesInterceptor, cih, irr, dlsFlsEnabled, namedXContentRegistry.get()); sf = new SecurityFilter(settings, evaluator, adminDns, dlsFlsValve, auditLog, threadPool, cs, compatConfig, irr, xffResolver); diff --git a/src/main/java/org/opensearch/security/support/GuardedSearchOperationWrapper.java b/src/main/java/org/opensearch/security/support/GuardedSearchOperationWrapper.java new file mode 100644 index 0000000000..76d316de2d --- /dev/null +++ b/src/main/java/org/opensearch/security/support/GuardedSearchOperationWrapper.java @@ -0,0 +1,85 @@ +/* + * 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.security.support; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import org.opensearch.index.shard.SearchOperationListener; +import org.opensearch.search.internal.ReaderContext; +import org.opensearch.search.internal.SearchContext; +import org.opensearch.transport.TransportRequest; + +/** + * Guarded version of Search Operation Listener to ensure critical request paths succeed + */ +public interface GuardedSearchOperationWrapper { + + static final Logger log = LogManager.getLogger(GuardedSearchOperationWrapper.class); + + void onPreQueryPhase(final SearchContext context); + + void onNewReaderContext(final ReaderContext readerContext); + + void onNewScrollContext(final ReaderContext readerContext); + + void validateReaderContext(final ReaderContext readerContext, final TransportRequest transportRequest); + + void onQueryPhase(final SearchContext searchContext, final long tookInNanos); + + default SearchOperationListener toListener() { + return new InnerSearchOperationListener(this); + } + + static class InnerSearchOperationListener implements SearchOperationListener { + + private GuardedSearchOperationWrapper that; + InnerSearchOperationListener(GuardedSearchOperationWrapper that) { + this.that = that; + } + + @Override + public void onPreQueryPhase(final SearchContext searchContext) { + try { + that.onPreQueryPhase(searchContext); + } catch (final Exception e) { + searchContext.setTask(null); + log.error("Cancelled request due to internal error", e); + } + } + + @Override + public void onNewReaderContext(final ReaderContext readerContext) { + that.onNewReaderContext(readerContext); + } + + @Override + public void onNewScrollContext(final ReaderContext readerContext) { + that.onNewScrollContext(readerContext); + } + + @Override + public void validateReaderContext(final ReaderContext readerContext, final TransportRequest transportRequest) { + that.validateReaderContext(readerContext, transportRequest); + } + + @Override + public void onQueryPhase(final SearchContext searchContext, final long tookInNanos) { + try { + that.onQueryPhase(searchContext, tookInNanos); + } catch (final Exception e) { + searchContext.setTask(null); + log.error("Cancelled request due to internal error", e); + } + } + } +} diff --git a/src/test/java/org/opensearch/security/support/GuardedSearchOperationWrapperTest.java b/src/test/java/org/opensearch/security/support/GuardedSearchOperationWrapperTest.java new file mode 100644 index 0000000000..982d1108ad --- /dev/null +++ b/src/test/java/org/opensearch/security/support/GuardedSearchOperationWrapperTest.java @@ -0,0 +1,146 @@ +/* + * 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.security.support; + +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.Test; + +import org.opensearch.index.shard.SearchOperationListener; +import org.opensearch.search.internal.ReaderContext; +import org.opensearch.search.internal.SearchContext; +import org.opensearch.transport.TransportRequest; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + + +public class GuardedSearchOperationWrapperTest { + + @Test + public void onNewReaderContextCanThrowException() { + final String expectedExceptionText = "abcd1234"; + + DefaultingGuardedSearchOperationWrapper testWrapper = new DefaultingGuardedSearchOperationWrapper() { + @Override + public void onNewReaderContext(ReaderContext readerContext) { + throw new RuntimeException(expectedExceptionText); + } + }; + + final RuntimeException expectedException = assertThrows(RuntimeException.class, testWrapper::exerciseAllMethods); + + assertThat(expectedException.getMessage(), equalTo(expectedExceptionText)); + } + + @Test + public void onNewScrollContextCanThrowException() { + final String expectedExceptionText = "qwerty978"; + + DefaultingGuardedSearchOperationWrapper testWrapper = new DefaultingGuardedSearchOperationWrapper() { + @Override + public void onNewScrollContext(ReaderContext readerContext) { + throw new RuntimeException(expectedExceptionText); + } + }; + + final RuntimeException expectedException = assertThrows(RuntimeException.class, testWrapper::exerciseAllMethods); + + assertThat(expectedException.getMessage(), equalTo(expectedExceptionText)); + } + + @Test + public void validateReaderContextCanThrowException() { + final String expectedExceptionText = "validationException"; + + DefaultingGuardedSearchOperationWrapper testWrapper = new DefaultingGuardedSearchOperationWrapper() { + @Override + public void validateReaderContext(ReaderContext readerContext, TransportRequest transportRequest) { + throw new RuntimeException(expectedExceptionText); + } + }; + + final RuntimeException expectedException = assertThrows(RuntimeException.class, testWrapper::exerciseAllMethods); + + assertThat(expectedException.getMessage(), equalTo(expectedExceptionText)); + } + + @Test + public void onPreQueryPhaseCannotThrow() { + AtomicReference calledSearchContext = new AtomicReference<>(); + DefaultingGuardedSearchOperationWrapper testWrapper = new DefaultingGuardedSearchOperationWrapper() { + @Override + public void onPreQueryPhase(SearchContext context) { + calledSearchContext.set(context); + throw new RuntimeException("EXCEPTIONAL!"); + } + }; + + testWrapper.exerciseAllMethods(); + + assertThat(calledSearchContext.get(), notNullValue()); + verify(calledSearchContext.get()).setTask(null); + } + + @Test + public void onQueryPhaseCannotThrow() { + AtomicReference calledSearchContext = new AtomicReference<>(); + DefaultingGuardedSearchOperationWrapper testWrapper = new DefaultingGuardedSearchOperationWrapper() { + @Override + public void onQueryPhase(SearchContext context, long tookInNanos) { + calledSearchContext.set(context); + throw new RuntimeException("EXCEPTIONAL!"); + } + }; + + testWrapper.exerciseAllMethods(); + + assertThat(calledSearchContext.get(), notNullValue()); + verify(calledSearchContext.get()).setTask(null); + } + + /** Only use to make testing easier */ + private static class DefaultingGuardedSearchOperationWrapper implements GuardedSearchOperationWrapper { + + @Override + public void onNewReaderContext(ReaderContext readerContext) { + } + + @Override + public void onNewScrollContext(ReaderContext readerContext) { + } + + @Override + public void onPreQueryPhase(SearchContext context) { + } + + @Override + public void onQueryPhase(SearchContext searchContext, long tookInNanos) { + } + + @Override + public void validateReaderContext(ReaderContext readerContext, TransportRequest transportRequest) { + } + + void exerciseAllMethods(){ + final SearchOperationListener sol = this.toListener(); + sol.onNewReaderContext(mock(ReaderContext.class)); + sol.onNewScrollContext(mock(ReaderContext.class)); + sol.onPreQueryPhase(mock(SearchContext.class)); + sol.onQueryPhase(mock(SearchContext.class), 12345L); + sol.validateReaderContext(mock(ReaderContext.class), mock(TransportRequest.class)); + } + } +} From d168c1a319944ca3266fdd4e2263f6228c5b9c25 Mon Sep 17 00:00:00 2001 From: Ryan Liang <109499885+RyanL1997@users.noreply.github.com> Date: Mon, 17 Apr 2023 18:50:55 -0700 Subject: [PATCH 13/16] Add release notes for 2.7.0 (#2690) * Add release notes for 2.7.0 Signed-off-by: Ryan Liang --- ...ensearch-security.release-notes-2.6.0.0.md | 1 + ...ensearch-security.release-notes-2.7.0.0.md | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 release-notes/opensearch-security.release-notes-2.7.0.0.md diff --git a/release-notes/opensearch-security.release-notes-2.6.0.0.md b/release-notes/opensearch-security.release-notes-2.6.0.0.md index 748454a95d..a1932db5f3 100644 --- a/release-notes/opensearch-security.release-notes-2.6.0.0.md +++ b/release-notes/opensearch-security.release-notes-2.6.0.0.md @@ -7,6 +7,7 @@ Compatible with OpenSearch 2.6.0 * Add actions cluster:admin/component_template/* to cluster_manage_index_templates ([#2409](https://github.com/opensearch-project/security/pull/2409)) * Publish snapshots to maven ([#2438](https://github.com/opensearch-project/security/pull/2438)) * Integrate k-NN functionality with security plugin ([#2274](https://github.com/opensearch-project/security/pull/2274)) +* Flatten response times ([#2471](https://github.com/opensearch-project/security/pull/2471)) ### Maintenance diff --git a/release-notes/opensearch-security.release-notes-2.7.0.0.md b/release-notes/opensearch-security.release-notes-2.7.0.0.md new file mode 100644 index 0000000000..8d2b8e4f7c --- /dev/null +++ b/release-notes/opensearch-security.release-notes-2.7.0.0.md @@ -0,0 +1,43 @@ +## 2023-04-25 Version 2.7.0.0 + +Compatible with OpenSearch 2.7.0 + +### Features + +* Dynamic tenancy configurations ([#2607](https://github.com/opensearch-project/security/pull/2607)) + +### Bug Fixes + +* Support multitenancy for the anonymous user ([#2459](https://github.com/opensearch-project/security/pull/2459)) +* Fix error message when system index is blocked ([#2525](https://github.com/opensearch-project/security/pull/2525)) +* Fix of OpenSSLTest is not using the OpenSSL Provider ([#2301](https://github.com/opensearch-project/security/pull/2301)) +* Add chmod 0600 to install_demo_configuration bash script ([#2550](https://github.com/opensearch-project/security/pull/2550)) +* Fix SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder" ([#2564](https://github.com/opensearch-project/security/pull/2564)) +* Fix lost privileges during auto initializing of the index ([#2498](https://github.com/opensearch-project/security/pull/2498)) +* Fix NPE and add additional graceful error handling ([#2687](https://github.com/opensearch-project/security/pull/2687)) + +### Enhancements + +* Clock skew tolerance for oidc token validation ([#2482](https://github.com/opensearch-project/security/pull/2482)) +* Adding index template permissions to kibana_server role ([#2503](https://github.com/opensearch-project/security/pull/2503)) +* Add a test in order to catch incorrect handling of index parsing during Snapshot Restoration ([#2384](https://github.com/opensearch-project/security/pull/2384)) +* Expand Dls Tests for easier verification of functionality ([#2634](https://github.com/opensearch-project/security/pull/2634)) +* New system index[.ql-datasources] for ppl/sql datasource configurations ([#2650](https://github.com/opensearch-project/security/pull/2650)) +* Allows for configuration of LDAP referral following ([#2135](https://github.com/opensearch-project/security/pull/2135)) + +### Maintenance + +* Update kafka client to 3.4.0 ([#2484](https://github.com/opensearch-project/security/pull/2484)) +* Update to gradle 8.0.2 ([#2520](https://github.com/opensearch-project/security/pull/2520)) +* XContent Refactor ([#2598](https://github.com/opensearch-project/security/pull/2598)) +* Update json-smart to 2.4.10 and update spring-core to 5.3.26 ([#2630](https://github.com/opensearch-project/security/pull/2630)) +* Update certs for SecuritySSLReloadCertsActionTests ([#2679](https://github.com/opensearch-project/security/pull/2679)) + +### Infrastructure + +* Add auto github release workflow ([#2450](https://github.com/opensearch-project/security/pull/2450)) +* Use correct format for push trigger ([#2474](https://github.com/opensearch-project/security/pull/2474)) + +### Documentation + +* Fix the format of the codeowners file ([#2469](https://github.com/opensearch-project/security/pull/2469)) From 24e08bd1b1b764734338ca9e9d25af46d1e58642 Mon Sep 17 00:00:00 2001 From: Stephen Crawford <65832608+scrawfor99@users.noreply.github.com> Date: Fri, 21 Apr 2023 13:10:13 -0400 Subject: [PATCH 14/16] Security User Refactor (#2594) --------- Signed-off-by: Stephen Crawford Signed-off-by: Stephen Crawford <65832608+scrawfor99@users.noreply.github.com> --- .../security/OpenSearchSecurityPlugin.java | 12 +- .../dlic/rest/api/InternalUsersApiAction.java | 76 +++----- .../dlic/rest/api/SecurityRestApiActions.java | 4 +- .../opensearch/security/user/UserService.java | 181 ++++++++++++++++++ .../security/user/UserServiceException.java | 20 ++ .../TransportUserInjectorIntegTest.java | 6 +- .../integration/TestAuditlogImpl.java | 6 +- .../security/dlic/rest/api/UserApiTest.java | 65 ++++++- 8 files changed, 306 insertions(+), 64 deletions(-) create mode 100644 src/main/java/org/opensearch/security/user/UserService.java create mode 100644 src/main/java/org/opensearch/security/user/UserServiceException.java diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index 362a46843e..87ca878fc6 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -176,6 +176,7 @@ import org.opensearch.security.transport.InterClusterRequestEvaluator; import org.opensearch.security.transport.SecurityInterceptor; import org.opensearch.security.user.User; +import org.opensearch.security.user.UserService; import org.opensearch.tasks.Task; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.RemoteClusterService; @@ -204,6 +205,7 @@ public final class OpenSearchSecurityPlugin extends OpenSearchSecuritySSLPlugin private volatile SecurityRestFilter securityRestHandler; private volatile SecurityInterceptor si; private volatile PrivilegesEvaluator evaluator; + private volatile UserService userService; private volatile ThreadPool threadPool; private volatile ConfigurationRepository cr; private volatile AdminDNs adminDns; @@ -487,6 +489,7 @@ public List getRestHandlers(Settings settings, RestController restC evaluator, threadPool, Objects.requireNonNull(auditLog), sks, + Objects.requireNonNull(userService), sslCertReloadEnabled) ); log.debug("Added {} rest handler(s)", handlers.size()); @@ -813,9 +816,11 @@ public Collection createComponents(Client localClient, ClusterService cl sslExceptionHandler = new AuditLogSslExceptionHandler(auditLog); adminDns = new AdminDNs(settings); - + cr = ConfigurationRepository.create(settings, this.configPath, threadPool, localClient, clusterService, auditLog); + userService = new UserService(cs, cr, settings, localClient); + final XFFResolver xffResolver = new XFFResolver(threadPool); backendRegistry = new BackendRegistry(settings, adminDns, xffResolver, auditLog, threadPool); @@ -872,6 +877,7 @@ public Collection createComponents(Client localClient, ClusterService cl components.add(evaluator); components.add(si); components.add(dcf); + components.add(userService); return components; @@ -1179,7 +1185,6 @@ public static class GuiceHolder implements LifecycleComponent { private static RepositoriesService repositoriesService; private static RemoteClusterService remoteClusterService; private static IndicesService indicesService; - private static PitService pitService; @Inject @@ -1204,7 +1209,8 @@ public static IndicesService getIndicesService() { } public static PitService getPitService() { return pitService; } - + + @Override public void close() { } diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index 646e1f81d6..0551c108a1 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -14,7 +14,6 @@ import java.io.IOException; import java.nio.file.Path; import java.util.List; -import java.util.stream.Collectors; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -32,18 +31,18 @@ import org.opensearch.rest.RestController; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; -import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.configuration.AdminDNs; import org.opensearch.security.configuration.ConfigurationRepository; import org.opensearch.security.dlic.rest.validation.AbstractConfigurationValidator; import org.opensearch.security.dlic.rest.validation.InternalUsersValidator; import org.opensearch.security.privileges.PrivilegesEvaluator; -import org.opensearch.security.securityconf.Hashed; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.support.SecurityJsonNode; +import org.opensearch.security.user.UserService; +import org.opensearch.security.user.UserServiceException; import org.opensearch.threadpool.ThreadPool; import static org.opensearch.security.dlic.rest.support.Utils.addRoutesPrefix; @@ -69,13 +68,16 @@ public class InternalUsersApiAction extends PatchableResourceApiAction { new Route(Method.PATCH, "/internalusers/{name}") )); + UserService userService; + @Inject public InternalUsersApiAction(final Settings settings, final Path configPath, final RestController controller, final Client client, final AdminDNs adminDNs, final ConfigurationRepository cl, final ClusterService cs, final PrincipalExtractor principalExtractor, final PrivilegesEvaluator evaluator, - ThreadPool threadPool, AuditLog auditLog) { + ThreadPool threadPool, UserService userService, AuditLog auditLog) { super(settings, configPath, controller, client, adminDNs, cl, cs, principalExtractor, evaluator, threadPool, auditLog); + this.userService = userService; } @Override @@ -100,22 +102,7 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C final String username = request.param("name"); - if (username == null || username.length() == 0) { - badRequestResponse(channel, "No " + getResourceName() + " specified."); - return; - } - - final List foundRestrictedContents = RESTRICTED_FROM_USERNAME.stream().filter(username::contains).collect(Collectors.toList()); - if (!foundRestrictedContents.isEmpty()) { - final String restrictedContents = foundRestrictedContents.stream().map(s -> "'" + s + "'").collect(Collectors.joining(",")); - badRequestResponse(channel, "Username has restricted characters " + restrictedContents + " that are not permitted."); - return; - } - - // TODO it might be sensible to consolidate this with the overridden method in - // order to minimize duplicated logic - - final SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName(), false); + SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName(), false); if (!isWriteable(channel, internalUsersConfiguration, username)) { return; @@ -128,50 +115,35 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C final List securityRoles = securityJsonNode.get("opendistro_security_roles").asList(); if (securityRoles != null) { for (final String role: securityRoles) { - if (!isValidRolesMapping(channel, role)) return; + if (!isValidRolesMapping(channel, role)) { + return; + } } } - // if password is set, it takes precedence over hash - final String plainTextPassword = securityJsonNode.get("password").asString(); - final String origHash = securityJsonNode.get("hash").asString(); - if (plainTextPassword != null && plainTextPassword.length() > 0) { - contentAsNode.remove("password"); - contentAsNode.put("hash", hash(plainTextPassword.toCharArray())); - } else if (origHash != null && origHash.length() > 0) { - contentAsNode.remove("password"); - } else if (plainTextPassword != null && plainTextPassword.isEmpty() && origHash == null) { - contentAsNode.remove("password"); - } - final boolean userExisted = internalUsersConfiguration.exists(username); // when updating an existing user password hash can be blank, which means no // changes - // sanity checks, hash is mandatory for newly created users - if (!userExisted && securityJsonNode.get("hash").asString() == null) { - badRequestResponse(channel, "Please specify either 'hash' or 'password' when creating a new internal user."); + try { + if (request.hasParam("owner")) { + ((ObjectNode) content).put("owner", request.param("owner")); + } + if (request.hasParam("isEnabled")) { + ((ObjectNode) content).put("isEnabled", request.param("isEnabled")); + } + ((ObjectNode) content).put("name", username); + internalUsersConfiguration = userService.createOrUpdateAccount((ObjectNode) content); + } + catch (UserServiceException ex) { + badRequestResponse(channel, ex.getMessage()); return; } - - // for existing users, hash is optional - if (userExisted && securityJsonNode.get("hash").asString() == null) { - // sanity check, this should usually not happen - final String hash = ((Hashed) internalUsersConfiguration.getCEntry(username)).getHash(); - if (hash == null || hash.length() == 0) { - internalErrorResponse(channel, - "Existing user " + username + " has no password, and no new password or hash was specified."); - return; - } - contentAsNode.put("hash", hash); + catch (IOException ex) { + throw new IOException(ex); } - internalUsersConfiguration.remove(username); - - // checks complete, create or update the user - internalUsersConfiguration.putCObject(username, DefaultObjectMapper.readTree(contentAsNode, internalUsersConfiguration.getImplementingClass())); - saveAndUpdateConfigs(this.securityIndexName,client, CType.INTERNALUSERS, internalUsersConfiguration, new OnSucessActionListener(channel) { @Override diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/SecurityRestApiActions.java b/src/main/java/org/opensearch/security/dlic/rest/api/SecurityRestApiActions.java index 9655ba67ea..e73d28e865 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/SecurityRestApiActions.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/SecurityRestApiActions.java @@ -28,6 +28,7 @@ import org.opensearch.security.privileges.PrivilegesEvaluator; import org.opensearch.security.ssl.SecurityKeyStore; import org.opensearch.security.ssl.transport.PrincipalExtractor; +import org.opensearch.security.user.UserService; import org.opensearch.threadpool.ThreadPool; public class SecurityRestApiActions { @@ -44,9 +45,10 @@ public static Collection getHandler(final Settings settings, final ThreadPool threadPool, final AuditLog auditLog, final SecurityKeyStore securityKeyStore, + final UserService userService, final boolean certificatesReloadEnabled) { final List handlers = new ArrayList(16); - handlers.add(new InternalUsersApiAction(settings, configPath, controller, client, adminDns, cr, cs, principalExtractor, evaluator, threadPool, auditLog)); + handlers.add(new InternalUsersApiAction(settings, configPath, controller, client, adminDns, cr, cs, principalExtractor, evaluator, threadPool, userService, auditLog)); handlers.add(new RolesMappingApiAction(settings, configPath, controller, client, adminDns, cr, cs, principalExtractor, evaluator, threadPool, auditLog)); handlers.add(new RolesApiAction(settings, configPath, controller, client, adminDns, cr, cs, principalExtractor, evaluator, threadPool, auditLog)); handlers.add(new ActionGroupsApiAction(settings, configPath, controller, client, adminDns, cr, cs, principalExtractor, evaluator, threadPool, auditLog)); diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java new file mode 100644 index 0000000000..c6eea8ef4c --- /dev/null +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -0,0 +1,181 @@ +/* + * 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.security.user; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableList; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import org.opensearch.client.Client; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.inject.Inject; +import org.opensearch.common.settings.Settings; +import org.opensearch.security.DefaultObjectMapper; +import org.opensearch.security.configuration.ConfigurationRepository; +import org.opensearch.security.securityconf.DynamicConfigFactory; +import org.opensearch.security.securityconf.Hashed; +import org.opensearch.security.securityconf.impl.CType; +import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.security.support.ConfigConstants; +import org.opensearch.security.support.SecurityJsonNode; + +import static org.opensearch.security.dlic.rest.support.Utils.hash; + +/** + * This class handles user registration and operations on behalf of the Security Plugin. + */ +public class UserService { + + protected final Logger log = LogManager.getLogger(this.getClass()); + ClusterService clusterService; + static ConfigurationRepository configurationRepository; + String securityIndex; + Client client; + final static String NO_PASSWORD_OR_HASH_MESSAGE = "Please specify either 'hash' or 'password' when creating a new internal user."; + final static String RESTRICTED_CHARACTER_USE_MESSAGE = "A restricted character(s) was detected in the account name. Please remove: "; + + final static String SERVICE_ACCOUNT_PASSWORD_MESSAGE = "A password cannot be provided for a service account. Failed to register service account: "; + + final static String SERVICE_ACCOUNT_HASH_MESSAGE = "A password hash cannot be provided for service account. Failed to register service account: "; + + final static String NO_ACCOUNT_NAME_MESSAGE = "No account name was specified in the request."; + private static CType getConfigName() { + return CType.INTERNALUSERS; + } + + static final List RESTRICTED_FROM_USERNAME = ImmutableList.of( + ":" // Not allowed in basic auth, see https://stackoverflow.com/a/33391003/533057 + ); + + @Inject + public UserService( + ClusterService clusterService, + ConfigurationRepository configurationRepository, + Settings settings, + Client client + ) { + this.clusterService = clusterService; + this.configurationRepository = configurationRepository; + this.securityIndex = settings.get(ConfigConstants.SECURITY_CONFIG_INDEX_NAME, + ConfigConstants.OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX); + this.client = client; + } + + /** + * Load data for a given CType + * @param config CType whose data is to be loaded in-memory + * @return configuration loaded with given CType data + */ + protected static final SecurityDynamicConfiguration load(final CType config, boolean logComplianceEvent) { + SecurityDynamicConfiguration loaded = configurationRepository.getConfigurationsFromIndex(Collections.singleton(config), logComplianceEvent).get(config).deepClone(); + return DynamicConfigFactory.addStatics(loaded); + } + + /** + * This function will handle the creation or update of a user account. + * + * @param contentAsNode An object node of different account configurations. + * @return InternalUserConfiguration with the new/updated user + * @throws UserServiceException + * @throws IOException + */ + public SecurityDynamicConfiguration createOrUpdateAccount(ObjectNode contentAsNode) throws IOException { + + + SecurityJsonNode securityJsonNode = new SecurityJsonNode(contentAsNode); + + final SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName(), false); + String accountName = securityJsonNode.get("name").asString(); + + if (accountName == null || accountName.length() == 0) { // Fail if field is present but empty + throw new UserServiceException(NO_ACCOUNT_NAME_MESSAGE); + } + + if (!securityJsonNode.get("attributes").get("owner").isNull() && !securityJsonNode.get("attributes").get("owner").equals(accountName)) { // If this is a service account + verifyServiceAccount(securityJsonNode, accountName); + String password = generatePassword(); + contentAsNode.put("hash", hash(password.toCharArray())); + } + + securityJsonNode = new SecurityJsonNode(contentAsNode); + final List foundRestrictedContents = RESTRICTED_FROM_USERNAME.stream().filter(accountName::contains).collect(Collectors.toList()); + if (!foundRestrictedContents.isEmpty()) { + final String restrictedContents = foundRestrictedContents.stream().map(s -> "'" + s + "'").collect(Collectors.joining(",")); + throw new UserServiceException(RESTRICTED_CHARACTER_USE_MESSAGE + restrictedContents); + } + + // if password is set, it takes precedence over hash + final String plainTextPassword = securityJsonNode.get("password").asString(); + final String origHash = securityJsonNode.get("hash").asString(); + if (plainTextPassword != null && plainTextPassword.length() > 0) { + contentAsNode.remove("password"); + contentAsNode.put("hash", hash(plainTextPassword.toCharArray())); + } else if (origHash != null && origHash.length() > 0) { + contentAsNode.remove("password"); + } else if (plainTextPassword != null && plainTextPassword.isEmpty() && origHash == null) { + contentAsNode.remove("password"); + } + + final boolean userExisted = internalUsersConfiguration.exists(accountName); + + // sanity checks, hash is mandatory for newly created users + if (!userExisted && securityJsonNode.get("hash").asString() == null) { + throw new UserServiceException(NO_PASSWORD_OR_HASH_MESSAGE); + } + + // for existing users, hash is optional + if (userExisted && securityJsonNode.get("hash").asString() == null) { + // sanity check, this should usually not happen + final String hash = ((Hashed) internalUsersConfiguration.getCEntry(accountName)).getHash(); + if (hash == null || hash.length() == 0) { + throw new UserServiceException("Existing user " + accountName + " has no password, and no new password or hash was specified."); + } + contentAsNode.put("hash", hash); + } + + internalUsersConfiguration.remove(accountName); + contentAsNode.remove("name"); + + internalUsersConfiguration.putCObject(accountName, DefaultObjectMapper.readTree(contentAsNode, internalUsersConfiguration.getImplementingClass())); + return internalUsersConfiguration; + } + + private void verifyServiceAccount(SecurityJsonNode securityJsonNode, String accountName) { + + final String plainTextPassword = securityJsonNode.get("password").asString(); + final String origHash = securityJsonNode.get("hash").asString(); + + if (plainTextPassword != null && plainTextPassword.length() > 0) { + throw new UserServiceException(SERVICE_ACCOUNT_PASSWORD_MESSAGE + accountName); + } + + if (origHash != null && origHash.length() > 0) { + throw new UserServiceException(SERVICE_ACCOUNT_HASH_MESSAGE + accountName); + } + } + + /** + * This will be swapped in for a real solution once one is decided on. + * + * @return A password for a service account. + */ + private String generatePassword() { + String generatedPassword = "superSecurePassword"; + return generatedPassword; + } +} diff --git a/src/main/java/org/opensearch/security/user/UserServiceException.java b/src/main/java/org/opensearch/security/user/UserServiceException.java new file mode 100644 index 0000000000..b8e6843751 --- /dev/null +++ b/src/main/java/org/opensearch/security/user/UserServiceException.java @@ -0,0 +1,20 @@ +/* + * 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.security.user; + +public class UserServiceException extends RuntimeException { + + public UserServiceException(String message) { + super(message); + } + +} diff --git a/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java b/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java index 8fa665e8ba..a3e08d5234 100644 --- a/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java +++ b/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java @@ -106,11 +106,12 @@ public void testSecurityUserInjection() throws Exception { Assert.fail("Expecting exception"); } catch (OpenSearchSecurityException ex) { exception = ex; - log.warn(ex.toString()); + log.debug(ex.toString()); Assert.assertNotNull(exception); - Assert.assertTrue(exception.getMessage().contains("indices:admin/create")); + Assert.assertTrue(exception.getMessage().toString().contains("no permissions for [indices:admin/create]")); } + // 3. with valid backend roles for injected user UserInjectorPlugin.injectedUser = "injectedadmin|injecttest"; try (Node node = new PluginAwareNode(false, tcSettings, Netty4ModulePlugin.class, @@ -157,6 +158,5 @@ public void testSecurityUserInjectionWithConfigDisabled() throws Exception { // Should pass as the user injection is disabled Assert.assertTrue(cir.isAcknowledged()); } - } } diff --git a/src/test/java/org/opensearch/security/auditlog/integration/TestAuditlogImpl.java b/src/test/java/org/opensearch/security/auditlog/integration/TestAuditlogImpl.java index b91ddee9fe..0502f078d9 100644 --- a/src/test/java/org/opensearch/security/auditlog/integration/TestAuditlogImpl.java +++ b/src/test/java/org/opensearch/security/auditlog/integration/TestAuditlogImpl.java @@ -61,7 +61,7 @@ public static List doThenWaitForMessages(final Runnable action, fi final List missedMessages = new ArrayList<>(); final List messages = new ArrayList<>(); final CountDownLatch latch = resetAuditStorage(expectedCount, messages); - + try { action.run(); final int maxSecondsToWaitForMessages = 1; @@ -104,9 +104,9 @@ public static List doThenWaitForMessages(final Runnable action, fi /** * Resets all of the mechanics for fresh messages to be captured - * + * * @param expectedMessageCount The number of messages before the latch is signalled, indicating all messages have been recieved - * @param message Where messages will be stored after being recieved + * @param messages Where messages will be stored after being recieved */ private static CountDownLatch resetAuditStorage(int expectedMessageCount, List messages) { final CountDownLatch latch = new CountDownLatch(expectedMessageCount); diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java index 1ecd96e148..d755751e54 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java @@ -42,6 +42,33 @@ protected String getEndpointPrefix() { return PLUGINS_PREFIX; } + + private static final String ENABLED_SERVICE_ACCOUNT_BODY = "{" + + " \"attributes\": { \"owner\": \"test_owner\", " + + "\"isEnabled\": \"true\"}" + + " }\n"; + + private static final String DISABLED_SERVICE_ACCOUNT_BODY = "{" + + " \"attributes\": { \"owner\": \"test_owner\", " + + "\"isEnabled\": \"false\"}" + + " }\n"; + private static final String ENABLED_NOT_SERVICE_ACCOUNT_BODY = "{" + + " \"attributes\": { \"owner\": \"user_is_owner_1\", " + + "\"isEnabled\": \"true\"}" + + " }\n"; + private static final String PASSWORD_SERVICE = "{ \"password\" : \"test\"," + + " \"attributes\": { \"owner\": \"test_owner\", " + + "\"isEnabled\": \"true\"}" + + " }\n"; + private static final String HASH_SERVICE = "{ \"owner\" : \"test_owner\"," + + " \"attributes\": { \"owner\": \"test_owner\", " + + "\"isEnabled\": \"true\"}" + + " }\n"; + private static final String PASSWORD_HASH_SERVICE = "{ \"password\" : \"test\", \"hash\" : \"123\"," + + " \"attributes\": { \"owner\": \"test_owner\", " + + "\"isEnabled\": \"true\"}" + + " }\n"; + public UserApiTest(){ ENDPOINT = getEndpointPrefix() + "/api"; } @@ -139,6 +166,7 @@ private void verifyGet(final Header... header) throws Exception { // GET, new URL endpoint in security response = rh.executeGetRequest(ENDPOINT + "/user", header); Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + } private void verifyPut(final Header... header) throws Exception { @@ -194,6 +222,7 @@ private void verifyPut(final Header... header) throws Exception { Assert.assertEquals(settings.get("reason"), AbstractConfigurationValidator.ErrorType.INVALID_CONFIGURATION.getMessage()); Assert.assertTrue(settings.get(AbstractConfigurationValidator.INVALID_KEYS_KEY + ".keys").contains("some")); Assert.assertTrue(settings.get(AbstractConfigurationValidator.INVALID_KEYS_KEY + ".keys").contains("other")); + } private void verifyPatch(final boolean sendAdminCert, Header... restAdminHeader) throws Exception { @@ -292,6 +321,40 @@ private void verifyPatch(final boolean sendAdminCert, Header... restAdminHeader) addUserWithHash("nagilum", "$2a$12$n5nubfWATfQjSYHiWtUyeOxMIxFInUHOAx8VMmGmxFNPGpaBmeB.m", HttpStatus.SC_CREATED); + // Add enabled service account then get it + response = rh.executePutRequest(ENDPOINT + "/internalusers/happyServiceLive", + ENABLED_SERVICE_ACCOUNT_BODY, restAdminHeader); + Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); + response = rh.executeGetRequest(ENDPOINT + "/internalusers/happyServiceLive", restAdminHeader); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + + // Add disabled service account + response = rh.executePutRequest(ENDPOINT + "/internalusers/happyServiceDead", + DISABLED_SERVICE_ACCOUNT_BODY, restAdminHeader); + Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); + + // Add enabled non-service account + response = rh.executePutRequest(ENDPOINT + "/internalusers/user_is_owner_1", + ENABLED_NOT_SERVICE_ACCOUNT_BODY, restAdminHeader); + Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); + + // Add service account with password -- Should Fail + + response = rh.executePutRequest(ENDPOINT + "/internalusers/passwordService", + PASSWORD_SERVICE, restAdminHeader); + Assert.assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatusCode()); + + //Add service with hash -- should fail + response = rh.executePutRequest(ENDPOINT + "/internalusers/hashService", + HASH_SERVICE, restAdminHeader); + Assert.assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatusCode()); + + // Add Service account with password & Hash -- should fail + response = rh.executePutRequest(ENDPOINT + "/internalusers/passwordHashService", + PASSWORD_HASH_SERVICE, restAdminHeader); + Assert.assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatusCode()); + // access must be allowed now checkGeneralAccess(HttpStatus.SC_OK, "nagilum", "nagilum"); @@ -417,7 +480,6 @@ private void verifyRoles(final boolean sendAdminCert, Header... header) throws E addUserWithPassword("$1aAAAAAAAAC", "$1aAAAAAAAAC", HttpStatus.SC_CREATED); addUserWithPassword("abc", "abc", HttpStatus.SC_CREATED); - // check tabs in json response = rh.executePutRequest(ENDPOINT + "/internalusers/userwithtabs", "\t{\"hash\": \t \"123\"\t} ", header); Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); @@ -478,7 +540,6 @@ public void testPasswordRules() throws Exception { HttpResponse response = rh .executeGetRequest("_plugins/_security/api/" + CType.INTERNALUSERS.toLCString()); Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); - System.out.println(response.getBody()); Settings settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); Assert.assertEquals(133, settings.size()); From 6ace852f3c422adb60e062c0bf8aedae2db9c8d8 Mon Sep 17 00:00:00 2001 From: Stephen Crawford <65832608+scrawfor99@users.noreply.github.com> Date: Tue, 25 Apr 2023 09:28:32 -0400 Subject: [PATCH 15/16] Resolve ImmutableOpenMap issue from core refactor (#2715) --- .../framework/matcher/AliasExistsMatcher.java | 15 +++++++++++---- ...lusterContainTemplateWithAliasMatcher.java | 19 +++++++++++++++---- ...ettingsResponseContainsIndicesMatcher.java | 13 ++++++++++--- .../matcher/IndexMappingIsEqualToMatcher.java | 5 +---- .../matcher/IndexStateIsEqualToMatcher.java | 5 +++-- .../privileges/PrivilegesEvaluator.java | 15 +++++++++------ 6 files changed, 49 insertions(+), 23 deletions(-) diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/AliasExistsMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/AliasExistsMatcher.java index ef2ffb365b..4999da8e95 100644 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/AliasExistsMatcher.java +++ b/src/integrationTest/java/org/opensearch/test/framework/matcher/AliasExistsMatcher.java @@ -10,12 +10,15 @@ package org.opensearch.test.framework.matcher; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import com.carrotsearch.hppc.cursors.ObjectObjectCursor; import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; @@ -23,7 +26,6 @@ import org.opensearch.action.admin.indices.alias.get.GetAliasesResponse; import org.opensearch.client.Client; import org.opensearch.cluster.metadata.AliasMetadata; -import org.opensearch.common.collect.ImmutableOpenMap; import static java.util.Objects.requireNonNull; import static java.util.Spliterator.IMMUTABLE; @@ -41,8 +43,13 @@ public AliasExistsMatcher(String aliasName) { protected boolean matchesSafely(Client client, Description mismatchDescription) { try { GetAliasesResponse response = client.admin().indices().getAliases(new GetAliasesRequest(aliasName)).get(); - ImmutableOpenMap> aliases = response.getAliases(); - Set actualAliasNames = StreamSupport.stream(spliteratorUnknownSize(aliases.valuesIt(), IMMUTABLE), false) + + final Map> aliases = new HashMap<>(); + for (ObjectObjectCursor> cursor : response.getAliases()) { + aliases.put(cursor.key, cursor.value); + } + + Set actualAliasNames = StreamSupport.stream(spliteratorUnknownSize(aliases.values().iterator(), IMMUTABLE), false) .flatMap(Collection::stream) .map(AliasMetadata::getAlias) .collect(Collectors.toSet()); @@ -53,7 +60,7 @@ protected boolean matchesSafely(Client client, Description mismatchDescription) } return true; } catch (InterruptedException | ExecutionException e) { - mismatchDescription.appendText("Error occured during checking if cluster contains alias ") + mismatchDescription.appendText("Error occurred during checking if cluster contains alias ") .appendValue(e); return false; } diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/ClusterContainTemplateWithAliasMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/ClusterContainTemplateWithAliasMatcher.java index 907fb30257..d59792e715 100644 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/ClusterContainTemplateWithAliasMatcher.java +++ b/src/integrationTest/java/org/opensearch/test/framework/matcher/ClusterContainTemplateWithAliasMatcher.java @@ -9,11 +9,14 @@ */ package org.opensearch.test.framework.matcher; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import com.carrotsearch.hppc.cursors.ObjectObjectCursor; import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; @@ -21,7 +24,6 @@ import org.opensearch.action.admin.indices.template.get.GetIndexTemplatesResponse; import org.opensearch.client.Client; import org.opensearch.cluster.metadata.AliasMetadata; -import org.opensearch.common.collect.ImmutableOpenMap; import static java.util.Objects.requireNonNull; @@ -55,15 +57,24 @@ protected boolean matchesSafely(Client client, Description mismatchDescription) private Set getAliases(GetIndexTemplatesResponse response) { return response.getIndexTemplates() .stream() - .map(metadata -> metadata.getAliases()) + .map(metadata -> { + Map aliases = new HashMap<>(); + for (ObjectObjectCursor cursor : metadata.getAliases()) { + aliases.put(cursor.key, cursor.value); + } + return aliases; + }) .flatMap(aliasMap -> aliasNames(aliasMap)) .collect(Collectors.toSet()); } - private Stream aliasNames(ImmutableOpenMap aliasMap) { - return StreamSupport.stream(aliasMap.keys().spliterator(), false).map(objectCursor -> objectCursor.value); + private Stream aliasNames(Map aliasMap) { + Iterable> iterable = () -> aliasMap.entrySet().iterator(); + return StreamSupport.stream(iterable.spliterator(), false) + .map(entry -> entry.getValue().getAlias()); } + @Override public void describeTo(Description description) { description.appendText("template ").appendValue(templateName).appendText(" exists and "); diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/GetSettingsResponseContainsIndicesMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/GetSettingsResponseContainsIndicesMatcher.java index 15c558d32f..79ac1c64ac 100644 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/GetSettingsResponseContainsIndicesMatcher.java +++ b/src/integrationTest/java/org/opensearch/test/framework/matcher/GetSettingsResponseContainsIndicesMatcher.java @@ -9,11 +9,14 @@ */ package org.opensearch.test.framework.matcher; +import java.util.HashMap; +import java.util.Map; + +import com.carrotsearch.hppc.cursors.ObjectObjectCursor; import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; import org.opensearch.action.admin.indices.settings.get.GetSettingsResponse; -import org.opensearch.common.collect.ImmutableOpenMap; import org.opensearch.common.settings.Settings; import static java.util.Objects.isNull; @@ -31,12 +34,16 @@ class GetSettingsResponseContainsIndicesMatcher extends TypeSafeDiagnosingMatche @Override protected boolean matchesSafely(GetSettingsResponse response, Description mismatchDescription) { - ImmutableOpenMap indexToSettings = response.getIndexToSettings(); + + final Map indexToSettings = new HashMap<>(); + for (ObjectObjectCursor cursor : response.getIndexToSettings()) { + indexToSettings.put(cursor.key, cursor.value); + } for (String index : expectedIndices) { if (!indexToSettings.containsKey(index)) { mismatchDescription .appendText("Response contains settings of indices: ") - .appendValue(indexToSettings.keys()); + .appendValue(indexToSettings.keySet()); return false; } } diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/IndexMappingIsEqualToMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/IndexMappingIsEqualToMatcher.java index 9621aff449..b90defef7d 100644 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/IndexMappingIsEqualToMatcher.java +++ b/src/integrationTest/java/org/opensearch/test/framework/matcher/IndexMappingIsEqualToMatcher.java @@ -17,8 +17,6 @@ import org.opensearch.action.admin.indices.mapping.get.GetMappingsRequest; import org.opensearch.action.admin.indices.mapping.get.GetMappingsResponse; import org.opensearch.client.Client; -import org.opensearch.cluster.metadata.MappingMetadata; -import org.opensearch.common.collect.ImmutableOpenMap; import org.opensearch.index.IndexNotFoundException; import org.opensearch.test.framework.cluster.LocalCluster; @@ -44,8 +42,7 @@ protected boolean matchesSafely(LocalCluster cluster, Description mismatchDescri GetMappingsResponse response = client.admin().indices() .getMappings(new GetMappingsRequest().indices(expectedIndexName)).actionGet(); - ImmutableOpenMap actualMappings = response.mappings(); - Map actualIndexMapping = actualMappings.get(expectedIndexName).getSourceAsMap(); + Map actualIndexMapping = response.getMappings().get(expectedIndexName).sourceAsMap(); if (!expectedMapping.equals(actualIndexMapping)) { mismatchDescription.appendText("Actual mapping ").appendValue(actualIndexMapping).appendText(" does not match expected"); diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/IndexStateIsEqualToMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/IndexStateIsEqualToMatcher.java index a9538b4b8b..ecff3fe2df 100644 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/IndexStateIsEqualToMatcher.java +++ b/src/integrationTest/java/org/opensearch/test/framework/matcher/IndexStateIsEqualToMatcher.java @@ -9,6 +9,8 @@ */ package org.opensearch.test.framework.matcher; +import java.util.Map; + import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; @@ -16,7 +18,6 @@ import org.opensearch.action.admin.cluster.state.ClusterStateResponse; import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexMetadata; -import org.opensearch.common.collect.ImmutableOpenMap; import org.opensearch.test.framework.cluster.LocalCluster; import static java.util.Objects.requireNonNull; @@ -37,7 +38,7 @@ protected boolean matchesSafely(LocalCluster cluster, Description mismatchDescri ClusterStateRequest clusterStateRequest = new ClusterStateRequest().indices(expectedIndexName); ClusterStateResponse clusterStateResponse = client.admin().cluster().state(clusterStateRequest).actionGet(); - ImmutableOpenMap indicesMetadata = clusterStateResponse.getState().getMetadata().indices(); + Map indicesMetadata = clusterStateResponse.getState().getMetadata().indices(); if (!indicesMetadata.containsKey(expectedIndexName)) { mismatchDescription.appendValue("Index does not exist"); } diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index 2c0e7ac7c0..b77b7a000f 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -37,6 +38,7 @@ import java.util.StringJoiner; import java.util.regex.Pattern; +import com.carrotsearch.hppc.cursors.ObjectObjectCursor; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import org.apache.logging.log4j.LogManager; @@ -78,7 +80,6 @@ import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.Strings; -import org.opensearch.common.collect.ImmutableOpenMap; import org.opensearch.common.settings.Settings; import org.opensearch.common.transport.TransportAddress; import org.opensearch.common.util.concurrent.ThreadContext; @@ -378,8 +379,6 @@ public PrivilegesEvaluatorResponse evaluate(final User user, String action0, fin presponse.allowed = true; return presponse; } - - } } @@ -632,6 +631,7 @@ public static boolean isClusterPerm(String action0) { ) ; } + @SuppressWarnings("unchecked") private boolean checkFilteredAliases(Resolved requestedResolved, String action, boolean isDebugEnabled) { final String faMode = dcm.getFilteredAliasMode();// getConfigSettings().dynamic.filtered_alias_mode; @@ -649,7 +649,7 @@ private boolean checkFilteredAliases(Resolved requestedResolved, String action, indexMetaDataCollection = new Iterable() { @Override public Iterator iterator() { - return clusterService.state().getMetadata().getIndices().valuesIt(); + return clusterService.state().getMetadata().getIndices().values().iterator(); } }; } else { @@ -674,14 +674,17 @@ public Iterator iterator() { final List filteredAliases = new ArrayList(); - final ImmutableOpenMap aliases = indexMetaData.getAliases(); + final Map aliases = new HashMap<>(); + for (ObjectObjectCursor cursor : indexMetaData.getAliases()) { + aliases.put(cursor.key, cursor.value); + } if(aliases != null && aliases.size() > 0) { if (isDebugEnabled) { log.debug("Aliases for {}: {}", indexMetaData.getIndex().getName(), aliases); } - final Iterator it = aliases.keysIt(); + final Iterator it = aliases.keySet().iterator(); while(it.hasNext()) { final String alias = it.next(); final AliasMetadata aliasMetadata = aliases.get(alias); From 6997f97f950683c1125ac5b0bb797c40fe8877e8 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 26 Apr 2023 17:45:15 -0400 Subject: [PATCH 16/16] Switch from ImmutableOpenMap to Map in AliasExistsMatcher (#2725) * Remove references to ObjectObjectCursor Signed-off-by: Craig Perkins --- .../test/framework/matcher/AliasExistsMatcher.java | 10 ++-------- .../ClusterContainTemplateWithAliasMatcher.java | 10 +--------- .../GetSettingsResponseContainsIndicesMatcher.java | 12 +++--------- .../security/privileges/PrivilegesEvaluator.java | 7 +------ 4 files changed, 7 insertions(+), 32 deletions(-) diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/AliasExistsMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/AliasExistsMatcher.java index 4999da8e95..4d8c81b037 100644 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/AliasExistsMatcher.java +++ b/src/integrationTest/java/org/opensearch/test/framework/matcher/AliasExistsMatcher.java @@ -10,7 +10,6 @@ package org.opensearch.test.framework.matcher; import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -18,7 +17,6 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; -import com.carrotsearch.hppc.cursors.ObjectObjectCursor; import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; @@ -44,11 +42,7 @@ protected boolean matchesSafely(Client client, Description mismatchDescription) try { GetAliasesResponse response = client.admin().indices().getAliases(new GetAliasesRequest(aliasName)).get(); - final Map> aliases = new HashMap<>(); - for (ObjectObjectCursor> cursor : response.getAliases()) { - aliases.put(cursor.key, cursor.value); - } - + Map> aliases = response.getAliases(); Set actualAliasNames = StreamSupport.stream(spliteratorUnknownSize(aliases.values().iterator(), IMMUTABLE), false) .flatMap(Collection::stream) .map(AliasMetadata::getAlias) @@ -61,7 +55,7 @@ protected boolean matchesSafely(Client client, Description mismatchDescription) return true; } catch (InterruptedException | ExecutionException e) { mismatchDescription.appendText("Error occurred during checking if cluster contains alias ") - .appendValue(e); + .appendValue(e); return false; } } diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/ClusterContainTemplateWithAliasMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/ClusterContainTemplateWithAliasMatcher.java index d59792e715..861aaa72e7 100644 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/ClusterContainTemplateWithAliasMatcher.java +++ b/src/integrationTest/java/org/opensearch/test/framework/matcher/ClusterContainTemplateWithAliasMatcher.java @@ -9,14 +9,12 @@ */ package org.opensearch.test.framework.matcher; -import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import com.carrotsearch.hppc.cursors.ObjectObjectCursor; import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; @@ -57,13 +55,7 @@ protected boolean matchesSafely(Client client, Description mismatchDescription) private Set getAliases(GetIndexTemplatesResponse response) { return response.getIndexTemplates() .stream() - .map(metadata -> { - Map aliases = new HashMap<>(); - for (ObjectObjectCursor cursor : metadata.getAliases()) { - aliases.put(cursor.key, cursor.value); - } - return aliases; - }) + .map(metadata -> metadata.getAliases()) .flatMap(aliasMap -> aliasNames(aliasMap)) .collect(Collectors.toSet()); } diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/GetSettingsResponseContainsIndicesMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/GetSettingsResponseContainsIndicesMatcher.java index 79ac1c64ac..01f14dd044 100644 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/GetSettingsResponseContainsIndicesMatcher.java +++ b/src/integrationTest/java/org/opensearch/test/framework/matcher/GetSettingsResponseContainsIndicesMatcher.java @@ -9,14 +9,11 @@ */ package org.opensearch.test.framework.matcher; -import java.util.HashMap; -import java.util.Map; - -import com.carrotsearch.hppc.cursors.ObjectObjectCursor; import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; import org.opensearch.action.admin.indices.settings.get.GetSettingsResponse; +import org.opensearch.common.collect.ImmutableOpenMap; import org.opensearch.common.settings.Settings; import static java.util.Objects.isNull; @@ -35,15 +32,12 @@ class GetSettingsResponseContainsIndicesMatcher extends TypeSafeDiagnosingMatche @Override protected boolean matchesSafely(GetSettingsResponse response, Description mismatchDescription) { - final Map indexToSettings = new HashMap<>(); - for (ObjectObjectCursor cursor : response.getIndexToSettings()) { - indexToSettings.put(cursor.key, cursor.value); - } + final ImmutableOpenMap indexToSettings = response.getIndexToSettings(); for (String index : expectedIndices) { if (!indexToSettings.containsKey(index)) { mismatchDescription .appendText("Response contains settings of indices: ") - .appendValue(indexToSettings.keySet()); + .appendValue(indexToSettings.keys()); return false; } } diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index b77b7a000f..8f490d180d 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -29,7 +29,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -38,7 +37,6 @@ import java.util.StringJoiner; import java.util.regex.Pattern; -import com.carrotsearch.hppc.cursors.ObjectObjectCursor; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import org.apache.logging.log4j.LogManager; @@ -674,10 +672,7 @@ public Iterator iterator() { final List filteredAliases = new ArrayList(); - final Map aliases = new HashMap<>(); - for (ObjectObjectCursor cursor : indexMetaData.getAliases()) { - aliases.put(cursor.key, cursor.value); - } + final Map aliases = indexMetaData.getAliases(); if(aliases != null && aliases.size() > 0) { if (isDebugEnabled) {