Skip to content

Commit 4af1d07

Browse files
authored
[2.x Backport] Optimized Privilege Evaluation: Action privileges ONLY, with feature flag (opensearch-project#4998)
Signed-off-by: Nils Bandener <[email protected]>
1 parent e7fabff commit 4af1d07

File tree

79 files changed

+12784
-1420
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+12784
-1420
lines changed

build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,10 @@ dependencies {
594594
implementation 'com.nimbusds:nimbus-jose-jwt:9.48'
595595
implementation 'com.rfksystems:blake2b:2.0.0'
596596
implementation 'com.password4j:password4j:1.8.2'
597+
598+
// Action privileges: check tables and compact collections
599+
implementation 'com.selectivem.collections:special-collections-complete:1.4.0'
600+
597601
//JWT
598602
implementation "io.jsonwebtoken:jjwt-api:${jjwt_version}"
599603
implementation "io.jsonwebtoken:jjwt-impl:${jjwt_version}"
@@ -747,6 +751,7 @@ dependencies {
747751
integrationTestImplementation "org.apache.httpcomponents:fluent-hc:4.5.14"
748752
integrationTestImplementation "org.apache.httpcomponents:httpcore:4.4.16"
749753
integrationTestImplementation "org.apache.httpcomponents:httpasyncclient:4.1.5"
754+
integrationTestImplementation "org.mockito:mockito-core:5.14.2"
750755

751756
//spotless
752757
implementation('com.google.googlejavaformat:google-java-format:1.25.2') {

src/integrationTest/java/org/opensearch/security/SnapshotSteps.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
import static java.util.Objects.requireNonNull;
3434
import static org.opensearch.client.RequestOptions.DEFAULT;
3535

36-
class SnapshotSteps {
36+
public class SnapshotSteps {
3737

3838
private final SnapshotClient snapshotClient;
3939

src/integrationTest/java/org/opensearch/security/legacy/DoNotFailOnForbiddenTests.java

Lines changed: 546 additions & 0 deletions
Large diffs are not rendered by default.

src/integrationTest/java/org/opensearch/security/legacy/PointInTimeOperationTest.java

Lines changed: 417 additions & 0 deletions
Large diffs are not rendered by default.

src/integrationTest/java/org/opensearch/security/legacy/SearchOperationTest.java

Lines changed: 2761 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*
8+
* Modifications Copyright OpenSearch Contributors. See
9+
* GitHub history for details.
10+
*/
11+
12+
package org.opensearch.security.legacy;
13+
14+
import java.util.Map;
15+
16+
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
17+
import org.apache.http.HttpStatus;
18+
import org.junit.ClassRule;
19+
import org.junit.Test;
20+
import org.junit.runner.RunWith;
21+
22+
import org.opensearch.security.privileges.PrivilegesEvaluator;
23+
import org.opensearch.test.framework.TestSecurityConfig;
24+
import org.opensearch.test.framework.TestSecurityConfig.Role;
25+
import org.opensearch.test.framework.cluster.ClusterManager;
26+
import org.opensearch.test.framework.cluster.LocalCluster;
27+
import org.opensearch.test.framework.cluster.TestRestClient;
28+
import org.opensearch.test.framework.cluster.TestRestClient.HttpResponse;
29+
30+
import static org.hamcrest.MatcherAssert.assertThat;
31+
import static org.hamcrest.Matchers.equalTo;
32+
import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL;
33+
34+
@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class)
35+
@ThreadLeakScope(ThreadLeakScope.Scope.NONE)
36+
public class SecurityRolesTests {
37+
38+
protected final static TestSecurityConfig.User USER_SR = new TestSecurityConfig.User("sr_user").roles(
39+
new Role("abc_ber").indexPermissions("*").on("*").clusterPermissions("*"),
40+
new Role("def_efg").indexPermissions("*").on("*").clusterPermissions("*")
41+
);
42+
43+
@ClassRule
44+
public static LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS)
45+
.anonymousAuth(true)
46+
.authc(AUTHC_HTTPBASIC_INTERNAL)
47+
.users(USER_SR)
48+
.nodeSettings(Map.of(PrivilegesEvaluator.USE_LEGACY_PRIVILEGE_EVALUATOR.getKey(), true))
49+
.build();
50+
51+
@Test
52+
public void testSecurityRoles() throws Exception {
53+
try (TestRestClient client = cluster.getRestClient(USER_SR)) {
54+
HttpResponse response = client.getAuthInfo();
55+
response.assertStatusCode(HttpStatus.SC_OK);
56+
57+
// Check username
58+
assertThat(response.getTextFromJsonBody("/user_name"), equalTo("sr_user"));
59+
60+
// Check security roles
61+
assertThat(response.getTextFromJsonBody("/roles/0"), equalTo("user_sr_user__abc_ber"));
62+
assertThat(response.getTextFromJsonBody("/roles/1"), equalTo("user_sr_user__def_efg"));
63+
64+
}
65+
}
66+
67+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* The OpenSearch Contributors require contributions made to
6+
* this file be licensed under the Apache-2.0 license or a
7+
* compatible open source license.
8+
*
9+
*/
10+
package org.opensearch.security.legacy;
11+
12+
import java.util.List;
13+
import java.util.Map;
14+
15+
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
16+
import org.junit.Before;
17+
import org.junit.ClassRule;
18+
import org.junit.Test;
19+
import org.junit.runner.RunWith;
20+
21+
import org.opensearch.core.rest.RestStatus;
22+
import org.opensearch.security.http.ExampleSystemIndexPlugin;
23+
import org.opensearch.security.privileges.PrivilegesEvaluator;
24+
import org.opensearch.test.framework.TestSecurityConfig.AuthcDomain;
25+
import org.opensearch.test.framework.cluster.ClusterManager;
26+
import org.opensearch.test.framework.cluster.LocalCluster;
27+
import org.opensearch.test.framework.cluster.TestRestClient;
28+
import org.opensearch.test.framework.cluster.TestRestClient.HttpResponse;
29+
30+
import static org.hamcrest.MatcherAssert.assertThat;
31+
import static org.hamcrest.Matchers.equalTo;
32+
import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ROLES_ENABLED;
33+
import static org.opensearch.security.support.ConfigConstants.SECURITY_SYSTEM_INDICES_ENABLED_KEY;
34+
import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS;
35+
import static org.opensearch.test.framework.TestSecurityConfig.User.USER_ADMIN;
36+
37+
@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class)
38+
@ThreadLeakScope(ThreadLeakScope.Scope.NONE)
39+
public class SystemIndexTests {
40+
41+
public static final AuthcDomain AUTHC_DOMAIN = new AuthcDomain("basic", 0).httpAuthenticatorWithChallenge("basic").backend("internal");
42+
43+
@ClassRule
44+
public static final LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE)
45+
.anonymousAuth(false)
46+
.authc(AUTHC_DOMAIN)
47+
.users(USER_ADMIN)
48+
.plugin(ExampleSystemIndexPlugin.class)
49+
.nodeSettings(
50+
Map.of(
51+
SECURITY_RESTAPI_ROLES_ENABLED,
52+
List.of("user_" + USER_ADMIN.getName() + "__" + ALL_ACCESS.getName()),
53+
SECURITY_SYSTEM_INDICES_ENABLED_KEY,
54+
true,
55+
PrivilegesEvaluator.USE_LEGACY_PRIVILEGE_EVALUATOR.getKey(),
56+
true
57+
)
58+
)
59+
.build();
60+
61+
@Before
62+
public void setup() {
63+
try (TestRestClient client = cluster.getRestClient(cluster.getAdminCertificate())) {
64+
client.delete(".system-index1");
65+
}
66+
}
67+
68+
@Test
69+
public void adminShouldNotBeAbleToDeleteSecurityIndex() {
70+
try (TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
71+
HttpResponse response = client.delete(".opendistro_security");
72+
73+
assertThat(response.getStatusCode(), equalTo(RestStatus.FORBIDDEN.getStatus()));
74+
75+
// Create regular index
76+
client.put("test-index");
77+
78+
// regular user can delete non-system index
79+
HttpResponse response2 = client.delete("test-index");
80+
81+
assertThat(response2.getStatusCode(), equalTo(RestStatus.OK.getStatus()));
82+
83+
// regular use can create system index
84+
HttpResponse response3 = client.put(".system-index1");
85+
86+
assertThat(response3.getStatusCode(), equalTo(RestStatus.OK.getStatus()));
87+
88+
// regular user cannot delete system index
89+
HttpResponse response4 = client.delete(".system-index1");
90+
91+
assertThat(response4.getStatusCode(), equalTo(RestStatus.FORBIDDEN.getStatus()));
92+
}
93+
}
94+
95+
@Test
96+
public void regularUserShouldGetNoResultsWhenSearchingSystemIndex() {
97+
// Create system index and index a dummy document as the super admin user, data returned to super admin
98+
try (TestRestClient client = cluster.getRestClient(cluster.getAdminCertificate())) {
99+
HttpResponse response1 = client.put(".system-index1");
100+
101+
assertThat(response1.getStatusCode(), equalTo(RestStatus.OK.getStatus()));
102+
String doc = "{\"field\":\"value\"}";
103+
HttpResponse adminPostResponse = client.postJson(".system-index1/_doc/1?refresh=true", doc);
104+
assertThat(adminPostResponse.getStatusCode(), equalTo(RestStatus.CREATED.getStatus()));
105+
HttpResponse response2 = client.get(".system-index1/_search");
106+
107+
assertThat(response2.getStatusCode(), equalTo(RestStatus.OK.getStatus()));
108+
assertThat(response2.getBody(), response2.getBody().contains("\"hits\":{\"total\":{\"value\":1,\"relation\":\"eq\"}"));
109+
}
110+
111+
// Regular users should not be able to read it
112+
try (TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
113+
// regular user cannot read system index
114+
HttpResponse response1 = client.get(".system-index1/_search");
115+
116+
assertThat(response1.getBody(), response1.getBody().contains("\"hits\":{\"total\":{\"value\":0,\"relation\":\"eq\"}"));
117+
}
118+
}
119+
}

0 commit comments

Comments
 (0)