diff --git a/build.gradle b/build.gradle
index 0ed643b9f2..329451009a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -495,9 +495,9 @@ configurations {
// For integrationTest
force "org.apache.httpcomponents:httpclient:4.5.14"
force "org.apache.httpcomponents:httpcore:4.4.16"
- force "com.google.errorprone:error_prone_annotations:2.33.0"
+ force "com.google.errorprone:error_prone_annotations:2.34.0"
force "org.checkerframework:checker-qual:3.48.1"
- force "ch.qos.logback:logback-classic:1.5.10"
+ force "ch.qos.logback:logback-classic:1.5.11"
force "commons-io:commons-io:2.17.0"
}
}
@@ -598,7 +598,7 @@ dependencies {
implementation 'org.apache.commons:commons-collections4:4.4'
//Password generation
- implementation 'org.passay:passay:1.6.5'
+ implementation 'org.passay:passay:1.6.6'
implementation "org.apache.kafka:kafka-clients:${kafka_version}"
@@ -608,7 +608,7 @@ dependencies {
runtimeOnly 'com.eclipsesource.minimal-json:minimal-json:0.9.5'
runtimeOnly 'commons-codec:commons-codec:1.17.1'
runtimeOnly 'org.cryptacular:cryptacular:1.2.7'
- compileOnly 'com.google.errorprone:error_prone_annotations:2.33.0'
+ compileOnly 'com.google.errorprone:error_prone_annotations:2.34.0'
runtimeOnly 'com.sun.istack:istack-commons-runtime:4.2.0'
runtimeOnly 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.2'
runtimeOnly 'org.ow2.asm:asm:9.7.1'
@@ -690,6 +690,9 @@ dependencies {
testImplementation('org.awaitility:awaitility:4.2.2') {
exclude(group: 'org.hamcrest', module: 'hamcrest')
}
+ testImplementation "org.bouncycastle:bcpkix-jdk18on:${versions.bouncycastle}"
+ testImplementation "org.bouncycastle:bcutil-jdk18on:${versions.bouncycastle}"
+
// Only osx-x86_64, osx-aarch_64, linux-x86_64, linux-aarch_64, windows-x86_64 are available
if (osdetector.classifier in ["osx-x86_64", "osx-aarch_64", "linux-x86_64", "linux-aarch_64", "windows-x86_64"]) {
testImplementation "io.netty:netty-tcnative-classes:2.0.61.Final"
diff --git a/checkstyle/checkstyle.xml b/checkstyle/checkstyle.xml
index 04a36c49c1..a9c1a8f765 100644
--- a/checkstyle/checkstyle.xml
+++ b/checkstyle/checkstyle.xml
@@ -43,6 +43,13 @@
+
+
+
+
+
+
+
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 2b189974c2..fb602ee2af 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionSha256Sum=5b9c5eb3f9fc2c94abaea57d90bd78747ca117ddbbf96c859d3741181a12bf2a
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
+distributionSha256Sum=31c55713e40233a8303827ceb42ca48a47267a0ad4bab9177123121e71524c26
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/release-notes/opensearch-security.release-notes-2.18.0.0.md b/release-notes/opensearch-security.release-notes-2.18.0.0.md
new file mode 100644
index 0000000000..b6faf32235
--- /dev/null
+++ b/release-notes/opensearch-security.release-notes-2.18.0.0.md
@@ -0,0 +1,48 @@
+## Version 2.18.0 Release Notes
+
+Compatible with OpenSearch and OpenSearch Dashboards version 2.18.0
+
+### Enhancements
+* Improve error message when a node with an incorrectly configured certificate attempts to connect ([#4819](https://github.com/opensearch-project/security/pull/4819))
+* Support datastreams as an AuditLog Sink ([#4756](https://github.com/opensearch-project/security/pull/4756))
+* Auto-convert V6 configuration instances into V7 configuration instances (for OpenSearch 2.x only) ([#4753](https://github.com/opensearch-project/security/pull/4753))
+* Add can trip circuit breaker override ([#4779](https://github.com/opensearch-project/security/pull/4779))
+* Adding index permissions for remote index in AD ([#4721](https://github.com/opensearch-project/security/pull/4721))
+* Fix env var password hashing for PBKDF2 ([#4778](https://github.com/opensearch-project/security/pull/4778))
+* Add ensureCustomSerialization to ensure that headers are serialized correctly with multiple transport hops ([#4741](https://github.com/opensearch-project/security/pull/4741))
+
+### Bug Fixes
+* Handle non-flat yaml settings for demo configuration detection ([#4798](https://github.com/opensearch-project/security/pull/4798))
+* Fix bug where admin can read system index ([#4775](https://github.com/opensearch-project/security/pull/4775))
+* Ensure that dual mode enabled flag from cluster settings can get propagated to core ([#4830](https://github.com/opensearch-project/security/pull/4830))
+* Remove failed login attempt for saml authenticator ([#4770](https://github.com/opensearch-project/security/pull/4770))
+* Fix issue in HashingStoredFieldVisitor with stored fields ([#4827](https://github.com/opensearch-project/security/pull/4827))
+* Fix issue with Get mappings on a Closed index ([#4777](https://github.com/opensearch-project/security/pull/4777))
+* changing comments permission for alerting_ack_alerts role ([#4723](https://github.com/opensearch-project/security/pull/4723))
+* Fixed use of rolesMappingConfiguration in InternalUsersApiActionValidationTest ([#4754](https://github.com/opensearch-project/security/pull/4754))
+* Use evaluateSslExceptionHandler() when constructing OpenSearchSecureSettingsFactory ([#4726](https://github.com/opensearch-project/security/pull/4726))
+
+### Maintenance
+* Bump gradle to 8.10.2 ([#4829](https://github.com/opensearch-project/security/pull/4829))
+* Bump ch.qos.logback:logback-classic from 1.5.8 to 1.5.11 ([#4807](https://github.com/opensearch-project/security/pull/4807)) ([#4825](https://github.com/opensearch-project/security/pull/4825))
+* Bump org.passay:passay from 1.6.5 to 1.6.6 ([#4824](https://github.com/opensearch-project/security/pull/4824))
+* Bump org.junit.jupiter:junit-jupiter from 5.11.0 to 5.11.2 ([#4767](https://github.com/opensearch-project/security/pull/4767)) ([#4811](https://github.com/opensearch-project/security/pull/4811))
+* Bump io.dropwizard.metrics:metrics-core from 4.2.27 to 4.2.28 ([#4789](https://github.com/opensearch-project/security/pull/4789))
+* Bump com.nimbusds:nimbus-jose-jwt from 9.40 to 9.41.2 ([#4737](https://github.com/opensearch-project/security/pull/4737)) ([#4787](https://github.com/opensearch-project/security/pull/4787))
+* Bump org.ow2.asm:asm from 9.7 to 9.7.1 ([#4788](https://github.com/opensearch-project/security/pull/4788))
+* Bump com.google.googlejavaformat:google-java-format from 1.23.0 to 1.24.0 ([#4786](https://github.com/opensearch-project/security/pull/4786))
+* Bump org.xerial.snappy:snappy-java from 1.1.10.6 to 1.1.10.7 ([#4738](https://github.com/opensearch-project/security/pull/4738))
+* Bump org.gradle.test-retry from 1.5.10 to 1.6.0 ([#4736](https://github.com/opensearch-project/security/pull/4736))
+* Moves @cliu123 to emeritus status ([#4667](https://github.com/opensearch-project/security/pull/4667))
+* Add Derek Ho (github: derek-ho) as a maintainer ([#4796](https://github.com/opensearch-project/security/pull/4796))
+* Add deprecation warning for GET/POST/PUT cache ([#4776](https://github.com/opensearch-project/security/pull/4776))
+* Fix for: CVE-2024-47554 ([#4792](https://github.com/opensearch-project/security/pull/4792))
+* Move Stephen to emeritus ([#4804](https://github.com/opensearch-project/security/pull/4804))
+* Undeprecate securityadmin script ([#4768](https://github.com/opensearch-project/security/pull/4768))
+* Bump commons-io:commons-io from 2.16.1 to 2.17.0 ([#4750](https://github.com/opensearch-project/security/pull/4750))
+* Bump org.scala-lang:scala-library from 2.13.14 to 2.13.15 ([#4749](https://github.com/opensearch-project/security/pull/4749))
+* org.checkerframework:checker-qual and ch.qos.logback:logback-classic to new versions ([#4717](https://github.com/opensearch-project/security/pull/4717))
+* Add isActionPaginated to DelegatingRestHandler ([#4765](https://github.com/opensearch-project/security/pull/4765))
+* Refactor ASN1 call ([#4740](https://github.com/opensearch-project/security/pull/4740))
+* Fix 'integTest' not called with test workflows during release ([#4815](https://github.com/opensearch-project/security/pull/4815))
+* Fixed bulk index requests in BWC tests and hardened assertions ([#4831](https://github.com/opensearch-project/security/pull/4831))
diff --git a/src/integrationTest/java/org/opensearch/security/EncryptionInTransitMigrationTests.java b/src/integrationTest/java/org/opensearch/security/EncryptionInTransitMigrationTests.java
new file mode 100644
index 0000000000..58eb7218e6
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/EncryptionInTransitMigrationTests.java
@@ -0,0 +1,70 @@
+/*
+ * 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.util.Map;
+
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.opensearch.security.support.ConfigConstants;
+import org.opensearch.test.framework.cluster.ClusterManager;
+import org.opensearch.test.framework.cluster.LocalCluster;
+import org.opensearch.test.framework.cluster.TestRestClient;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL;
+import static org.awaitility.Awaitility.await;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test related to SSL-only mode of security plugin. In this mode, the security plugin is responsible only for TLS/SSL encryption.
+ * Therefore, the plugin does not perform authentication and authorization. Moreover, the REST resources (e.g. /_plugins/_security/whoami,
+ * /_plugins/_security/authinfo, etc.) provided by the plugin are not available.
+ */
+@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class)
+@ThreadLeakScope(ThreadLeakScope.Scope.NONE)
+public class EncryptionInTransitMigrationTests {
+
+ @ClassRule
+ public static LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.DEFAULT)
+ .anonymousAuth(false)
+ .loadConfigurationIntoIndex(false)
+ .nodeSettings(Map.of(ConfigConstants.SECURITY_SSL_ONLY, true))
+ .sslOnly(true)
+ .nodeSpecificSettings(0, Map.of(ConfigConstants.SECURITY_CONFIG_SSL_DUAL_MODE_ENABLED, true))
+ .nodeSpecificSettings(1, Map.of(ConfigConstants.SECURITY_CONFIG_SSL_DUAL_MODE_ENABLED, true))
+ .extectedNodeStartupCount(2)
+ .authc(AUTHC_HTTPBASIC_INTERNAL)
+ .build();
+
+ @Test
+ public void shouldOnlyConnectWithThirdNodeAfterDynamicDualModeChange() {
+ try (TestRestClient client = cluster.getRestClient()) {
+ TestRestClient.HttpResponse response = client.get("_cat/nodes");
+ response.assertStatusCode(200);
+
+ String[] lines = response.getBody().split("\n");
+ assertEquals("Expected 2 nodes in the initial response", 2, lines.length);
+
+ String settingsJson = "{\"persistent\": {\"plugins.security_config.ssl_dual_mode_enabled\": false}}";
+ TestRestClient.HttpResponse settingsResponse = client.putJson("_cluster/settings", settingsJson);
+ settingsResponse.assertStatusCode(200);
+
+ await().atMost(10, SECONDS).pollInterval(1, SECONDS).until(() -> {
+ TestRestClient.HttpResponse secondResponse = client.get("_cat/nodes");
+ String[] secondLines = secondResponse.getBody().split("\n");
+ return secondLines.length == 3;
+ });
+ }
+ }
+}
diff --git a/src/integrationTest/java/org/opensearch/security/StoredFieldsTests.java b/src/integrationTest/java/org/opensearch/security/StoredFieldsTests.java
new file mode 100644
index 0000000000..9bcc0c5526
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/StoredFieldsTests.java
@@ -0,0 +1,110 @@
+/*
+ * 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 com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
+import org.apache.http.HttpStatus;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.opensearch.action.admin.indices.create.CreateIndexResponse;
+import org.opensearch.client.Client;
+import org.opensearch.test.framework.TestSecurityConfig;
+import org.opensearch.test.framework.cluster.ClusterManager;
+import org.opensearch.test.framework.cluster.LocalCluster;
+import org.opensearch.test.framework.cluster.TestRestClient;
+
+import static org.opensearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE;
+import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL;
+
+@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class)
+@ThreadLeakScope(ThreadLeakScope.Scope.NONE)
+public class StoredFieldsTests {
+ static final TestSecurityConfig.User TEST_USER_MASKED_FIELDS = new TestSecurityConfig.User("test_user_masked_fields").roles(
+ new TestSecurityConfig.Role("role_masked_fields").clusterPermissions("cluster_composite_ops_ro")
+ .indexPermissions("read")
+ .maskedFields("restricted")
+ .on("test_index")
+ );
+
+ static final TestSecurityConfig.User TEST_USER_FLS = new TestSecurityConfig.User("test_user_fls").roles(
+ new TestSecurityConfig.Role("role_fls").clusterPermissions("cluster_composite_ops_ro")
+ .indexPermissions("read")
+ .fls("~restricted")
+ .on("test_index")
+ );
+
+ @ClassRule
+ public static final LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS)
+ .authc(AUTHC_HTTPBASIC_INTERNAL)
+ .users(TEST_USER_MASKED_FIELDS, TEST_USER_FLS)
+ .build();
+
+ @BeforeClass
+ public static void createTestData() {
+ try (Client client = cluster.getInternalNodeClient()) {
+ CreateIndexResponse r = client.admin()
+ .indices()
+ .prepareCreate("test_index")
+ .setMapping("raw", "type=keyword,store=true", "restricted", "type=keyword,store=true")
+ .get();
+
+ client.prepareIndex("test_index").setRefreshPolicy(IMMEDIATE).setSource("raw", "hello", "restricted", "boo!").get();
+ }
+ }
+
+ @Test
+ public void testStoredWithWithApplicableMaskedFieldRestrictions() {
+ try (TestRestClient client = cluster.getRestClient(TEST_USER_MASKED_FIELDS)) {
+ TestRestClient.HttpResponse normalSearchResponse = client.get("test_index/_search");
+ Assert.assertFalse(normalSearchResponse.getBody().contains("boo!"));
+
+ TestRestClient.HttpResponse fieldSearchResponse = client.postJson("test_index/_search", """
+ {
+ "stored_fields": [
+ "raw",
+ "restricted"
+ ]
+ }
+ """);
+ fieldSearchResponse.assertStatusCode(HttpStatus.SC_OK);
+ Assert.assertTrue(fieldSearchResponse.getBody().contains("raw"));
+ Assert.assertTrue(fieldSearchResponse.getBody().contains("hello"));
+ Assert.assertTrue(fieldSearchResponse.getBody().contains("restricted"));
+ Assert.assertFalse(fieldSearchResponse.getBody().contains("boo!"));
+ }
+ }
+
+ @Test
+ public void testStoredWithWithApplicableFlsRestrictions() {
+ try (TestRestClient client = cluster.getRestClient(TEST_USER_FLS)) {
+ TestRestClient.HttpResponse normalSearchResponse = client.get("test_index/_search");
+ Assert.assertFalse(normalSearchResponse.getBody().contains("boo!"));
+
+ TestRestClient.HttpResponse fieldSearchResponse = client.postJson("test_index/_search", """
+ {
+ "stored_fields": [
+ "raw",
+ "restricted"
+ ]
+ }
+ """);
+ fieldSearchResponse.assertStatusCode(HttpStatus.SC_OK);
+ Assert.assertTrue(fieldSearchResponse.getBody().contains("raw"));
+ Assert.assertTrue(fieldSearchResponse.getBody().contains("hello"));
+ Assert.assertFalse(fieldSearchResponse.getBody().contains("restricted"));
+ Assert.assertFalse(fieldSearchResponse.getBody().contains("boo!"));
+ }
+ }
+
+}
diff --git a/src/integrationTest/java/org/opensearch/security/SystemIndexTests.java b/src/integrationTest/java/org/opensearch/security/SystemIndexTests.java
index add98ca572..a131bb9891 100644
--- a/src/integrationTest/java/org/opensearch/security/SystemIndexTests.java
+++ b/src/integrationTest/java/org/opensearch/security/SystemIndexTests.java
@@ -13,12 +13,14 @@
import java.util.Map;
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
+import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.opensearch.core.rest.RestStatus;
-import org.opensearch.security.http.ExampleSystemIndexPlugin;
+import org.opensearch.security.plugin.SystemIndexPlugin1;
+import org.opensearch.security.plugin.SystemIndexPlugin2;
import org.opensearch.test.framework.TestSecurityConfig.AuthcDomain;
import org.opensearch.test.framework.cluster.ClusterManager;
import org.opensearch.test.framework.cluster.LocalCluster;
@@ -26,7 +28,10 @@
import org.opensearch.test.framework.cluster.TestRestClient.HttpResponse;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
+import static org.opensearch.security.plugin.SystemIndexPlugin1.SYSTEM_INDEX_1;
+import static org.opensearch.security.plugin.SystemIndexPlugin2.SYSTEM_INDEX_2;
import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ROLES_ENABLED;
import static org.opensearch.security.support.ConfigConstants.SECURITY_SYSTEM_INDICES_ENABLED_KEY;
import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS;
@@ -39,11 +44,11 @@ public class SystemIndexTests {
public static final AuthcDomain AUTHC_DOMAIN = new AuthcDomain("basic", 0).httpAuthenticatorWithChallenge("basic").backend("internal");
@ClassRule
- public static final LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE)
+ public static final LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.DEFAULT)
.anonymousAuth(false)
.authc(AUTHC_DOMAIN)
.users(USER_ADMIN)
- .plugin(ExampleSystemIndexPlugin.class)
+ .plugin(SystemIndexPlugin1.class, SystemIndexPlugin2.class)
.nodeSettings(
Map.of(
SECURITY_RESTAPI_ROLES_ENABLED,
@@ -54,6 +59,14 @@ public class SystemIndexTests {
)
.build();
+ @Before
+ public void wipeAllIndices() {
+ try (TestRestClient client = cluster.getRestClient(cluster.getAdminCertificate())) {
+ client.delete(".system-index1");
+ client.delete(".system-index2");
+ }
+ }
+
@Test
public void adminShouldNotBeAbleToDeleteSecurityIndex() {
try (TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
@@ -69,7 +82,7 @@ public void adminShouldNotBeAbleToDeleteSecurityIndex() {
assertThat(response2.getStatusCode(), equalTo(RestStatus.OK.getStatus()));
- // regular use can create system index
+ // regular user can create system index
HttpResponse response3 = client.put(".system-index1");
assertThat(response3.getStatusCode(), equalTo(RestStatus.OK.getStatus()));
@@ -81,6 +94,103 @@ public void adminShouldNotBeAbleToDeleteSecurityIndex() {
}
}
+ @Test
+ public void testPluginShouldBeAbleToIndexDocumentIntoItsSystemIndex() {
+ try (TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
+ HttpResponse response = client.put("try-create-and-index/" + SYSTEM_INDEX_1);
+
+ System.out.println("response: " + response.getBody());
+
+ assertThat(response.getStatusCode(), equalTo(RestStatus.OK.getStatus()));
+ assertThat(response.getBody(), containsString(SystemIndexPlugin1.class.getCanonicalName()));
+ }
+ }
+
+ @Test
+ public void testPluginShouldNotBeAbleToIndexDocumentIntoSystemIndexRegisteredByOtherPlugin() {
+ try (TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
+ HttpResponse response = client.put("try-create-and-index/" + SYSTEM_INDEX_2);
+
+ assertThat(response.getStatusCode(), equalTo(RestStatus.FORBIDDEN.getStatus()));
+ assertThat(
+ response.getBody(),
+ containsString(
+ "no permissions for [indices:admin/create] and User [name=plugin:org.opensearch.security.plugin.SystemIndexPlugin1"
+ )
+ );
+ }
+ }
+
+ @Test
+ public void testPluginShouldBeAbleToCreateSystemIndexButUserShouldNotBeAbleToIndex() {
+ try (TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
+ HttpResponse response = client.put("try-create-and-index/" + SYSTEM_INDEX_1 + "?runAs=user");
+
+ assertThat(response.getStatusCode(), equalTo(RestStatus.FORBIDDEN.getStatus()));
+ assertThat(response.getBody(), containsString("no permissions for [indices:data/write/index] and User [name=admin"));
+ }
+ }
+
+ @Test
+ public void testPluginShouldNotBeAbleToRunClusterActions() {
+ try (TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
+ HttpResponse response = client.get("try-cluster-health/plugin");
+
+ assertThat(response.getStatusCode(), equalTo(RestStatus.FORBIDDEN.getStatus()));
+ assertThat(
+ response.getBody(),
+ containsString(
+ "no permissions for [cluster:monitor/health] and User [name=plugin:org.opensearch.security.plugin.SystemIndexPlugin1"
+ )
+ );
+ }
+ }
+
+ @Test
+ public void testAdminUserShouldBeAbleToRunClusterActions() {
+ try (TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
+ HttpResponse response = client.get("try-cluster-health/user");
+
+ assertThat(response.getStatusCode(), equalTo(RestStatus.OK.getStatus()));
+ }
+ }
+
+ @Test
+ public void testAuthenticatedUserShouldBeAbleToRunClusterActions() {
+ try (TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
+ HttpResponse response = client.get("try-cluster-health/default");
+
+ assertThat(response.getStatusCode(), equalTo(RestStatus.OK.getStatus()));
+ }
+ }
+
+ @Test
+ public void testPluginShouldBeAbleToBulkIndexDocumentIntoItsSystemIndex() {
+ try (TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
+ HttpResponse response = client.put("try-create-and-bulk-index/" + SYSTEM_INDEX_1);
+
+ assertThat(response.getStatusCode(), equalTo(RestStatus.OK.getStatus()));
+ }
+ }
+
+ @Test
+ public void testPluginShouldNotBeAbleToBulkIndexDocumentIntoMixOfSystemIndexWhereAtLeastOneDoesNotBelongToPlugin() {
+ try (TestRestClient client = cluster.getRestClient(cluster.getAdminCertificate())) {
+ client.put(".system-index1");
+ client.put(".system-index2");
+ }
+ try (TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
+ HttpResponse response = client.put("try-create-and-bulk-mixed-index");
+
+ assertThat(
+ response.getBody(),
+ containsString(
+ "no permissions for [indices:data/write/bulk[s]] and User [name=plugin:org.opensearch.security.plugin.SystemIndexPlugin1"
+ )
+ );
+ }
+ }
+
@Test
public void regularUserShouldGetNoResultsWhenSearchingSystemIndex() {
// Create system index and index a dummy document as the super admin user, data returned to super admin
diff --git a/src/integrationTest/java/org/opensearch/security/http/ExampleSystemIndexPlugin.java b/src/integrationTest/java/org/opensearch/security/http/ExampleSystemIndexPlugin.java
deleted file mode 100644
index b4877aae14..0000000000
--- a/src/integrationTest/java/org/opensearch/security/http/ExampleSystemIndexPlugin.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright OpenSearch Contributors
- * SPDX-License-Identifier: Apache-2.0
- *
- * The OpenSearch Contributors require contributions made to
- * this file be licensed under the Apache-2.0 license or a
- * compatible open source license.
- *
- */
-package org.opensearch.security.http;
-
-import java.util.Collection;
-import java.util.Collections;
-
-import org.opensearch.common.settings.Settings;
-import org.opensearch.indices.SystemIndexDescriptor;
-import org.opensearch.plugins.Plugin;
-import org.opensearch.plugins.SystemIndexPlugin;
-
-public class ExampleSystemIndexPlugin extends Plugin implements SystemIndexPlugin {
-
- @Override
- public Collection getSystemIndexDescriptors(Settings settings) {
- final SystemIndexDescriptor systemIndexDescriptor = new SystemIndexDescriptor(".system-index1", "System index 1");
- return Collections.singletonList(systemIndexDescriptor);
- }
-}
diff --git a/src/integrationTest/java/org/opensearch/security/plugin/IndexDocumentIntoSystemIndexAction.java b/src/integrationTest/java/org/opensearch/security/plugin/IndexDocumentIntoSystemIndexAction.java
new file mode 100644
index 0000000000..9a60de201c
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/plugin/IndexDocumentIntoSystemIndexAction.java
@@ -0,0 +1,22 @@
+/*
+ * 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.plugin;
+
+import org.opensearch.action.ActionType;
+
+public class IndexDocumentIntoSystemIndexAction extends ActionType {
+ public static final IndexDocumentIntoSystemIndexAction INSTANCE = new IndexDocumentIntoSystemIndexAction();
+ public static final String NAME = "cluster:mock/systemindex/index";
+
+ private IndexDocumentIntoSystemIndexAction() {
+ super(NAME, IndexDocumentIntoSystemIndexResponse::new);
+ }
+}
diff --git a/src/integrationTest/java/org/opensearch/security/plugin/IndexDocumentIntoSystemIndexRequest.java b/src/integrationTest/java/org/opensearch/security/plugin/IndexDocumentIntoSystemIndexRequest.java
new file mode 100644
index 0000000000..d1b644ad11
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/plugin/IndexDocumentIntoSystemIndexRequest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.plugin;
+
+import java.io.IOException;
+
+import org.opensearch.action.ActionRequest;
+import org.opensearch.action.ActionRequestValidationException;
+import org.opensearch.core.common.io.stream.StreamInput;
+
+public class IndexDocumentIntoSystemIndexRequest extends ActionRequest {
+
+ private final String indexName;
+
+ private final String runAs;
+
+ public IndexDocumentIntoSystemIndexRequest(String indexName, String runAs) {
+ this.indexName = indexName;
+ this.runAs = runAs;
+ }
+
+ public IndexDocumentIntoSystemIndexRequest(StreamInput in) throws IOException {
+ super(in);
+ this.indexName = in.readString();
+ this.runAs = in.readOptionalString();
+ }
+
+ @Override
+ public ActionRequestValidationException validate() {
+ return null;
+ }
+
+ public String getIndexName() {
+ return this.indexName;
+ }
+
+ public String getRunAs() {
+ return this.runAs;
+ }
+}
diff --git a/src/integrationTest/java/org/opensearch/security/plugin/IndexDocumentIntoSystemIndexResponse.java b/src/integrationTest/java/org/opensearch/security/plugin/IndexDocumentIntoSystemIndexResponse.java
new file mode 100644
index 0000000000..9779cca252
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/plugin/IndexDocumentIntoSystemIndexResponse.java
@@ -0,0 +1,48 @@
+/*
+ * 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.plugin;
+
+// CS-SUPPRESS-SINGLE: RegexpSingleline It is not possible to use phrase "cluster manager" instead of master here
+import java.io.IOException;
+
+import org.opensearch.action.support.master.AcknowledgedResponse;
+import org.opensearch.core.common.io.stream.StreamInput;
+import org.opensearch.core.common.io.stream.StreamOutput;
+import org.opensearch.core.xcontent.ToXContent;
+import org.opensearch.core.xcontent.ToXContentObject;
+import org.opensearch.core.xcontent.XContentBuilder;
+// CS-ENFORCE-SINGLE
+
+public class IndexDocumentIntoSystemIndexResponse extends AcknowledgedResponse implements ToXContentObject {
+
+ private String plugin;
+
+ public IndexDocumentIntoSystemIndexResponse(boolean status, String plugin) {
+ super(status);
+ this.plugin = plugin;
+ }
+
+ public IndexDocumentIntoSystemIndexResponse(StreamInput in) throws IOException {
+ super(in);
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ super.writeTo(out);
+ out.writeString(plugin);
+ }
+
+ @Override
+ public void addCustomFields(XContentBuilder builder, ToXContent.Params params) throws IOException {
+ super.addCustomFields(builder, params);
+ builder.field("plugin", plugin);
+ }
+}
diff --git a/src/integrationTest/java/org/opensearch/security/plugin/RestBulkIndexDocumentIntoMixOfSystemIndexAction.java b/src/integrationTest/java/org/opensearch/security/plugin/RestBulkIndexDocumentIntoMixOfSystemIndexAction.java
new file mode 100644
index 0000000000..0d1dc4fe01
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/plugin/RestBulkIndexDocumentIntoMixOfSystemIndexAction.java
@@ -0,0 +1,78 @@
+/*
+ * 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.plugin;
+
+import java.util.List;
+
+import org.opensearch.action.bulk.BulkRequest;
+import org.opensearch.action.bulk.BulkRequestBuilder;
+import org.opensearch.action.index.IndexRequest;
+import org.opensearch.action.support.WriteRequest;
+import org.opensearch.client.Client;
+import org.opensearch.client.node.NodeClient;
+import org.opensearch.common.xcontent.XContentType;
+import org.opensearch.core.action.ActionListener;
+import org.opensearch.core.rest.RestStatus;
+import org.opensearch.core.xcontent.ToXContent;
+import org.opensearch.rest.BaseRestHandler;
+import org.opensearch.rest.BytesRestResponse;
+import org.opensearch.rest.RestChannel;
+import org.opensearch.rest.RestRequest;
+import org.opensearch.security.identity.PluginContextSwitcher;
+
+import static java.util.Collections.singletonList;
+import static org.opensearch.rest.RestRequest.Method.PUT;
+import static org.opensearch.security.plugin.SystemIndexPlugin1.SYSTEM_INDEX_1;
+import static org.opensearch.security.plugin.SystemIndexPlugin2.SYSTEM_INDEX_2;
+
+public class RestBulkIndexDocumentIntoMixOfSystemIndexAction extends BaseRestHandler {
+
+ private final Client client;
+ private final PluginContextSwitcher contextSwitcher;
+
+ public RestBulkIndexDocumentIntoMixOfSystemIndexAction(Client client, PluginContextSwitcher contextSwitcher) {
+ this.client = client;
+ this.contextSwitcher = contextSwitcher;
+ }
+
+ @Override
+ public List routes() {
+ return singletonList(new Route(PUT, "/try-create-and-bulk-mixed-index"));
+ }
+
+ @Override
+ public String getName() {
+ return "test_bulk_index_document_into_mix_of_system_index_action";
+ }
+
+ @Override
+ public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) {
+ return new RestChannelConsumer() {
+
+ @Override
+ public void accept(RestChannel channel) throws Exception {
+ contextSwitcher.runAs(() -> {
+ BulkRequestBuilder builder = client.prepareBulk();
+ builder.add(new IndexRequest(SYSTEM_INDEX_1).source("{\"content\":1}", XContentType.JSON));
+ builder.add(new IndexRequest(SYSTEM_INDEX_2).source("{\"content\":1}", XContentType.JSON));
+ builder.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
+ BulkRequest bulkRequest = builder.request();
+ client.bulk(bulkRequest, ActionListener.wrap(r -> {
+ channel.sendResponse(
+ new BytesRestResponse(RestStatus.OK, r.toXContent(channel.newBuilder(), ToXContent.EMPTY_PARAMS))
+ );
+ }, fr -> { channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, String.valueOf(fr))); }));
+ return null;
+ });
+ }
+ };
+ }
+}
diff --git a/src/integrationTest/java/org/opensearch/security/plugin/RestBulkIndexDocumentIntoSystemIndexAction.java b/src/integrationTest/java/org/opensearch/security/plugin/RestBulkIndexDocumentIntoSystemIndexAction.java
new file mode 100644
index 0000000000..56fa3ef2a9
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/plugin/RestBulkIndexDocumentIntoSystemIndexAction.java
@@ -0,0 +1,80 @@
+/*
+ * 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.plugin;
+
+import java.util.List;
+
+import org.opensearch.action.admin.indices.create.CreateIndexRequest;
+import org.opensearch.action.bulk.BulkRequest;
+import org.opensearch.action.bulk.BulkRequestBuilder;
+import org.opensearch.action.index.IndexRequest;
+import org.opensearch.action.support.WriteRequest;
+import org.opensearch.client.Client;
+import org.opensearch.client.node.NodeClient;
+import org.opensearch.common.xcontent.XContentType;
+import org.opensearch.core.action.ActionListener;
+import org.opensearch.core.rest.RestStatus;
+import org.opensearch.core.xcontent.ToXContent;
+import org.opensearch.rest.BaseRestHandler;
+import org.opensearch.rest.BytesRestResponse;
+import org.opensearch.rest.RestChannel;
+import org.opensearch.rest.RestRequest;
+import org.opensearch.security.identity.PluginContextSwitcher;
+
+import static java.util.Collections.singletonList;
+import static org.opensearch.rest.RestRequest.Method.PUT;
+
+public class RestBulkIndexDocumentIntoSystemIndexAction extends BaseRestHandler {
+
+ private final Client client;
+ private final PluginContextSwitcher contextSwitcher;
+
+ public RestBulkIndexDocumentIntoSystemIndexAction(Client client, PluginContextSwitcher contextSwitcher) {
+ this.client = client;
+ this.contextSwitcher = contextSwitcher;
+ }
+
+ @Override
+ public List routes() {
+ return singletonList(new Route(PUT, "/try-create-and-bulk-index/{index}"));
+ }
+
+ @Override
+ public String getName() {
+ return "test_bulk_index_document_into_system_index_action";
+ }
+
+ @Override
+ public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) {
+ String indexName = request.param("index");
+ return new RestChannelConsumer() {
+
+ @Override
+ public void accept(RestChannel channel) throws Exception {
+ contextSwitcher.runAs(() -> {
+ client.admin().indices().create(new CreateIndexRequest(indexName), ActionListener.wrap(r -> {
+ BulkRequestBuilder builder = client.prepareBulk();
+ builder.add(new IndexRequest(indexName).source("{\"content\":1}", XContentType.JSON));
+ builder.add(new IndexRequest(indexName).source("{\"content\":2}", XContentType.JSON));
+ builder.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
+ BulkRequest bulkRequest = builder.request();
+ client.bulk(bulkRequest, ActionListener.wrap(r2 -> {
+ channel.sendResponse(
+ new BytesRestResponse(RestStatus.OK, r.toXContent(channel.newBuilder(), ToXContent.EMPTY_PARAMS))
+ );
+ }, fr -> { channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, String.valueOf(fr))); }));
+ }, fr -> { channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, String.valueOf(fr))); }));
+ return null;
+ });
+ }
+ };
+ }
+}
diff --git a/src/integrationTest/java/org/opensearch/security/plugin/RestIndexDocumentIntoSystemIndexAction.java b/src/integrationTest/java/org/opensearch/security/plugin/RestIndexDocumentIntoSystemIndexAction.java
new file mode 100644
index 0000000000..e668e8bccc
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/plugin/RestIndexDocumentIntoSystemIndexAction.java
@@ -0,0 +1,49 @@
+/*
+ * 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.plugin;
+
+import java.util.List;
+
+import org.opensearch.client.Client;
+import org.opensearch.client.node.NodeClient;
+import org.opensearch.rest.BaseRestHandler;
+import org.opensearch.rest.RestRequest;
+import org.opensearch.rest.action.RestToXContentListener;
+
+import static java.util.Collections.singletonList;
+import static org.opensearch.rest.RestRequest.Method.PUT;
+
+public class RestIndexDocumentIntoSystemIndexAction extends BaseRestHandler {
+
+ private final Client client;
+
+ public RestIndexDocumentIntoSystemIndexAction(Client client) {
+ this.client = client;
+ }
+
+ @Override
+ public List routes() {
+ return singletonList(new Route(PUT, "/try-create-and-index/{index}"));
+ }
+
+ @Override
+ public String getName() {
+ return "test_index_document_into_system_index_action";
+ }
+
+ @Override
+ public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) {
+ String runAs = request.param("runAs");
+ String indexName = request.param("index");
+ IndexDocumentIntoSystemIndexRequest indexRequest = new IndexDocumentIntoSystemIndexRequest(indexName, runAs);
+ return channel -> client.execute(IndexDocumentIntoSystemIndexAction.INSTANCE, indexRequest, new RestToXContentListener<>(channel));
+ }
+}
diff --git a/src/integrationTest/java/org/opensearch/security/plugin/RestRunClusterHealthAction.java b/src/integrationTest/java/org/opensearch/security/plugin/RestRunClusterHealthAction.java
new file mode 100644
index 0000000000..755f3278f0
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/plugin/RestRunClusterHealthAction.java
@@ -0,0 +1,51 @@
+/*
+ * 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.plugin;
+
+import java.util.List;
+
+import org.opensearch.client.Client;
+import org.opensearch.client.node.NodeClient;
+import org.opensearch.rest.BaseRestHandler;
+import org.opensearch.rest.RestRequest;
+import org.opensearch.rest.action.RestToXContentListener;
+import org.opensearch.security.identity.PluginContextSwitcher;
+
+import static java.util.Collections.singletonList;
+import static org.opensearch.rest.RestRequest.Method.GET;
+
+public class RestRunClusterHealthAction extends BaseRestHandler {
+
+ private final Client client;
+ private final PluginContextSwitcher contextSwitcher;
+
+ public RestRunClusterHealthAction(Client client, PluginContextSwitcher contextSwitcher) {
+ this.client = client;
+ this.contextSwitcher = contextSwitcher;
+ }
+
+ @Override
+ public List routes() {
+ return singletonList(new Route(GET, "/try-cluster-health/{runAs}"));
+ }
+
+ @Override
+ public String getName() {
+ return "test_run_cluster_health_action";
+ }
+
+ @Override
+ public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) {
+ String runAs = request.param("runAs");
+ RunClusterHealthRequest runRequest = new RunClusterHealthRequest(runAs);
+ return channel -> client.execute(RunClusterHealthAction.INSTANCE, runRequest, new RestToXContentListener<>(channel));
+ }
+}
diff --git a/src/integrationTest/java/org/opensearch/security/plugin/RunClusterHealthAction.java b/src/integrationTest/java/org/opensearch/security/plugin/RunClusterHealthAction.java
new file mode 100644
index 0000000000..4234879bb8
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/plugin/RunClusterHealthAction.java
@@ -0,0 +1,22 @@
+/*
+ * 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.plugin;
+
+import org.opensearch.action.ActionType;
+
+public class RunClusterHealthAction extends ActionType {
+ public static final RunClusterHealthAction INSTANCE = new RunClusterHealthAction();
+ public static final String NAME = "cluster:mock/monitor/health";
+
+ private RunClusterHealthAction() {
+ super(NAME, RunClusterHealthResponse::new);
+ }
+}
diff --git a/src/integrationTest/java/org/opensearch/security/plugin/RunClusterHealthRequest.java b/src/integrationTest/java/org/opensearch/security/plugin/RunClusterHealthRequest.java
new file mode 100644
index 0000000000..8ae08bd6ff
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/plugin/RunClusterHealthRequest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.plugin;
+
+import java.io.IOException;
+
+import org.opensearch.action.ActionRequest;
+import org.opensearch.action.ActionRequestValidationException;
+import org.opensearch.core.common.io.stream.StreamInput;
+
+public class RunClusterHealthRequest extends ActionRequest {
+
+ private final String runAs;
+
+ public RunClusterHealthRequest(String runAs) {
+ this.runAs = runAs;
+ }
+
+ public RunClusterHealthRequest(StreamInput in) throws IOException {
+ super(in);
+ this.runAs = in.readString();
+ }
+
+ @Override
+ public ActionRequestValidationException validate() {
+ return null;
+ }
+
+ public String getRunAs() {
+ return this.runAs;
+ }
+}
diff --git a/src/integrationTest/java/org/opensearch/security/plugin/RunClusterHealthResponse.java b/src/integrationTest/java/org/opensearch/security/plugin/RunClusterHealthResponse.java
new file mode 100644
index 0000000000..7a855744dc
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/plugin/RunClusterHealthResponse.java
@@ -0,0 +1,42 @@
+/*
+ * 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.plugin;
+
+// CS-SUPPRESS-SINGLE: RegexpSingleline It is not possible to use phrase "cluster manager" instead of master here
+import java.io.IOException;
+
+import org.opensearch.action.support.master.AcknowledgedResponse;
+import org.opensearch.core.common.io.stream.StreamInput;
+import org.opensearch.core.common.io.stream.StreamOutput;
+import org.opensearch.core.xcontent.ToXContentObject;
+import org.opensearch.core.xcontent.XContentBuilder;
+// CS-ENFORCE-SINGLE
+
+public class RunClusterHealthResponse extends AcknowledgedResponse implements ToXContentObject {
+
+ public RunClusterHealthResponse(boolean status) {
+ super(status);
+ }
+
+ public RunClusterHealthResponse(StreamInput in) throws IOException {
+ super(in);
+ }
+
+ @Override
+ public void writeTo(StreamOutput out) throws IOException {
+ super.writeTo(out);
+ }
+
+ @Override
+ public void addCustomFields(XContentBuilder builder, Params params) throws IOException {
+ super.addCustomFields(builder, params);
+ }
+}
diff --git a/src/integrationTest/java/org/opensearch/security/plugin/SystemIndexPlugin1.java b/src/integrationTest/java/org/opensearch/security/plugin/SystemIndexPlugin1.java
new file mode 100644
index 0000000000..3f1112c4b6
--- /dev/null
+++ b/src/integrationTest/java/org/opensearch/security/plugin/SystemIndexPlugin1.java
@@ -0,0 +1,110 @@
+/*
+ * 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.plugin;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.opensearch.action.ActionRequest;
+import org.opensearch.client.Client;
+import org.opensearch.cluster.metadata.IndexNameExpressionResolver;
+import org.opensearch.cluster.node.DiscoveryNodes;
+import org.opensearch.cluster.service.ClusterService;
+import org.opensearch.common.settings.ClusterSettings;
+import org.opensearch.common.settings.IndexScopedSettings;
+import org.opensearch.common.settings.Settings;
+import org.opensearch.common.settings.SettingsFilter;
+import org.opensearch.core.action.ActionResponse;
+import org.opensearch.core.common.io.stream.NamedWriteableRegistry;
+import org.opensearch.core.xcontent.NamedXContentRegistry;
+import org.opensearch.env.Environment;
+import org.opensearch.env.NodeEnvironment;
+import org.opensearch.identity.PluginSubject;
+import org.opensearch.indices.SystemIndexDescriptor;
+import org.opensearch.plugins.IdentityAwarePlugin;
+import org.opensearch.plugins.Plugin;
+import org.opensearch.plugins.SystemIndexPlugin;
+import org.opensearch.repositories.RepositoriesService;
+import org.opensearch.rest.RestController;
+import org.opensearch.rest.RestHandler;
+import org.opensearch.script.ScriptService;
+import org.opensearch.security.identity.PluginContextSwitcher;
+import org.opensearch.threadpool.ThreadPool;
+import org.opensearch.watcher.ResourceWatcherService;
+
+public class SystemIndexPlugin1 extends Plugin implements SystemIndexPlugin, IdentityAwarePlugin {
+ public static final String SYSTEM_INDEX_1 = ".system-index1";
+
+ private PluginContextSwitcher contextSwitcher;
+
+ private Client client;
+
+ @Override
+ public Collection