From 1d2ea3aa4ad9fcd19e7e615c3bc3f4028063a43b Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 19:14:13 -0400 Subject: [PATCH 01/13] [Backport 3.2] Bumps spotbugs to 6.2.4 and checkstyle to 11.0.0 (#5556) Signed-off-by: Darshit Chanpura Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: Darshit Chanpura --- CHANGELOG.md | 1 + build.gradle | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bddbcf990d..397deac7d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Bump `net.minidev:accessors-smart` from 2.5.2 to 2.6.0 ([#5535](https://github.com/opensearch-project/security/pull/5535)) - Bump `commons-codec:commons-codec` from 1.18.0 to 1.19.0 ([#5534](https://github.com/opensearch-project/security/pull/5534)) - Bump `commons-cli:commons-cli` from 1.9.0 to 1.10.0 ([#5533](https://github.com/opensearch-project/security/pull/5533)) +- Bump `checkstyle` to 11.0.0 and `spotbugs` to 6.2.4 ([#5555](https://github.com/opensearch-project/security/pull/5555)) ### Documentation diff --git a/build.gradle b/build.gradle index 1f9fcbfeb3..45c517f4c5 100644 --- a/build.gradle +++ b/build.gradle @@ -69,7 +69,7 @@ plugins { id 'com.netflix.nebula.ospackage' version "11.11.2" id "org.gradle.test-retry" version "1.6.2" id 'eclipse' - id "com.github.spotbugs" version "6.2.3" + id "com.github.spotbugs" version "6.2.4" id "com.google.osdetector" version "1.7.3" } @@ -376,7 +376,7 @@ jacocoTestReport { } checkstyle { - toolVersion "10.26.1" + toolVersion "11.0.0" showViolations true configDirectory.set(rootProject.file("checkstyle/")) } From d9369b6bcb010456b1e9db05c64ac4b171123ff8 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 15:55:32 -0400 Subject: [PATCH 02/13] [Backport 3.2] Remove `commons-io` and `commons-lang3` maven metadata from being shaded in opensaml jar (#5559) Signed-off-by: Darshit Chanpura Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- CHANGELOG.md | 1 + libs/opensaml/build.gradle | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 397deac7d5..73865839af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Bump `commons-codec:commons-codec` from 1.18.0 to 1.19.0 ([#5534](https://github.com/opensearch-project/security/pull/5534)) - Bump `commons-cli:commons-cli` from 1.9.0 to 1.10.0 ([#5533](https://github.com/opensearch-project/security/pull/5533)) - Bump `checkstyle` to 11.0.0 and `spotbugs` to 6.2.4 ([#5555](https://github.com/opensearch-project/security/pull/5555)) +- Removes `commons-io` and `commons-lang3` maven metadata from shaded opensaml jar to fix CVE-2024-47554 ([#5558](https://github.com/opensearch-project/security/pull/5558)) ### Documentation diff --git a/libs/opensaml/build.gradle b/libs/opensaml/build.gradle index a316aed41b..974f461108 100644 --- a/libs/opensaml/build.gradle +++ b/libs/opensaml/build.gradle @@ -69,6 +69,8 @@ tasks.shadowJar { exclude 'org/publicsuffix/**' exclude 'org/slf4j/**' exclude 'javax/**' + exclude 'META-INF/maven/commons-io/commons-io/**' + exclude 'META-INF/maven/org.apache.commons/commons-lang3/**' exclude 'META-INF/versions/**/org/bouncycastle/**' exclude 'META-INF/services/org.opensaml.security.crypto.ec.NamedCurve' } From b2ef519bc405a6181d974aff6da98648b87b2dce Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Thu, 28 Aug 2025 15:18:40 -0400 Subject: [PATCH 03/13] Skip all types of write requests when user has document restrictions Signed-off-by: Craig Perkins --- .../security/configuration/DlsFlsValveImpl.java | 12 ++++++------ .../opensearch/security/filter/SecurityFilter.java | 3 ++- .../security/privileges/PrivilegesEvaluator.java | 1 + .../privileges/PrivilegesEvaluatorResponse.java | 8 ++++++++ 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/opensearch/security/configuration/DlsFlsValveImpl.java b/src/main/java/org/opensearch/security/configuration/DlsFlsValveImpl.java index 9762bfdc64..ff8cb97b3d 100644 --- a/src/main/java/org/opensearch/security/configuration/DlsFlsValveImpl.java +++ b/src/main/java/org/opensearch/security/configuration/DlsFlsValveImpl.java @@ -279,12 +279,12 @@ public boolean invoke(PrivilegesEvaluationContext context, final ActionListener< if (request instanceof BulkShardRequest) { for (BulkItemRequest inner : ((BulkShardRequest) request).items()) { - if (inner.request() instanceof UpdateRequest) { - listener.onFailure( - new OpenSearchSecurityException("Update is not supported when FLS or DLS or Fieldmasking is activated") - ); - return false; - } + listener.onFailure( + new OpenSearchSecurityException( + inner.request().getClass().getSimpleName() + " is not supported when FLS or DLS or Fieldmasking is activated" + ) + ); + return false; } } diff --git a/src/main/java/org/opensearch/security/filter/SecurityFilter.java b/src/main/java/org/opensearch/security/filter/SecurityFilter.java index c731c3545c..653b9fff81 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityFilter.java @@ -451,7 +451,7 @@ private void ap if (pres.isAllowed()) { auditLog.logGrantedPrivileges(action, request, task); auditLog.logIndexEvent(action, request, task); - if (!dlsFlsValve.invoke(context, listener)) { + if (!pres.shouldSkipDlsValve() && !dlsFlsValve.invoke(context, listener)) { return; } final CreateIndexRequestBuilder createIndexRequestBuilder = pres.getCreateIndexRequestBuilder(); @@ -465,6 +465,7 @@ private void ap createIndexRequest.index(), alias2Name(createIndexRequest.aliases()) ); + threadContext.putHeader(ConfigConstants.OPENDISTRO_SECURITY_CONF_REQUEST_HEADER, "true"); createIndexRequestBuilder.execute(ActionListener.wrap(createIndexResponse -> { if (createIndexResponse.isAcknowledged()) { log.debug( diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index 65c98d7165..d09653ecbd 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -537,6 +537,7 @@ public PrivilegesEvaluatorResponse evaluate(PrivilegesEvaluationContext context) if (replaceResult.accessDenied) { auditLog.logMissingPrivileges(action0, request, task); } else { + presponse.shouldSkipDlsValve = true; presponse.allowed = true; presponse.createIndexRequestBuilder = replaceResult.createIndexRequestBuilder; } diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorResponse.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorResponse.java index d072ec301c..1747df9fcb 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorResponse.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorResponse.java @@ -48,6 +48,7 @@ public class PrivilegesEvaluatorResponse { private CheckTable indexToActionCheckTable; private String privilegeMatrix; private String reason; + boolean shouldSkipDlsValve = false; /** * Contains issues that were encountered during privilege evaluation. Can be used for logging. @@ -61,6 +62,13 @@ public boolean isAllowed() { return allowed; } + /** + * Returns true if the request is only for dashboards indices + */ + public boolean shouldSkipDlsValve() { + return shouldSkipDlsValve; + } + /** * Returns true if the request can be allowed if the referenced indices are reduced (aka "do not fail on forbidden"). * See getAvailableIndices() for the indices for which we have privileges. From 1dd991801401c8070e1cc3e05db76f783a2a6d70 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 29 Aug 2025 11:00:02 -0400 Subject: [PATCH 04/13] Fix CHANGELOG Signed-off-by: Craig Perkins --- CHANGELOG.md | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c0e6bcfaf..03b4ccb57d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,32 +21,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Maintenance -- Bump `org.eclipse.platform:org.eclipse.core.runtime` from 3.33.0 to 3.33.100 ([#5400](https://github.com/opensearch-project/security/pull/5400)) -- Bump `org.eclipse.platform:org.eclipse.equinox.common` from 3.20.0 to 3.20.100 ([#5402](https://github.com/opensearch-project/security/pull/5402)) -- Bump `spring_version` from 6.2.7 to 6.2.9 ([#5403](https://github.com/opensearch-project/security/pull/5403), [#5493](https://github.com/opensearch-project/security/pull/5493)) -- Bump `stefanzweifel/git-auto-commit-action` from 5 to 6 ([#5401](https://github.com/opensearch-project/security/pull/5401)) -- Bump `com.github.spotbugs` from 5.2.5 to 6.2.3 ([#5409](https://github.com/opensearch-project/security/pull/5409), [#5450](https://github.com/opensearch-project/security/pull/5450), [#5474](https://github.com/opensearch-project/security/pull/5474), [#5536](https://github.com/opensearch-project/security/pull/5536)) -- Bump `org.codehaus.plexus:plexus-utils` from 3.3.0 to 3.6.0 ([#5429](https://github.com/opensearch-project/security/pull/5429)) -- Bump `net.bytebuddy:byte-buddy` from 1.17.5 to 1.17.6 ([#5427](https://github.com/opensearch-project/security/pull/5427)) -- Bump `io.dropwizard.metrics:metrics-core` from 4.2.32 to 4.2.33 ([#5428](https://github.com/opensearch-project/security/pull/5428)) -- Bump `org.junit.jupiter:junit-jupiter-api` from 5.13.1 to 5.13.2 ([#5446](https://github.com/opensearch-project/security/pull/5446)) -- Bump `com.google.errorprone:error_prone_annotations` from 2.38.0 to 2.41.0 ([#5447](https://github.com/opensearch-project/security/pull/5447), [#5477](https://github.com/opensearch-project/security/pull/5477), [#5512](https://github.com/opensearch-project/security/pull/5512), [#5532](https://github.com/opensearch-project/security/pull/5532)) -- Bump `io.dropwizard.metrics:metrics-core` from 4.2.32 to 4.2.33 ([#5428](https://github.com/opensearch-project/security/pull/5428)) -- Bump `org.junit.jupiter:junit-jupiter` from 5.13.2 to 5.13.4 ([#5460](https://github.com/opensearch-project/security/pull/5460), [#5513](https://github.com/opensearch-project/security/pull/5513)) -- Bump `org.checkerframework:checker-qual` from 3.49.4 to 3.49.5 ([#5462](https://github.com/opensearch-project/security/pull/5462)) -- Bump `com.google.googlejavaformat:google-java-format` from 1.27.0 to 1.28.0 ([#5475](https://github.com/opensearch-project/security/pull/5475)) -- Bump `commons-validator:commons-validator` from 1.9.0 to 1.10.0 ([#5476](https://github.com/opensearch-project/security/pull/5476)) -- Bumps checkstyle to 10.26.1 that fixes CVE-2025-48734 ([#5485](https://github.com/opensearch-project/security/pull/5485)) -- Bump `commons-io:commons-io` from 2.19.0 to 2.20.0 ([#5494](https://github.com/opensearch-project/security/pull/5494)) -- Bump `org.xerial.snappy:snappy-java` from 1.1.10.7 to 1.1.10.8 ([#5495](https://github.com/opensearch-project/security/pull/5495)) -- Bump `org.apache.commons:commons-text` from 1.13.1 to 1.14.0 ([#5511](https://github.com/opensearch-project/security/pull/5511)) -- Bump `org.springframework.kafka:spring-kafka-test` from 4.0.0-M2 to 4.0.0-M3 ([#5514](https://github.com/opensearch-project/security/pull/5514)) -- Bumps opensearch-protobufs plugin version to 0.6.0 ([#5529](https://github.com/opensearch-project/security/pull/5529)) -- Bump `net.minidev:accessors-smart` from 2.5.2 to 2.6.0 ([#5535](https://github.com/opensearch-project/security/pull/5535)) -- Bump `commons-codec:commons-codec` from 1.18.0 to 1.19.0 ([#5534](https://github.com/opensearch-project/security/pull/5534)) -- Bump `commons-cli:commons-cli` from 1.9.0 to 1.10.0 ([#5533](https://github.com/opensearch-project/security/pull/5533)) -- Bump `checkstyle` to 11.0.0 and `spotbugs` to 6.2.4 ([#5555](https://github.com/opensearch-project/security/pull/5555)) -- Removes `commons-io` and `commons-lang3` maven metadata from shaded opensaml jar to fix CVE-2024-47554 ([#5558](https://github.com/opensearch-project/security/pull/5558)) - Update delete_backport_branch workflow to include release-chores branches ([#5548](https://github.com/opensearch-project/security/pull/5548)) - Bump `1password/load-secrets-action` from 2 to 3 ([#5573](https://github.com/opensearch-project/security/pull/5573)) - Bump `jjwt_version` from 0.12.6 to 0.13.0 ([#5568](https://github.com/opensearch-project/security/pull/5568), [#5581](https://github.com/opensearch-project/security/pull/5581)) From ec66b0add471b9a5d067e332889507be38b786d6 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 29 Aug 2025 11:28:26 -0400 Subject: [PATCH 05/13] Fix bwc tests Signed-off-by: Craig Perkins --- .../bwc/SecurityBackwardsCompatibilityIT.java | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/bwc-test/src/test/java/org/opensearch/security/bwc/SecurityBackwardsCompatibilityIT.java b/bwc-test/src/test/java/org/opensearch/security/bwc/SecurityBackwardsCompatibilityIT.java index f32051967c..46100d66eb 100644 --- a/bwc-test/src/test/java/org/opensearch/security/bwc/SecurityBackwardsCompatibilityIT.java +++ b/bwc-test/src/test/java/org/opensearch/security/bwc/SecurityBackwardsCompatibilityIT.java @@ -337,7 +337,7 @@ private void ingestData(String index) throws IOException { bulkRequestBody.append(Song.randomSong().asJson() + "\n"); } List responses = RestHelper.requestAgainstAllNodes( - testUserRestClient, + adminClient(), "POST", "_bulk?refresh=wait_for", new StringEntity(bulkRequestBody.toString(), APPLICATION_NDJSON) @@ -413,30 +413,31 @@ private boolean resourceExists(String url) throws IOException { */ private void createTestRoleIfNotExists(String role) throws IOException { String url = "_plugins/_security/api/roles/" + role; - String roleSettings = "{\n" - + " \"cluster_permissions\": [\n" - + " \"unlimited\"\n" - + " ],\n" - + " \"index_permissions\": [\n" - + " {\n" - + " \"index_patterns\": [\n" - + " \"test_index*\"\n" - + " ],\n" - + " \"dls\": \"{ \\\"bool\\\": { \\\"must\\\": { \\\"match\\\": { \\\"genre\\\": \\\"rock\\\" } } } }\",\n" - + " \"fls\": [\n" - + " \"~lyrics\"\n" - + " ],\n" - + " \"masked_fields\": [\n" - + " \"artist\"\n" - + " ],\n" - + " \"allowed_actions\": [\n" - + " \"read\",\n" - + " \"write\"\n" - + " ]\n" - + " }\n" - + " ],\n" - + " \"tenant_permissions\": []\n" - + "}\n"; + String roleSettings = """ + { + "cluster_permissions": [ + "unlimited" + ], + "index_permissions": [ + { + "index_patterns": [ + "test_index*" + ], + "dls": "{ \"bool\": { \"must\": { \"match\": { \"genre\": \"rock\" } } } }", + "fls": [ + "~lyrics" + ], + "masked_fields": [ + "artist" + ], + "allowed_actions": [ + "read", + ] + } + ], + "tenant_permissions": [] + } + """; Response response = RestHelper.makeRequest(adminClient(), "PUT", url, RestHelper.toHttpEntity(roleSettings)); assertThat(response.getStatusLine().getStatusCode(), anyOf(equalTo(200), equalTo(201))); From a5d84da834ac735a97a09575cdf8ac709d7d0a4e Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 29 Aug 2025 11:57:22 -0400 Subject: [PATCH 06/13] Remove trailing comma Signed-off-by: Craig Perkins --- .../security/bwc/SecurityBackwardsCompatibilityIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bwc-test/src/test/java/org/opensearch/security/bwc/SecurityBackwardsCompatibilityIT.java b/bwc-test/src/test/java/org/opensearch/security/bwc/SecurityBackwardsCompatibilityIT.java index 46100d66eb..764ce133dd 100644 --- a/bwc-test/src/test/java/org/opensearch/security/bwc/SecurityBackwardsCompatibilityIT.java +++ b/bwc-test/src/test/java/org/opensearch/security/bwc/SecurityBackwardsCompatibilityIT.java @@ -431,7 +431,7 @@ private void createTestRoleIfNotExists(String role) throws IOException { "artist" ], "allowed_actions": [ - "read", + "read" ] } ], From 63419cd26ed1e771da41e2cd93d0f07665ccdcaa Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 29 Aug 2025 12:59:12 -0400 Subject: [PATCH 07/13] Use 3 backslashes Signed-off-by: Craig Perkins --- .../security/bwc/SecurityBackwardsCompatibilityIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bwc-test/src/test/java/org/opensearch/security/bwc/SecurityBackwardsCompatibilityIT.java b/bwc-test/src/test/java/org/opensearch/security/bwc/SecurityBackwardsCompatibilityIT.java index 764ce133dd..ab4abb6f55 100644 --- a/bwc-test/src/test/java/org/opensearch/security/bwc/SecurityBackwardsCompatibilityIT.java +++ b/bwc-test/src/test/java/org/opensearch/security/bwc/SecurityBackwardsCompatibilityIT.java @@ -423,7 +423,7 @@ private void createTestRoleIfNotExists(String role) throws IOException { "index_patterns": [ "test_index*" ], - "dls": "{ \"bool\": { \"must\": { \"match\": { \"genre\": \"rock\" } } } }", + "dls": "{ \\\"bool\\\": { \\\"must\\\": { \\\"match\\\": { \\\"genre\\\": \\\"rock\\\" } } } }", "fls": [ "~lyrics" ], From 442b84a12a008a8f66773f5aaf7eb14d39092ccc Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 2 Dec 2025 12:25:38 -0500 Subject: [PATCH 08/13] Remove shouldSkipDlsValve Signed-off-by: Craig Perkins --- .../org/opensearch/security/filter/SecurityFilter.java | 2 +- .../security/privileges/PrivilegesEvaluatorImpl.java | 1 - .../security/privileges/PrivilegesEvaluatorResponse.java | 8 -------- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/java/org/opensearch/security/filter/SecurityFilter.java b/src/main/java/org/opensearch/security/filter/SecurityFilter.java index 339bb20330..bb4aaa9685 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityFilter.java @@ -448,7 +448,7 @@ private void ap if (pres.isAllowed()) { auditLog.logGrantedPrivileges(action, request, task); auditLog.logIndexEvent(action, request, task); - if (!pres.shouldSkipDlsValve() && !dlsFlsValve.invoke(context, listener)) { + if (!dlsFlsValve.invoke(context, listener)) { return; } final CreateIndexRequestBuilder createIndexRequestBuilder = pres.getCreateIndexRequestBuilder(); diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorImpl.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorImpl.java index 14a8a97097..558fb6e6ad 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorImpl.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorImpl.java @@ -413,7 +413,6 @@ public PrivilegesEvaluatorResponse evaluate(PrivilegesEvaluationContext context) if (!replaceResult.continueEvaluation) { if (replaceResult.accessDenied) { - presponse.shouldSkipDlsValve = true; auditLog.logMissingPrivileges(action0, request, task); } else { return PrivilegesEvaluatorResponse.ok().with(replaceResult.createIndexRequestBuilder); diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorResponse.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorResponse.java index b13943b590..574200b3d7 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorResponse.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorResponse.java @@ -44,7 +44,6 @@ public class PrivilegesEvaluatorResponse { private final CheckTable indexToActionCheckTable; private String privilegeMatrix; private final String reason; - boolean shouldSkipDlsValve = false; /** * Contains issues that were encountered during privilege evaluation. Can be used for logging. @@ -90,13 +89,6 @@ public boolean isAllowed() { return allowed; } - /** - * Returns true if the request is only for dashboards indices - */ - public boolean shouldSkipDlsValve() { - return shouldSkipDlsValve; - } - /** * Returns true if the request can be allowed if the referenced indices are reduced (aka "do not fail on forbidden"). * See getAvailableIndices() for the indices for which we have privileges. From 4647d540558ef31455a21f7d816a433402efa6a6 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 2 Dec 2025 14:02:24 -0500 Subject: [PATCH 09/13] Remove unnecessary changes Signed-off-by: Craig Perkins --- CHANGELOG.md | 13 ------------- .../opensearch/security/filter/SecurityFilter.java | 1 - 2 files changed, 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad2fb9015c..016d8195e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,19 +50,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Maintenance -- Update delete_backport_branch workflow to include release-chores branches ([#5548](https://github.com/opensearch-project/security/pull/5548)) -- Bump `1password/load-secrets-action` from 2 to 3 ([#5573](https://github.com/opensearch-project/security/pull/5573)) -- Bump `jjwt_version` from 0.12.6 to 0.13.0 ([#5568](https://github.com/opensearch-project/security/pull/5568), [#5581](https://github.com/opensearch-project/security/pull/5581)) -- Bump `org.mockito:mockito-core` from 5.18.0 to 5.19.0 ([#5566](https://github.com/opensearch-project/security/pull/5566)) -- Bump `open_saml_version` from 5.1.4 to 5.1.5 ([#5567](https://github.com/opensearch-project/security/pull/5567)) -- Bump `com.google.j2objc:j2objc-annotations` from 3.0.0 to 3.1 ([#5570](https://github.com/opensearch-project/security/pull/5570)) -- Bump `spring_version` from 6.2.9 to 6.2.10 ([#5569](https://github.com/opensearch-project/security/pull/5569)) -- Bump `com.github.spotbugs` from 6.2.4 to 6.2.5 ([#5584](https://github.com/opensearch-project/security/pull/5584)) -- Bump `open_saml_shib_version` from 9.1.4 to 9.1.5 ([#5585](https://github.com/opensearch-project/security/pull/5585)) -- Bump `org.springframework.kafka:spring-kafka-test` from 4.0.0-M3 to 4.0.0-M4 ([#5583](https://github.com/opensearch-project/security/pull/5583)) -- Bump `net.bytebuddy:byte-buddy` from 1.17.6 to 1.17.7 ([#5586](https://github.com/opensearch-project/security/pull/5586)) -- Bump `io.dropwizard.metrics:metrics-core` from 4.2.33 to 4.2.34 ([#5589](https://github.com/opensearch-project/security/pull/5589)) -- Bump `com.nimbusds:nimbus-jose-jwt:9.48` from 9.48 to 10.4.2 ([#5595](https://github.com/opensearch-project/security/pull/5595)) - Bump `org.junit.jupiter:junit-jupiter` from 5.13.4 to 5.14.1 ([#5678](https://github.com/opensearch-project/security/pull/5678), [#5764](https://github.com/opensearch-project/security/pull/5764)) - Bump `ch.qos.logback:logback-classic` from 1.5.18 to 1.5.20 ([#5680](https://github.com/opensearch-project/security/pull/5680), [#5724](https://github.com/opensearch-project/security/pull/5724)) - Bump `org.scala-lang:scala-library` from 2.13.16 to 2.13.18 ([#5682](https://github.com/opensearch-project/security/pull/5682), [#5809](https://github.com/opensearch-project/security/pull/5809)) diff --git a/src/main/java/org/opensearch/security/filter/SecurityFilter.java b/src/main/java/org/opensearch/security/filter/SecurityFilter.java index bb4aaa9685..f4e005d6a2 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityFilter.java @@ -462,7 +462,6 @@ private void ap createIndexRequest.index(), alias2Name(createIndexRequest.aliases()) ); - threadContext.putHeader(ConfigConstants.OPENDISTRO_SECURITY_CONF_REQUEST_HEADER, "true"); createIndexRequestBuilder.execute(ActionListener.wrap(createIndexResponse -> { if (createIndexResponse.isAcknowledged()) { log.debug( From a745520d439439bdfdb3c25bb2a0f345f2f04b52 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 2 Dec 2025 14:10:14 -0500 Subject: [PATCH 10/13] Introduce dynamic cluster setting Signed-off-by: Craig Perkins --- .../security/OpenSearchSecurityPlugin.java | 1 + .../configuration/DlsFlsValveImpl.java | 32 +++++++++++++++---- .../security/support/ConfigConstants.java | 2 ++ .../security/support/SecuritySettings.java | 7 ++++ 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index 57af519311..8ed0d6de9b 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -2269,6 +2269,7 @@ public List> getSettings() { ); settings.add(SecuritySettings.USER_ATTRIBUTE_SERIALIZATION_ENABLED_SETTING); + settings.add(SecuritySettings.DLS_WRITE_BLOCKED); } return settings; diff --git a/src/main/java/org/opensearch/security/configuration/DlsFlsValveImpl.java b/src/main/java/org/opensearch/security/configuration/DlsFlsValveImpl.java index 1701164dc8..122ef92c86 100644 --- a/src/main/java/org/opensearch/security/configuration/DlsFlsValveImpl.java +++ b/src/main/java/org/opensearch/security/configuration/DlsFlsValveImpl.java @@ -85,11 +85,14 @@ import org.opensearch.security.setting.OpensearchDynamicSetting; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.HeaderHelper; +import org.opensearch.security.support.SecuritySettings; import org.opensearch.security.support.WildcardMatcher; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.client.Client; import static org.opensearch.security.privileges.PrivilegesEvaluatorImpl.isClusterPerm; +import static org.opensearch.security.support.ConfigConstants.SECURITY_DLS_WRITE_BLOCKED; +import static org.opensearch.security.support.ConfigConstants.SECURITY_DLS_WRITE_BLOCKED_ENABLED_DEFAULT; public class DlsFlsValveImpl implements DlsFlsRequestValve { @@ -109,6 +112,7 @@ public class DlsFlsValveImpl implements DlsFlsRequestValve { private final AdminDNs adminDNs; private final OpensearchDynamicSetting resourceSharingEnabledSetting; private final ResourcePluginInfo resourcePluginInfo; + private volatile boolean dlsWriteBlockedEnabled; public DlsFlsValveImpl( Settings settings, @@ -142,6 +146,12 @@ public DlsFlsValveImpl( config.updateClusterStateMetadataAsync(clusterService, threadPool); } }); + this.dlsWriteBlockedEnabled = settings.getAsBoolean(SECURITY_DLS_WRITE_BLOCKED, SECURITY_DLS_WRITE_BLOCKED_ENABLED_DEFAULT); + if (clusterService.getClusterSettings() != null) { + clusterService.getClusterSettings().addSettingsUpdateConsumer(SecuritySettings.DLS_WRITE_BLOCKED, newDlsWriteBlockedEnabled -> { + dlsWriteBlockedEnabled = newDlsWriteBlockedEnabled; + }); + } this.resourceSharingEnabledSetting = resourceSharingEnabledSetting; } @@ -333,12 +343,22 @@ public boolean invoke(PrivilegesEvaluationContext context, final ActionListener< if (request instanceof BulkShardRequest) { for (BulkItemRequest inner : ((BulkShardRequest) request).items()) { - listener.onFailure( - new OpenSearchSecurityException( - inner.request().getClass().getSimpleName() + " is not supported when FLS or DLS or Fieldmasking is activated" - ) - ); - return false; + if (dlsWriteBlockedEnabled) { + listener.onFailure( + new OpenSearchSecurityException( + inner.request().getClass().getSimpleName() + + " is not supported when FLS or DLS or Fieldmasking is activated" + ) + ); + return false; + } else { + if (inner.request() instanceof UpdateRequest) { + listener.onFailure( + new OpenSearchSecurityException("Update is not supported when FLS or DLS or Fieldmasking is activated") + ); + return false; + } + } } } diff --git a/src/main/java/org/opensearch/security/support/ConfigConstants.java b/src/main/java/org/opensearch/security/support/ConfigConstants.java index a7a271c758..37eb41a771 100644 --- a/src/main/java/org/opensearch/security/support/ConfigConstants.java +++ b/src/main/java/org/opensearch/security/support/ConfigConstants.java @@ -340,6 +340,8 @@ public enum RolesMappingResolution { public static final String SECURITY_FILTER_SECURITYINDEX_FROM_ALL_REQUESTS = SECURITY_SETTINGS_PREFIX + "filter_securityindex_from_all_requests"; public static final String SECURITY_DLS_MODE = SECURITY_SETTINGS_PREFIX + "dls.mode"; + public static final String SECURITY_DLS_WRITE_BLOCKED = SECURITY_SETTINGS_PREFIX + "dls.write_blocked"; + public static final boolean SECURITY_DLS_WRITE_BLOCKED_ENABLED_DEFAULT = false; // REST API public static final String SECURITY_RESTAPI_ROLES_ENABLED = SECURITY_SETTINGS_PREFIX + "restapi.roles_enabled"; public static final String SECURITY_RESTAPI_ADMIN_ENABLED = SECURITY_SETTINGS_PREFIX + "restapi.admin.enabled"; diff --git a/src/main/java/org/opensearch/security/support/SecuritySettings.java b/src/main/java/org/opensearch/security/support/SecuritySettings.java index 4a442c9316..cb5e6c1cd1 100644 --- a/src/main/java/org/opensearch/security/support/SecuritySettings.java +++ b/src/main/java/org/opensearch/security/support/SecuritySettings.java @@ -42,4 +42,11 @@ public class SecuritySettings { Setting.Property.NodeScope, Setting.Property.Dynamic ); // Not filtered + + public static final Setting DLS_WRITE_BLOCKED = Setting.boolSetting( + ConfigConstants.SECURITY_DLS_WRITE_BLOCKED, + false, + Setting.Property.NodeScope, + Setting.Property.Dynamic + ); } From 328199d033bfaad50c1d72f212e7ce1020b44ef3 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 2 Dec 2025 14:32:48 -0500 Subject: [PATCH 11/13] Add integrationTest suite Signed-off-by: Craig Perkins --- CHANGELOG.md | 1 - .../DlsWriteBlockedIntegrationTest.java | 183 ++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 src/integrationTest/java/org/opensearch/security/dlsfls/DlsWriteBlockedIntegrationTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 016d8195e3..2f32bacb66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Remove reflective call to getInnerChannel ([#5816](https://github.com/opensearch-project/security/pull/5816)) ### Maintenance - - Bump `org.junit.jupiter:junit-jupiter` from 5.13.4 to 5.14.1 ([#5678](https://github.com/opensearch-project/security/pull/5678), [#5764](https://github.com/opensearch-project/security/pull/5764)) - Bump `ch.qos.logback:logback-classic` from 1.5.18 to 1.5.20 ([#5680](https://github.com/opensearch-project/security/pull/5680), [#5724](https://github.com/opensearch-project/security/pull/5724)) - Bump `org.scala-lang:scala-library` from 2.13.16 to 2.13.18 ([#5682](https://github.com/opensearch-project/security/pull/5682), [#5809](https://github.com/opensearch-project/security/pull/5809)) diff --git a/src/integrationTest/java/org/opensearch/security/dlsfls/DlsWriteBlockedIntegrationTest.java b/src/integrationTest/java/org/opensearch/security/dlsfls/DlsWriteBlockedIntegrationTest.java new file mode 100644 index 0000000000..3f88c00a8e --- /dev/null +++ b/src/integrationTest/java/org/opensearch/security/dlsfls/DlsWriteBlockedIntegrationTest.java @@ -0,0 +1,183 @@ +/* + * 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.dlsfls; + +import java.io.IOException; +import java.util.Map; + +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.index.IndexRequest; +import org.opensearch.action.support.WriteRequest.RefreshPolicy; +import org.opensearch.client.RestHighLevelClient; +import org.opensearch.security.support.ConfigConstants; +import org.opensearch.test.framework.TestSecurityConfig.Role; +import org.opensearch.test.framework.TestSecurityConfig.User; +import org.opensearch.test.framework.cluster.ClusterManager; +import org.opensearch.test.framework.cluster.LocalCluster; +import org.opensearch.transport.client.Client; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; +import static org.opensearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; +import static org.opensearch.client.RequestOptions.DEFAULT; +import static org.opensearch.core.rest.RestStatus.INTERNAL_SERVER_ERROR; +import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL; +import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS; +import static org.opensearch.test.framework.matcher.ExceptionMatcherAssert.assertThatThrownBy; +import static org.opensearch.test.framework.matcher.OpenSearchExceptionMatchers.errorMessageContain; +import static org.opensearch.test.framework.matcher.OpenSearchExceptionMatchers.statusException; + +/** + * Integration tests for DLS_WRITE_BLOCKED setting which blocks write operations + * when users have DLS, FLS, or Field Masking restrictions. + */ +@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) +@ThreadLeakScope(ThreadLeakScope.Scope.NONE) +public class DlsWriteBlockedIntegrationTest { + + private static final String DLS_INDEX = "dls_index"; + private static final String FLS_INDEX = "fls_index"; + private static final String NO_RESTRICTION_INDEX = "no_restriction_index"; + + static final User ADMIN_USER = new User("admin").roles(ALL_ACCESS); + + static final User DLS_USER = new User("dls_user").roles( + new Role("dls_role").clusterPermissions("*").indexPermissions("*").dls("{\"term\": {\"dept\": \"sales\"}}").on(DLS_INDEX) + ); + + static final User FLS_USER = new User("fls_user").roles( + new Role("fls_role").clusterPermissions("*").indexPermissions("*").fls("public").on(FLS_INDEX) + ); + + @ClassRule + public static final LocalCluster clusterWithoutDlsWriteBlocked = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE) + .anonymousAuth(false) + .authc(AUTHC_HTTPBASIC_INTERNAL) + .users(ADMIN_USER, DLS_USER, FLS_USER) + .build(); + + @ClassRule + public static final LocalCluster clusterWithDlsWriteBlocked = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE) + .anonymousAuth(false) + .authc(AUTHC_HTTPBASIC_INTERNAL) + .users(ADMIN_USER, DLS_USER, FLS_USER) + .nodeSettings(Map.of(ConfigConstants.SECURITY_DLS_WRITE_BLOCKED, true)) + .build(); + + @BeforeClass + public static void createTestData() { + try (Client client = clusterWithoutDlsWriteBlocked.getInternalNodeClient()) { + client.index(new IndexRequest(DLS_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("dept", "sales", "amount", 100))) + .actionGet(); + client.index( + new IndexRequest(FLS_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("public", "data", "secret", "hidden")) + ).actionGet(); + client.index(new IndexRequest(NO_RESTRICTION_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("data", "value1"))) + .actionGet(); + } + + try (Client client = clusterWithDlsWriteBlocked.getInternalNodeClient()) { + client.index(new IndexRequest(DLS_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("dept", "sales", "amount", 100))) + .actionGet(); + client.index( + new IndexRequest(FLS_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("public", "data", "secret", "hidden")) + ).actionGet(); + client.index(new IndexRequest(NO_RESTRICTION_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("data", "value1"))) + .actionGet(); + } + } + + @Test + public void testDlsUser_CanWrite_WhenSettingDisabled() throws IOException { + try (RestHighLevelClient client = clusterWithoutDlsWriteBlocked.getRestHighLevelClient(DLS_USER)) { + IndexRequest request = new IndexRequest(DLS_INDEX).id("new1") + .setRefreshPolicy(RefreshPolicy.IMMEDIATE) + .source(Map.of("dept", "sales", "amount", 400)); + + var response = client.index(request, DEFAULT); + + assertThat(response.status().getStatus(), is(201)); + } + } + + @Test + public void testDlsUser_CannotWrite_WhenSettingEnabled() throws IOException { + try (RestHighLevelClient client = clusterWithDlsWriteBlocked.getRestHighLevelClient(DLS_USER)) { + IndexRequest request = new IndexRequest(DLS_INDEX).id("new1") + .setRefreshPolicy(RefreshPolicy.IMMEDIATE) + .source(Map.of("dept", "sales", "amount", 400)); + + assertThatThrownBy( + () -> client.index(request, DEFAULT), + allOf( + statusException(INTERNAL_SERVER_ERROR), + errorMessageContain("is not supported when FLS or DLS or Fieldmasking is activated") + ) + ); + } + } + + @Test + public void testFlsUser_CanWrite_WhenSettingDisabled() throws IOException { + try (RestHighLevelClient client = clusterWithoutDlsWriteBlocked.getRestHighLevelClient(FLS_USER)) { + IndexRequest request = new IndexRequest(FLS_INDEX).id("new1") + .setRefreshPolicy(RefreshPolicy.IMMEDIATE) + .source(Map.of("public", "new_data", "secret", "new_secret")); + + var response = client.index(request, DEFAULT); + + assertThat(response.status().getStatus(), is(201)); + } + } + + @Test + public void testFlsUser_CannotWrite_WhenSettingEnabled() throws IOException { + try (RestHighLevelClient client = clusterWithDlsWriteBlocked.getRestHighLevelClient(FLS_USER)) { + IndexRequest request = new IndexRequest(FLS_INDEX).id("new1") + .setRefreshPolicy(RefreshPolicy.IMMEDIATE) + .source(Map.of("public", "new_data", "secret", "new_secret")); + + assertThatThrownBy( + () -> client.index(request, DEFAULT), + allOf( + statusException(INTERNAL_SERVER_ERROR), + errorMessageContain("is not supported when FLS or DLS or Fieldmasking is activated") + ) + ); + } + } + + @Test + public void testAdminUser_CanWrite_WhenSettingEnabled() throws IOException { + try (RestHighLevelClient client = clusterWithDlsWriteBlocked.getRestHighLevelClient(ADMIN_USER)) { + IndexRequest request = new IndexRequest(DLS_INDEX).id("admin_doc") + .setRefreshPolicy(RefreshPolicy.IMMEDIATE) + .source(Map.of("dept", "admin", "amount", 999)); + + var response = client.index(request, DEFAULT); + + assertThat(response.status().getStatus(), is(201)); + } + } + + @Test + public void testDlsUser_CanRead_WhenSettingEnabled() throws IOException { + try (RestHighLevelClient client = clusterWithDlsWriteBlocked.getRestHighLevelClient(DLS_USER)) { + var response = client.search(new org.opensearch.action.search.SearchRequest(DLS_INDEX), DEFAULT); + + assertThat(response.status().getStatus(), is(200)); + } + } +} From f2ca6002c787053411e7931020644604c91f8db3 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 2 Dec 2025 14:45:39 -0500 Subject: [PATCH 12/13] Toggle setting dynamically Signed-off-by: Craig Perkins --- .../DlsWriteBlockedIntegrationTest.java | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/integrationTest/java/org/opensearch/security/dlsfls/DlsWriteBlockedIntegrationTest.java b/src/integrationTest/java/org/opensearch/security/dlsfls/DlsWriteBlockedIntegrationTest.java index 3f88c00a8e..c4225e6ba1 100644 --- a/src/integrationTest/java/org/opensearch/security/dlsfls/DlsWriteBlockedIntegrationTest.java +++ b/src/integrationTest/java/org/opensearch/security/dlsfls/DlsWriteBlockedIntegrationTest.java @@ -25,6 +25,7 @@ import org.opensearch.test.framework.TestSecurityConfig.User; import org.opensearch.test.framework.cluster.ClusterManager; import org.opensearch.test.framework.cluster.LocalCluster; +import org.opensearch.test.framework.cluster.TestRestClient; import org.opensearch.transport.client.Client; import static org.hamcrest.MatcherAssert.assertThat; @@ -62,23 +63,15 @@ public class DlsWriteBlockedIntegrationTest { ); @ClassRule - public static final LocalCluster clusterWithoutDlsWriteBlocked = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE) + public static final LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE) .anonymousAuth(false) .authc(AUTHC_HTTPBASIC_INTERNAL) .users(ADMIN_USER, DLS_USER, FLS_USER) .build(); - @ClassRule - public static final LocalCluster clusterWithDlsWriteBlocked = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE) - .anonymousAuth(false) - .authc(AUTHC_HTTPBASIC_INTERNAL) - .users(ADMIN_USER, DLS_USER, FLS_USER) - .nodeSettings(Map.of(ConfigConstants.SECURITY_DLS_WRITE_BLOCKED, true)) - .build(); - @BeforeClass public static void createTestData() { - try (Client client = clusterWithoutDlsWriteBlocked.getInternalNodeClient()) { + try (Client client = cluster.getInternalNodeClient()) { client.index(new IndexRequest(DLS_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("dept", "sales", "amount", 100))) .actionGet(); client.index( @@ -87,22 +80,22 @@ public static void createTestData() { client.index(new IndexRequest(NO_RESTRICTION_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("data", "value1"))) .actionGet(); } + } - try (Client client = clusterWithDlsWriteBlocked.getInternalNodeClient()) { - client.index(new IndexRequest(DLS_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("dept", "sales", "amount", 100))) - .actionGet(); - client.index( - new IndexRequest(FLS_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("public", "data", "secret", "hidden")) - ).actionGet(); - client.index(new IndexRequest(NO_RESTRICTION_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("data", "value1"))) - .actionGet(); + private void setDlsWriteBlocked(boolean enabled) throws IOException { + try (TestRestClient client = cluster.getRestClient(ADMIN_USER)) { + client.putJson( + "_cluster/settings", + String.format("{\"transient\":{\"%s\":%b}}", ConfigConstants.SECURITY_DLS_WRITE_BLOCKED, enabled) + ); } } @Test public void testDlsUser_CanWrite_WhenSettingDisabled() throws IOException { - try (RestHighLevelClient client = clusterWithoutDlsWriteBlocked.getRestHighLevelClient(DLS_USER)) { - IndexRequest request = new IndexRequest(DLS_INDEX).id("new1") + setDlsWriteBlocked(false); + try (RestHighLevelClient client = cluster.getRestHighLevelClient(DLS_USER)) { + IndexRequest request = new IndexRequest(DLS_INDEX).id("test1") .setRefreshPolicy(RefreshPolicy.IMMEDIATE) .source(Map.of("dept", "sales", "amount", 400)); @@ -114,8 +107,9 @@ public void testDlsUser_CanWrite_WhenSettingDisabled() throws IOException { @Test public void testDlsUser_CannotWrite_WhenSettingEnabled() throws IOException { - try (RestHighLevelClient client = clusterWithDlsWriteBlocked.getRestHighLevelClient(DLS_USER)) { - IndexRequest request = new IndexRequest(DLS_INDEX).id("new1") + setDlsWriteBlocked(true); + try (RestHighLevelClient client = cluster.getRestHighLevelClient(DLS_USER)) { + IndexRequest request = new IndexRequest(DLS_INDEX).id("test2") .setRefreshPolicy(RefreshPolicy.IMMEDIATE) .source(Map.of("dept", "sales", "amount", 400)); @@ -131,8 +125,9 @@ public void testDlsUser_CannotWrite_WhenSettingEnabled() throws IOException { @Test public void testFlsUser_CanWrite_WhenSettingDisabled() throws IOException { - try (RestHighLevelClient client = clusterWithoutDlsWriteBlocked.getRestHighLevelClient(FLS_USER)) { - IndexRequest request = new IndexRequest(FLS_INDEX).id("new1") + setDlsWriteBlocked(false); + try (RestHighLevelClient client = cluster.getRestHighLevelClient(FLS_USER)) { + IndexRequest request = new IndexRequest(FLS_INDEX).id("test3") .setRefreshPolicy(RefreshPolicy.IMMEDIATE) .source(Map.of("public", "new_data", "secret", "new_secret")); @@ -144,8 +139,9 @@ public void testFlsUser_CanWrite_WhenSettingDisabled() throws IOException { @Test public void testFlsUser_CannotWrite_WhenSettingEnabled() throws IOException { - try (RestHighLevelClient client = clusterWithDlsWriteBlocked.getRestHighLevelClient(FLS_USER)) { - IndexRequest request = new IndexRequest(FLS_INDEX).id("new1") + setDlsWriteBlocked(true); + try (RestHighLevelClient client = cluster.getRestHighLevelClient(FLS_USER)) { + IndexRequest request = new IndexRequest(FLS_INDEX).id("test4") .setRefreshPolicy(RefreshPolicy.IMMEDIATE) .source(Map.of("public", "new_data", "secret", "new_secret")); @@ -161,8 +157,9 @@ public void testFlsUser_CannotWrite_WhenSettingEnabled() throws IOException { @Test public void testAdminUser_CanWrite_WhenSettingEnabled() throws IOException { - try (RestHighLevelClient client = clusterWithDlsWriteBlocked.getRestHighLevelClient(ADMIN_USER)) { - IndexRequest request = new IndexRequest(DLS_INDEX).id("admin_doc") + setDlsWriteBlocked(true); + try (RestHighLevelClient client = cluster.getRestHighLevelClient(ADMIN_USER)) { + IndexRequest request = new IndexRequest(DLS_INDEX).id("test6") .setRefreshPolicy(RefreshPolicy.IMMEDIATE) .source(Map.of("dept", "admin", "amount", 999)); @@ -174,7 +171,8 @@ public void testAdminUser_CanWrite_WhenSettingEnabled() throws IOException { @Test public void testDlsUser_CanRead_WhenSettingEnabled() throws IOException { - try (RestHighLevelClient client = clusterWithDlsWriteBlocked.getRestHighLevelClient(DLS_USER)) { + setDlsWriteBlocked(true); + try (RestHighLevelClient client = cluster.getRestHighLevelClient(DLS_USER)) { var response = client.search(new org.opensearch.action.search.SearchRequest(DLS_INDEX), DEFAULT); assertThat(response.status().getStatus(), is(200)); From 6ffa2525a1d78d214aaf33c9f17fea2baa18cb77 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 2 Dec 2025 14:57:32 -0500 Subject: [PATCH 13/13] Use rest client Signed-off-by: Craig Perkins --- .../DlsWriteBlockedIntegrationTest.java | 97 ++++++------------- 1 file changed, 28 insertions(+), 69 deletions(-) diff --git a/src/integrationTest/java/org/opensearch/security/dlsfls/DlsWriteBlockedIntegrationTest.java b/src/integrationTest/java/org/opensearch/security/dlsfls/DlsWriteBlockedIntegrationTest.java index c4225e6ba1..c6468d6280 100644 --- a/src/integrationTest/java/org/opensearch/security/dlsfls/DlsWriteBlockedIntegrationTest.java +++ b/src/integrationTest/java/org/opensearch/security/dlsfls/DlsWriteBlockedIntegrationTest.java @@ -9,7 +9,6 @@ package org.opensearch.security.dlsfls; import java.io.IOException; -import java.util.Map; import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; import org.junit.BeforeClass; @@ -17,28 +16,18 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.opensearch.action.index.IndexRequest; -import org.opensearch.action.support.WriteRequest.RefreshPolicy; -import org.opensearch.client.RestHighLevelClient; import org.opensearch.security.support.ConfigConstants; import org.opensearch.test.framework.TestSecurityConfig.Role; import org.opensearch.test.framework.TestSecurityConfig.User; import org.opensearch.test.framework.cluster.ClusterManager; import org.opensearch.test.framework.cluster.LocalCluster; import org.opensearch.test.framework.cluster.TestRestClient; -import org.opensearch.transport.client.Client; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; -import static org.opensearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; -import static org.opensearch.client.RequestOptions.DEFAULT; -import static org.opensearch.core.rest.RestStatus.INTERNAL_SERVER_ERROR; import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL; import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS; -import static org.opensearch.test.framework.matcher.ExceptionMatcherAssert.assertThatThrownBy; -import static org.opensearch.test.framework.matcher.OpenSearchExceptionMatchers.errorMessageContain; -import static org.opensearch.test.framework.matcher.OpenSearchExceptionMatchers.statusException; /** * Integration tests for DLS_WRITE_BLOCKED setting which blocks write operations @@ -70,15 +59,11 @@ public class DlsWriteBlockedIntegrationTest { .build(); @BeforeClass - public static void createTestData() { - try (Client client = cluster.getInternalNodeClient()) { - client.index(new IndexRequest(DLS_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("dept", "sales", "amount", 100))) - .actionGet(); - client.index( - new IndexRequest(FLS_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("public", "data", "secret", "hidden")) - ).actionGet(); - client.index(new IndexRequest(NO_RESTRICTION_INDEX).id("1").setRefreshPolicy(IMMEDIATE).source(Map.of("data", "value1"))) - .actionGet(); + public static void createTestData() throws IOException { + try (TestRestClient client = cluster.getRestClient(ADMIN_USER)) { + client.putJson(DLS_INDEX + "/_doc/1?refresh=true", "{\"dept\":\"sales\",\"amount\":100}"); + client.putJson(FLS_INDEX + "/_doc/1?refresh=true", "{\"public\":\"data\",\"secret\":\"hidden\"}"); + client.putJson(NO_RESTRICTION_INDEX + "/_doc/1?refresh=true", "{\"data\":\"value1\"}"); } } @@ -94,88 +79,62 @@ private void setDlsWriteBlocked(boolean enabled) throws IOException { @Test public void testDlsUser_CanWrite_WhenSettingDisabled() throws IOException { setDlsWriteBlocked(false); - try (RestHighLevelClient client = cluster.getRestHighLevelClient(DLS_USER)) { - IndexRequest request = new IndexRequest(DLS_INDEX).id("test1") - .setRefreshPolicy(RefreshPolicy.IMMEDIATE) - .source(Map.of("dept", "sales", "amount", 400)); - - var response = client.index(request, DEFAULT); + try (TestRestClient client = cluster.getRestClient(DLS_USER)) { + var response = client.putJson(DLS_INDEX + "/_doc/test1?refresh=true", "{\"dept\":\"sales\",\"amount\":400}"); - assertThat(response.status().getStatus(), is(201)); + assertThat(response.getStatusCode(), is(201)); } } @Test public void testDlsUser_CannotWrite_WhenSettingEnabled() throws IOException { setDlsWriteBlocked(true); - try (RestHighLevelClient client = cluster.getRestHighLevelClient(DLS_USER)) { - IndexRequest request = new IndexRequest(DLS_INDEX).id("test2") - .setRefreshPolicy(RefreshPolicy.IMMEDIATE) - .source(Map.of("dept", "sales", "amount", 400)); - - assertThatThrownBy( - () -> client.index(request, DEFAULT), - allOf( - statusException(INTERNAL_SERVER_ERROR), - errorMessageContain("is not supported when FLS or DLS or Fieldmasking is activated") - ) - ); + try (TestRestClient client = cluster.getRestClient(DLS_USER)) { + var response = client.putJson(DLS_INDEX + "/_doc/test2?refresh=true", "{\"dept\":\"sales\",\"amount\":400}"); + + assertThat(response.getStatusCode(), is(500)); + assertThat(response.getBody(), containsString("is not supported when FLS or DLS or Fieldmasking is activated")); } } @Test public void testFlsUser_CanWrite_WhenSettingDisabled() throws IOException { setDlsWriteBlocked(false); - try (RestHighLevelClient client = cluster.getRestHighLevelClient(FLS_USER)) { - IndexRequest request = new IndexRequest(FLS_INDEX).id("test3") - .setRefreshPolicy(RefreshPolicy.IMMEDIATE) - .source(Map.of("public", "new_data", "secret", "new_secret")); - - var response = client.index(request, DEFAULT); + try (TestRestClient client = cluster.getRestClient(FLS_USER)) { + var response = client.putJson(FLS_INDEX + "/_doc/test3?refresh=true", "{\"public\":\"new_data\",\"secret\":\"new_secret\"}"); - assertThat(response.status().getStatus(), is(201)); + assertThat(response.getStatusCode(), is(201)); } } @Test public void testFlsUser_CannotWrite_WhenSettingEnabled() throws IOException { setDlsWriteBlocked(true); - try (RestHighLevelClient client = cluster.getRestHighLevelClient(FLS_USER)) { - IndexRequest request = new IndexRequest(FLS_INDEX).id("test4") - .setRefreshPolicy(RefreshPolicy.IMMEDIATE) - .source(Map.of("public", "new_data", "secret", "new_secret")); - - assertThatThrownBy( - () -> client.index(request, DEFAULT), - allOf( - statusException(INTERNAL_SERVER_ERROR), - errorMessageContain("is not supported when FLS or DLS or Fieldmasking is activated") - ) - ); + try (TestRestClient client = cluster.getRestClient(FLS_USER)) { + var response = client.putJson(FLS_INDEX + "/_doc/test4?refresh=true", "{\"public\":\"new_data\",\"secret\":\"new_secret\"}"); + + assertThat(response.getStatusCode(), is(500)); + assertThat(response.getBody(), containsString("is not supported when FLS or DLS or Fieldmasking is activated")); } } @Test public void testAdminUser_CanWrite_WhenSettingEnabled() throws IOException { setDlsWriteBlocked(true); - try (RestHighLevelClient client = cluster.getRestHighLevelClient(ADMIN_USER)) { - IndexRequest request = new IndexRequest(DLS_INDEX).id("test6") - .setRefreshPolicy(RefreshPolicy.IMMEDIATE) - .source(Map.of("dept", "admin", "amount", 999)); - - var response = client.index(request, DEFAULT); + try (TestRestClient client = cluster.getRestClient(ADMIN_USER)) { + var response = client.putJson(DLS_INDEX + "/_doc/test6?refresh=true", "{\"dept\":\"admin\",\"amount\":999}"); - assertThat(response.status().getStatus(), is(201)); + assertThat(response.getStatusCode(), is(201)); } } @Test public void testDlsUser_CanRead_WhenSettingEnabled() throws IOException { setDlsWriteBlocked(true); - try (RestHighLevelClient client = cluster.getRestHighLevelClient(DLS_USER)) { - var response = client.search(new org.opensearch.action.search.SearchRequest(DLS_INDEX), DEFAULT); + try (TestRestClient client = cluster.getRestClient(DLS_USER)) { + var response = client.get(DLS_INDEX + "/_search"); - assertThat(response.status().getStatus(), is(200)); + assertThat(response.getStatusCode(), is(200)); } } }