Skip to content

Commit 07e79e3

Browse files
authored
The org.opensearch.bootstrap.Security should support codebase for JAR files with classifiers (#12586)
Signed-off-by: Andriy Redko <andriy.redko@aiven.io>
1 parent dc29e17 commit 07e79e3

File tree

5 files changed

+116
-17
lines changed

5 files changed

+116
-17
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
106106
- Add shard id property to SearchLookup for use in field types provided by plugins ([#1063](https://github.com/opensearch-project/OpenSearch/pull/1063))
107107
- [Tiered caching] Make IndicesRequestCache implementation configurable [EXPERIMENTAL] ([#12533](https://github.com/opensearch-project/OpenSearch/pull/12533))
108108
- Add kuromoji_completion analyzer and filter ([#4835](https://github.com/opensearch-project/OpenSearch/issues/4835))
109+
- The org.opensearch.bootstrap.Security should support codebase for JAR files with classifiers ([#12586](https://github.com/opensearch-project/OpenSearch/issues/12586))
109110

110111
### Dependencies
111112
- Bump `peter-evans/find-comment` from 2 to 3 ([#12288](https://github.com/opensearch-project/OpenSearch/pull/12288))

server/src/main/java/org/opensearch/bootstrap/Security.java

+54-17
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@
6666
import java.util.List;
6767
import java.util.Map;
6868
import java.util.Set;
69+
import java.util.regex.Matcher;
70+
import java.util.regex.Pattern;
6971

7072
import static org.opensearch.bootstrap.FilePermissionUtils.addDirectoryPath;
7173
import static org.opensearch.bootstrap.FilePermissionUtils.addSingleFilePath;
@@ -121,6 +123,8 @@
121123
*/
122124
@SuppressWarnings("removal")
123125
final class Security {
126+
private static final Pattern CODEBASE_JAR_WITH_CLASSIFIER = Pattern.compile("^(.+)-\\d+\\.\\d+[^-]*.*?[-]?([^-]+)?\\.jar$");
127+
124128
/** no instantiation */
125129
private Security() {}
126130

@@ -231,33 +235,45 @@ static Policy readPolicy(URL policyFile, Map<String, URL> codebases) {
231235
try {
232236
List<String> propertiesSet = new ArrayList<>();
233237
try {
238+
final Map<Map.Entry<String, URL>, String> jarsWithPossibleClassifiers = new HashMap<>();
234239
// set codebase properties
235240
for (Map.Entry<String, URL> codebase : codebases.entrySet()) {
236-
String name = codebase.getKey();
237-
URL url = codebase.getValue();
241+
final String name = codebase.getKey();
242+
final URL url = codebase.getValue();
238243

239244
// We attempt to use a versionless identifier for each codebase. This assumes a specific version
240245
// format in the jar filename. While we cannot ensure all jars in all plugins use this format, nonconformity
241246
// only means policy grants would need to include the entire jar filename as they always have before.
247+
final Matcher matcher = CODEBASE_JAR_WITH_CLASSIFIER.matcher(name);
248+
if (matcher.matches() && matcher.group(2) != null) {
249+
// There is a JAR that, possibly, has a classifier or SNAPSHOT at the end, examples are:
250+
// - netty-tcnative-boringssl-static-2.0.61.Final-linux-x86_64.jar
251+
// - kafka-server-common-3.6.1-test.jar
252+
// - lucene-core-9.11.0-snapshot-8a555eb.jar
253+
// - zstd-jni-1.5.5-5.jar
254+
jarsWithPossibleClassifiers.put(codebase, matcher.group(2));
255+
} else {
256+
String property = "codebase." + name;
257+
String aliasProperty = "codebase." + name.replaceFirst("-\\d+\\.\\d+.*\\.jar", "");
258+
addCodebaseToSystemProperties(propertiesSet, url, property, aliasProperty);
259+
}
260+
}
261+
262+
// set codebase properties for JARs that might present with classifiers
263+
for (Map.Entry<Map.Entry<String, URL>, String> jarWithPossibleClassifier : jarsWithPossibleClassifiers.entrySet()) {
264+
final Map.Entry<String, URL> codebase = jarWithPossibleClassifier.getKey();
265+
final String name = codebase.getKey();
266+
final URL url = codebase.getValue();
267+
242268
String property = "codebase." + name;
243269
String aliasProperty = "codebase." + name.replaceFirst("-\\d+\\.\\d+.*\\.jar", "");
244-
if (aliasProperty.equals(property) == false) {
245-
propertiesSet.add(aliasProperty);
246-
String previous = System.setProperty(aliasProperty, url.toString());
247-
if (previous != null) {
248-
throw new IllegalStateException(
249-
"codebase property already set: " + aliasProperty + " -> " + previous + ", cannot set to " + url.toString()
250-
);
251-
}
252-
}
253-
propertiesSet.add(property);
254-
String previous = System.setProperty(property, url.toString());
255-
if (previous != null) {
256-
throw new IllegalStateException(
257-
"codebase property already set: " + property + " -> " + previous + ", cannot set to " + url.toString()
258-
);
270+
if (System.getProperties().containsKey(aliasProperty)) {
271+
aliasProperty = aliasProperty + "@" + jarWithPossibleClassifier.getValue();
259272
}
273+
274+
addCodebaseToSystemProperties(propertiesSet, url, property, aliasProperty);
260275
}
276+
261277
return Policy.getInstance("JavaPolicy", new URIParameter(policyFile.toURI()));
262278
} finally {
263279
// clear codebase properties
@@ -270,6 +286,27 @@ static Policy readPolicy(URL policyFile, Map<String, URL> codebases) {
270286
}
271287
}
272288

289+
/** adds the codebase to properties and System properties */
290+
@SuppressForbidden(reason = "accesses System properties to configure codebases")
291+
private static void addCodebaseToSystemProperties(List<String> propertiesSet, final URL url, String property, String aliasProperty) {
292+
if (aliasProperty.equals(property) == false) {
293+
propertiesSet.add(aliasProperty);
294+
String previous = System.setProperty(aliasProperty, url.toString());
295+
if (previous != null) {
296+
throw new IllegalStateException(
297+
"codebase property already set: " + aliasProperty + " -> " + previous + ", cannot set to " + url.toString()
298+
);
299+
}
300+
}
301+
propertiesSet.add(property);
302+
String previous = System.setProperty(property, url.toString());
303+
if (previous != null) {
304+
throw new IllegalStateException(
305+
"codebase property already set: " + property + " -> " + previous + ", cannot set to " + url.toString()
306+
);
307+
}
308+
}
309+
273310
/** returns dynamic Permissions to configured paths and bind ports */
274311
static Permissions createPermissions(Environment environment) throws IOException {
275312
Permissions policy = new Permissions();

server/src/test/java/org/opensearch/bootstrap/SecurityTests.java

+23
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@
3535
import org.opensearch.test.OpenSearchTestCase;
3636

3737
import java.io.IOException;
38+
import java.net.URL;
3839
import java.nio.file.Files;
3940
import java.nio.file.Path;
41+
import java.security.AccessController;
42+
import java.security.PrivilegedAction;
43+
import java.util.Map;
4044

4145
public class SecurityTests extends OpenSearchTestCase {
4246

@@ -80,4 +84,23 @@ public void testProcessExecution() throws Exception {
8084
fail("didn't get expected exception");
8185
} catch (SecurityException expected) {}
8286
}
87+
88+
public void testReadPolicyWithCodebases() throws IOException {
89+
final Map<String, URL> codebases = Map.of(
90+
"test-netty-tcnative-boringssl-static-2.0.61.Final-linux-x86_64.jar",
91+
new URL("file://test-netty-tcnative-boringssl-static-2.0.61.Final-linux-x86_64.jar"),
92+
"test-kafka-server-common-3.6.1.jar",
93+
new URL("file://test-kafka-server-common-3.6.1.jar"),
94+
"test-kafka-server-common-3.6.1-test.jar",
95+
new URL("file://test-kafka-server-common-3.6.1-test.jar"),
96+
"test-lucene-core-9.11.0-snapshot-8a555eb.jar",
97+
new URL("file://test-lucene-core-9.11.0-snapshot-8a555eb.jar"),
98+
"test-zstd-jni-1.5.5-5.jar",
99+
new URL("file://test-zstd-jni-1.5.5-5.jar")
100+
);
101+
102+
AccessController.doPrivileged(
103+
(PrivilegedAction<?>) () -> Security.readPolicy(SecurityTests.class.getResource("test-codebases.policy"), codebases)
104+
);
105+
}
83106
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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+
9+
/*
10+
* Modifications Copyright OpenSearch Contributors. See
11+
* GitHub history for details.
12+
*/
13+
14+
//// additional test framework permissions.
15+
//// These are mock objects and test management that we allow test framework libs
16+
//// to provide on our behalf. But tests themselves cannot do this stuff!
17+
18+
grant codeBase "${codebase.zstd-jni}" {
19+
};
20+
21+
grant codeBase "${codebase.kafka-server-common}" {
22+
};
23+
24+
grant codeBase "${codebase.kafka-server-common@test}" {
25+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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+
9+
grant {
10+
// allow to test Security policy and codebases
11+
permission java.util.PropertyPermission "*", "read,write";
12+
permission java.security.SecurityPermission "createPolicy.JavaPolicy";
13+
};

0 commit comments

Comments
 (0)