From f1c80796c01580dc10407de4095b782f038ff9f5 Mon Sep 17 00:00:00 2001 From: Andrew Ross Date: Wed, 26 Mar 2025 12:20:39 -0700 Subject: [PATCH 1/2] Revert "Add simple PolicyParser unit test (#17690)" This reverts commit 3fb09c770a4359a90d0cc7e88b64c898101fd6c0. Signed-off-by: Andrew Ross --- libs/agent-sm/agent-policy/build.gradle | 5 +- .../secure_sm/policy/PolicyParserTests.java | 53 ------------------- 2 files changed, 2 insertions(+), 56 deletions(-) delete mode 100644 libs/agent-sm/agent-policy/src/test/java/org/opensearch/secure_sm/policy/PolicyParserTests.java diff --git a/libs/agent-sm/agent-policy/build.gradle b/libs/agent-sm/agent-policy/build.gradle index a44c2c1349909..997ed5ddf174b 100644 --- a/libs/agent-sm/agent-policy/build.gradle +++ b/libs/agent-sm/agent-policy/build.gradle @@ -22,6 +22,5 @@ base { disableTasks('forbiddenApisMain') -dependencies { - testImplementation(project(":test:framework")) -} +test.enabled = false +testingConventions.enabled = false diff --git a/libs/agent-sm/agent-policy/src/test/java/org/opensearch/secure_sm/policy/PolicyParserTests.java b/libs/agent-sm/agent-policy/src/test/java/org/opensearch/secure_sm/policy/PolicyParserTests.java deleted file mode 100644 index 098e4c2605a95..0000000000000 --- a/libs/agent-sm/agent-policy/src/test/java/org/opensearch/secure_sm/policy/PolicyParserTests.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.secure_sm.policy; - -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.util.Enumeration; - -public class PolicyParserTests extends OpenSearchTestCase { - private static final String POLICY = """ - grant codeBase "TestCodeBase" { - permission java.net.NetPermission "accessUnixDomainSocket"; - }; - - grant { - permission java.net.NetPermission "accessUnixDomainSocket"; - permission java.net.SocketPermission "*", "accept,connect"; - }; - """; - - public void testPolicy() throws IOException, PolicyParser.ParsingException { - try (Reader reader = new StringReader(POLICY)) { - final PolicyParser policyParser = new PolicyParser(); - policyParser.read(reader); - - final Enumeration grantEntryEnumeration = policyParser.grantElements(); - final PolicyParser.GrantEntry grantEntry1 = grantEntryEnumeration.nextElement(); - final PolicyParser.GrantEntry grantEntry2 = grantEntryEnumeration.nextElement(); - - assertEquals("TestCodeBase", grantEntry1.codeBase); - assertEquals(1, grantEntry1.permissionEntries.size()); - assertEquals("java.net.NetPermission", grantEntry1.permissionEntries.getFirst().permission); - assertEquals("accessUnixDomainSocket", grantEntry1.permissionEntries.getFirst().name); - - assertNull(grantEntry2.codeBase); - assertEquals(2, grantEntry2.permissionEntries.size()); - assertEquals("java.net.NetPermission", grantEntry2.permissionEntries.getFirst().permission); - assertEquals("accessUnixDomainSocket", grantEntry2.permissionEntries.getFirst().name); - assertEquals("java.net.SocketPermission", grantEntry2.permissionEntries.getLast().permission); - assertEquals("*", grantEntry2.permissionEntries.getLast().name); - assertEquals("accept,connect", grantEntry2.permissionEntries.getLast().action); - } - } -} From a7ff41e3a2cd6e5747aa445ffc0fc0703178aaba Mon Sep 17 00:00:00 2001 From: Andrew Ross Date: Wed, 26 Mar 2025 12:20:41 -0700 Subject: [PATCH 2/2] Revert "Add support of Java policies (#17663)" This reverts commit 17289b7685e72425e13051b1169518cdcafc4600. Signed-off-by: Andrew Ross --- CHANGELOG.md | 1 - gradle/missing-javadoc.gradle | 1 - libs/agent-sm/agent-policy/build.gradle | 26 - .../java/org/opensearch/package-info.java | 12 - .../secure_sm/policy/ParseUtil.java | 616 ------- .../opensearch/secure_sm/policy/Password.java | 173 -- .../secure_sm/policy/PolicyFile.java | 1601 ----------------- .../secure_sm/policy/PolicyParser.java | 1163 ------------ .../secure_sm/policy/PolicyUtil.java | 170 -- .../secure_sm/policy/PropertyExpander.java | 133 -- .../secure_sm/policy/SecurityConstants.java | 145 -- .../secure_sm/policy/package-info.java | 12 - libs/agent-sm/bootstrap/build.gradle | 24 - .../javaagent/bootstrap/AgentPolicy.java | 89 - .../javaagent/bootstrap/package-info.java | 12 - .../java/org/opensearch/package-info.java | 12 - libs/agent-sm/build.gradle | 22 - 17 files changed, 4212 deletions(-) delete mode 100644 libs/agent-sm/agent-policy/build.gradle delete mode 100644 libs/agent-sm/agent-policy/src/main/java/org/opensearch/package-info.java delete mode 100644 libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/ParseUtil.java delete mode 100644 libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/Password.java delete mode 100644 libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PolicyFile.java delete mode 100644 libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PolicyParser.java delete mode 100644 libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PolicyUtil.java delete mode 100644 libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PropertyExpander.java delete mode 100644 libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/SecurityConstants.java delete mode 100644 libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/package-info.java delete mode 100644 libs/agent-sm/bootstrap/build.gradle delete mode 100644 libs/agent-sm/bootstrap/src/main/java/org/opensearch/javaagent/bootstrap/AgentPolicy.java delete mode 100644 libs/agent-sm/bootstrap/src/main/java/org/opensearch/javaagent/bootstrap/package-info.java delete mode 100644 libs/agent-sm/bootstrap/src/main/java/org/opensearch/package-info.java delete mode 100644 libs/agent-sm/build.gradle diff --git a/CHANGELOG.md b/CHANGELOG.md index 27c39896ab8c5..c96ddf75e3282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Introduce a new search node role to hold search only shards ([#17620](https://github.com/opensearch-project/OpenSearch/pull/17620)) - Fix systemd integTest on deb regarding path ownership check ([#17641](https://github.com/opensearch-project/OpenSearch/pull/17641)) - Add dfs transformation function in XContentMapValues ([#17612](https://github.com/opensearch-project/OpenSearch/pull/17612)) -- [Security Manager Replacement] Add support of Java policies ([#17663](https://github.com/opensearch-project/OpenSearch/pull/17663)) - Added Kinesis support as a plugin for the pull-based ingestion ([#17615](https://github.com/opensearch-project/OpenSearch/pull/17615) ### Changed diff --git a/gradle/missing-javadoc.gradle b/gradle/missing-javadoc.gradle index 9f27dc5cadcd2..6e31f838e678a 100644 --- a/gradle/missing-javadoc.gradle +++ b/gradle/missing-javadoc.gradle @@ -106,7 +106,6 @@ configure([ project(":libs:opensearch-secure-sm"), project(":libs:opensearch-ssl-config"), project(":libs:opensearch-x-content"), - project(":libs:agent-sm:agent-policy"), project(":modules:aggs-matrix-stats"), project(":modules:analysis-common"), project(":modules:geo"), diff --git a/libs/agent-sm/agent-policy/build.gradle b/libs/agent-sm/agent-policy/build.gradle deleted file mode 100644 index 997ed5ddf174b..0000000000000 --- a/libs/agent-sm/agent-policy/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -apply plugin: 'opensearch.build' -apply plugin: 'opensearch.publish' - -ext { - failOnJavadocWarning = false -} - -base { - archivesName = 'opensearch-agent-policy' -} - -disableTasks('forbiddenApisMain') - -test.enabled = false -testingConventions.enabled = false diff --git a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/package-info.java b/libs/agent-sm/agent-policy/src/main/java/org/opensearch/package-info.java deleted file mode 100644 index 0724b60d1777f..0000000000000 --- a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/package-info.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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. - */ - -/** - * Java Agent Policy - */ -package org.opensearch; diff --git a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/ParseUtil.java b/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/ParseUtil.java deleted file mode 100644 index d4477fa13fdcd..0000000000000 --- a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/ParseUtil.java +++ /dev/null @@ -1,616 +0,0 @@ -/* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * 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.secure_sm.policy; - -import java.io.File; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; -import java.nio.charset.StandardCharsets; -import java.util.HexFormat; - -/** - * Adapted from: https://github.com/openjdk/jdk23u/blob/master/src/java.base/share/classes/sun/net/www/ParseUtil.java - */ -public final class ParseUtil { - - private static final HexFormat HEX_UPPERCASE = HexFormat.of().withUpperCase(); - - private ParseUtil() {} - - /** - * Constructs an encoded version of the specified path string suitable - * for use in the construction of a URL. - * - * A path separator is replaced by a forward slash. The string is UTF8 - * encoded. The % escape sequence is used for characters that are above - * 0x7F or those defined in RFC2396 as reserved or excluded in the path - * component of a URL. - */ - public static String encodePath(String path) { - return encodePath(path, true); - } - - /* - * flag indicates whether path uses platform dependent - * File.separatorChar or not. True indicates path uses platform - * dependent File.separatorChar. - */ - public static String encodePath(String path, boolean flag) { - if (flag && File.separatorChar != '/') { - return encodePath(path, 0, File.separatorChar); - } else { - int index = firstEncodeIndex(path); - if (index > -1) { - return encodePath(path, index, '/'); - } else { - return path; - } - } - } - - private static int firstEncodeIndex(String path) { - int len = path.length(); - for (int i = 0; i < len; i++) { - char c = path.charAt(i); - // Ordering in the following test is performance sensitive, - // and typically paths have most chars in the a-z range, then - // in the symbol range '&'-':' (includes '.', '/' and '0'-'9') - // and more rarely in the A-Z range. - if (c >= 'a' && c <= 'z' || c >= '&' && c <= ':' || c >= 'A' && c <= 'Z') { - continue; - } else if (c > 0x007F || match(c, L_ENCODED, H_ENCODED)) { - return i; - } - } - return -1; - } - - private static String encodePath(String path, int index, char sep) { - char[] pathCC = path.toCharArray(); - char[] retCC = new char[pathCC.length * 2 + 16 - index]; - if (index > 0) { - System.arraycopy(pathCC, 0, retCC, 0, index); - } - int retLen = index; - - for (int i = index; i < pathCC.length; i++) { - char c = pathCC[i]; - if (c == sep) retCC[retLen++] = '/'; - else { - if (c <= 0x007F) { - if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9') { - retCC[retLen++] = c; - } else if (match(c, L_ENCODED, H_ENCODED)) { - retLen = escape(retCC, c, retLen); - } else { - retCC[retLen++] = c; - } - } else if (c > 0x07FF) { - retLen = escape(retCC, (char) (0xE0 | ((c >> 12) & 0x0F)), retLen); - retLen = escape(retCC, (char) (0x80 | ((c >> 6) & 0x3F)), retLen); - retLen = escape(retCC, (char) (0x80 | ((c >> 0) & 0x3F)), retLen); - } else { - retLen = escape(retCC, (char) (0xC0 | ((c >> 6) & 0x1F)), retLen); - retLen = escape(retCC, (char) (0x80 | ((c >> 0) & 0x3F)), retLen); - } - } - // worst case scenario for character [0x7ff-] every single - // character will be encoded into 9 characters. - if (retLen + 9 > retCC.length) { - int newLen = retCC.length * 2 + 16; - if (newLen < 0) { - newLen = Integer.MAX_VALUE; - } - char[] buf = new char[newLen]; - System.arraycopy(retCC, 0, buf, 0, retLen); - retCC = buf; - } - } - return new String(retCC, 0, retLen); - } - - /** - * Appends the URL escape sequence for the specified char to the - * specified character array. - */ - private static int escape(char[] cc, char c, int index) { - cc[index++] = '%'; - cc[index++] = Character.forDigit((c >> 4) & 0xF, 16); - cc[index++] = Character.forDigit(c & 0xF, 16); - return index; - } - - /** - * Un-escape and return the character at position i in string s. - */ - private static byte unescape(String s, int i) { - return (byte) Integer.parseInt(s, i + 1, i + 3, 16); - } - - /** - * Returns a new String constructed from the specified String by replacing - * the URL escape sequences and UTF8 encoding with the characters they - * represent. - */ - public static String decode(String s) { - int n = s.length(); - if ((n == 0) || (s.indexOf('%') < 0)) return s; - - StringBuilder sb = new StringBuilder(n); - ByteBuffer bb = ByteBuffer.allocate(n); - CharBuffer cb = CharBuffer.allocate(n); - CharsetDecoder dec = StandardCharsets.UTF_8.newDecoder() - .onMalformedInput(CodingErrorAction.REPORT) - .onUnmappableCharacter(CodingErrorAction.REPORT); - - char c = s.charAt(0); - for (int i = 0; i < n;) { - assert c == s.charAt(i); - if (c != '%') { - sb.append(c); - if (++i >= n) break; - c = s.charAt(i); - continue; - } - bb.clear(); - for (;;) { - if (n - i < 2) { - throw new IllegalArgumentException("Malformed escape pair: " + s); - } - - try { - bb.put(unescape(s, i)); - } catch (NumberFormatException | IndexOutOfBoundsException e) { - throw new IllegalArgumentException("Malformed escape pair: " + s); - } - i += 3; - if (i >= n) break; - c = s.charAt(i); - if (c != '%') break; - } - bb.flip(); - cb.clear(); - dec.reset(); - CoderResult cr = dec.decode(bb, cb, true); - if (cr.isError()) throw new IllegalArgumentException("Error decoding percent encoded characters"); - cr = dec.flush(cb); - if (cr.isError()) throw new IllegalArgumentException("Error decoding percent encoded characters"); - sb.append(cb.flip().toString()); - } - - return sb.toString(); - } - - public static URL fileToEncodedURL(File file) throws MalformedURLException { - String path = file.getAbsolutePath(); - path = ParseUtil.encodePath(path); - if (!path.startsWith("/")) { - path = "/" + path; - } - if (!path.endsWith("/") && file.isDirectory()) { - path = path + "/"; - } - @SuppressWarnings("deprecation") - var result = new URL("file", "", path); - return result; - } - - public static java.net.URI toURI(URL url) { - String protocol = url.getProtocol(); - String auth = url.getAuthority(); - String path = url.getPath(); - String query = url.getQuery(); - String ref = url.getRef(); - if (path != null && !(path.startsWith("/"))) path = "/" + path; - - // - // In java.net.URI class, a port number of -1 implies the default - // port number. So get it stripped off before creating URI instance. - // - if (auth != null && auth.endsWith(":-1")) auth = auth.substring(0, auth.length() - 3); - - java.net.URI uri; - try { - uri = createURI(protocol, auth, path, query, ref); - } catch (java.net.URISyntaxException e) { - uri = null; - } - return uri; - } - - // - // createURI() and its auxiliary code are cloned from java.net.URI. - // Most of the code are just copy and paste, except that quote() - // has been modified to avoid double-escape. - // - // Usually it is unacceptable, but we're forced to do it because - // otherwise we need to change public API, namely java.net.URI's - // multi-argument constructors. It turns out that the changes cause - // incompatibilities so can't be done. - // - private static URI createURI(String scheme, String authority, String path, String query, String fragment) throws URISyntaxException { - String s = toString(scheme, null, authority, null, null, -1, path, query, fragment); - checkPath(s, scheme, path); - return new URI(s); - } - - private static String toString( - String scheme, - String opaquePart, - String authority, - String userInfo, - String host, - int port, - String path, - String query, - String fragment - ) { - StringBuilder sb = new StringBuilder(); - if (scheme != null) { - sb.append(scheme); - sb.append(':'); - } - appendSchemeSpecificPart(sb, opaquePart, authority, userInfo, host, port, path, query); - appendFragment(sb, fragment); - return sb.toString(); - } - - private static void appendSchemeSpecificPart( - StringBuilder sb, - String opaquePart, - String authority, - String userInfo, - String host, - int port, - String path, - String query - ) { - if (opaquePart != null) { - /* check if SSP begins with an IPv6 address - * because we must not quote a literal IPv6 address - */ - if (opaquePart.startsWith("//[")) { - int end = opaquePart.indexOf(']'); - if (end != -1 && opaquePart.indexOf(':') != -1) { - String doquote, dontquote; - if (end == opaquePart.length()) { - dontquote = opaquePart; - doquote = ""; - } else { - dontquote = opaquePart.substring(0, end + 1); - doquote = opaquePart.substring(end + 1); - } - sb.append(dontquote); - sb.append(quote(doquote, L_URIC, H_URIC)); - } - } else { - sb.append(quote(opaquePart, L_URIC, H_URIC)); - } - } else { - appendAuthority(sb, authority, userInfo, host, port); - if (path != null) sb.append(quote(path, L_PATH, H_PATH)); - if (query != null) { - sb.append('?'); - sb.append(quote(query, L_URIC, H_URIC)); - } - } - } - - private static void appendAuthority(StringBuilder sb, String authority, String userInfo, String host, int port) { - if (host != null) { - sb.append("//"); - if (userInfo != null) { - sb.append(quote(userInfo, L_USERINFO, H_USERINFO)); - sb.append('@'); - } - boolean needBrackets = ((host.indexOf(':') >= 0) && !host.startsWith("[") && !host.endsWith("]")); - if (needBrackets) sb.append('['); - sb.append(host); - if (needBrackets) sb.append(']'); - if (port != -1) { - sb.append(':'); - sb.append(port); - } - } else if (authority != null) { - sb.append("//"); - if (authority.startsWith("[")) { - int end = authority.indexOf(']'); - if (end != -1 && authority.indexOf(':') != -1) { - String doquote, dontquote; - if (end == authority.length()) { - dontquote = authority; - doquote = ""; - } else { - dontquote = authority.substring(0, end + 1); - doquote = authority.substring(end + 1); - } - sb.append(dontquote); - sb.append(quote(doquote, L_REG_NAME | L_SERVER, H_REG_NAME | H_SERVER)); - } - } else { - sb.append(quote(authority, L_REG_NAME | L_SERVER, H_REG_NAME | H_SERVER)); - } - } - } - - private static void appendFragment(StringBuilder sb, String fragment) { - if (fragment != null) { - sb.append('#'); - sb.append(quote(fragment, L_URIC, H_URIC)); - } - } - - // Quote any characters in s that are not permitted - // by the given mask pair - // - private static String quote(String s, long lowMask, long highMask) { - int n = s.length(); - StringBuilder sb = null; - CharsetEncoder encoder = null; - boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0); - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (c < '\u0080') { - if (!match(c, lowMask, highMask) && !isEscaped(s, i)) { - if (sb == null) { - sb = new StringBuilder(); - sb.append(s, 0, i); - } - appendEscape(sb, (byte) c); - } else { - if (sb != null) sb.append(c); - } - } else if (allowNonASCII && (Character.isSpaceChar(c) || Character.isISOControl(c))) { - if (encoder == null) { - encoder = StandardCharsets.UTF_8.newEncoder(); - } - if (sb == null) { - sb = new StringBuilder(); - sb.append(s, 0, i); - } - appendEncoded(encoder, sb, c); - } else { - if (sb != null) sb.append(c); - } - } - return (sb == null) ? s : sb.toString(); - } - - // - // To check if the given string has an escaped triplet - // at the given position - // - private static boolean isEscaped(String s, int pos) { - if (s == null || (s.length() <= (pos + 2))) return false; - - return s.charAt(pos) == '%' && match(s.charAt(pos + 1), L_HEX, H_HEX) && match(s.charAt(pos + 2), L_HEX, H_HEX); - } - - private static void appendEncoded(CharsetEncoder encoder, StringBuilder sb, char c) { - ByteBuffer bb = null; - try { - bb = encoder.encode(CharBuffer.wrap("" + c)); - } catch (CharacterCodingException x) { - assert false; - } - while (bb.hasRemaining()) { - int b = bb.get() & 0xff; - if (b >= 0x80) appendEscape(sb, (byte) b); - else sb.append((char) b); - } - } - - private static void appendEscape(StringBuilder sb, byte b) { - sb.append('%'); - HEX_UPPERCASE.toHexDigits(sb, b); - } - - // Tell whether the given character is permitted by the given mask pair - private static boolean match(char c, long lowMask, long highMask) { - if (c < 64) return ((1L << c) & lowMask) != 0; - if (c < 128) return ((1L << (c - 64)) & highMask) != 0; - return false; - } - - // If a scheme is given then the path, if given, must be absolute - // - private static void checkPath(String s, String scheme, String path) throws URISyntaxException { - if (scheme != null) { - if (path != null && !path.isEmpty() && path.charAt(0) != '/') throw new URISyntaxException(s, "Relative path in absolute URI"); - } - } - - // -- Character classes for parsing -- - - // To save startup time, we manually calculate the low-/highMask constants. - // For reference, the following methods were used to calculate the values: - - // Compute a low-order mask for the characters - // between first and last, inclusive - // private static long lowMask(char first, char last) { - // long m = 0; - // int f = Math.max(Math.min(first, 63), 0); - // int l = Math.max(Math.min(last, 63), 0); - // for (int i = f; i <= l; i++) - // m |= 1L << i; - // return m; - // } - - // Compute the low-order mask for the characters in the given string - // private static long lowMask(String chars) { - // int n = chars.length(); - // long m = 0; - // for (int i = 0; i < n; i++) { - // char c = chars.charAt(i); - // if (c < 64) - // m |= (1L << c); - // } - // return m; - // } - - // Compute a high-order mask for the characters - // between first and last, inclusive - // private static long highMask(char first, char last) { - // long m = 0; - // int f = Math.max(Math.min(first, 127), 64) - 64; - // int l = Math.max(Math.min(last, 127), 64) - 64; - // for (int i = f; i <= l; i++) - // m |= 1L << i; - // return m; - // } - - // Compute the high-order mask for the characters in the given string - // private static long highMask(String chars) { - // int n = chars.length(); - // long m = 0; - // for (int i = 0; i < n; i++) { - // char c = chars.charAt(i); - // if ((c >= 64) && (c < 128)) - // m |= (1L << (c - 64)); - // } - // return m; - // } - - // Character-class masks - - // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | - // "8" | "9" - private static final long L_DIGIT = 0x3FF000000000000L; // lowMask('0', '9'); - private static final long H_DIGIT = 0L; - - // hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | - // "a" | "b" | "c" | "d" | "e" | "f" - private static final long L_HEX = L_DIGIT; - private static final long H_HEX = 0x7E0000007EL; // highMask('A', 'F') | highMask('a', 'f'); - - // upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | - // "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | - // "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" - private static final long L_UPALPHA = 0L; - private static final long H_UPALPHA = 0x7FFFFFEL; // highMask('A', 'Z'); - - // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | - // "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | - // "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" - private static final long L_LOWALPHA = 0L; - private static final long H_LOWALPHA = 0x7FFFFFE00000000L; // highMask('a', 'z'); - - // alpha = lowalpha | upalpha - private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA; - private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA; - - // alphanum = alpha | digit - private static final long L_ALPHANUM = L_DIGIT | L_ALPHA; - private static final long H_ALPHANUM = H_DIGIT | H_ALPHA; - - // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | - // "(" | ")" - private static final long L_MARK = 0x678200000000L; // lowMask("-_.!~*'()"); - private static final long H_MARK = 0x4000000080000000L; // highMask("-_.!~*'()"); - - // unreserved = alphanum | mark - private static final long L_UNRESERVED = L_ALPHANUM | L_MARK; - private static final long H_UNRESERVED = H_ALPHANUM | H_MARK; - - // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | - // "$" | "," | "[" | "]" - // Added per RFC2732: "[", "]" - private static final long L_RESERVED = 0xAC00985000000000L; // lowMask(";/?:@&=+$,[]"); - private static final long H_RESERVED = 0x28000001L; // highMask(";/?:@&=+$,[]"); - - // The zero'th bit is used to indicate that escape pairs and non-US-ASCII - // characters are allowed; this is handled by the scanEscape method below. - private static final long L_ESCAPED = 1L; - private static final long H_ESCAPED = 0L; - - // uric = reserved | unreserved | escaped - private static final long L_URIC = L_RESERVED | L_UNRESERVED | L_ESCAPED; - private static final long H_URIC = H_RESERVED | H_UNRESERVED | H_ESCAPED; - - // pchar = unreserved | escaped | - // ":" | "@" | "&" | "=" | "+" | "$" | "," - private static final long L_PCHAR = L_UNRESERVED | L_ESCAPED | 0x2400185000000000L; // lowMask(":@&=+$,"); - private static final long H_PCHAR = H_UNRESERVED | H_ESCAPED | 0x1L; // highMask(":@&=+$,"); - - // All valid path characters - private static final long L_PATH = L_PCHAR | 0x800800000000000L; // lowMask(";/"); - private static final long H_PATH = H_PCHAR; // highMask(";/") == 0x0L; - - // Dash, for use in domainlabel and toplabel - private static final long L_DASH = 0x200000000000L; // lowMask("-"); - private static final long H_DASH = 0x0L; // highMask("-"); - - // userinfo = *( unreserved | escaped | - // ";" | ":" | "&" | "=" | "+" | "$" | "," ) - private static final long L_USERINFO = L_UNRESERVED | L_ESCAPED | 0x2C00185000000000L; // lowMask(";:&=+$,"); - private static final long H_USERINFO = H_UNRESERVED | H_ESCAPED; // | highMask(";:&=+$,") == 0L; - - // reg_name = 1*( unreserved | escaped | "$" | "," | - // ";" | ":" | "@" | "&" | "=" | "+" ) - private static final long L_REG_NAME = L_UNRESERVED | L_ESCAPED | 0x2C00185000000000L; // lowMask("$,;:@&=+"); - private static final long H_REG_NAME = H_UNRESERVED | H_ESCAPED | 0x1L; // highMask("$,;:@&=+"); - - // All valid characters for server-based authorities - private static final long L_SERVER = L_USERINFO | L_ALPHANUM | L_DASH | 0x400400000000000L; // lowMask(".:@[]"); - private static final long H_SERVER = H_USERINFO | H_ALPHANUM | H_DASH | 0x28000001L; // highMask(".:@[]"); - - // Characters that are encoded in the path component of a URI. - // - // These characters are reserved in the path segment as described in - // RFC2396 section 3.3: - // "=" | ";" | "?" | "/" - // - // These characters are defined as excluded in RFC2396 section 2.4.3 - // and must be escaped if they occur in the data part of a URI: - // "#" | " " | "<" | ">" | "%" | "\"" | "{" | "}" | "|" | "\\" | "^" | - // "[" | "]" | "`" - // - // Also US ASCII control characters 00-1F and 7F. - - // lowMask((char)0, (char)31) | lowMask("=;?/# <>%\"{}|\\^[]`"); - private static final long L_ENCODED = 0xF800802DFFFFFFFFL; - - // highMask((char)0x7F, (char)0x7F) | highMask("=;?/# <>%\"{}|\\^[]`"); - private static final long H_ENCODED = 0xB800000178000000L; - -} diff --git a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/Password.java b/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/Password.java deleted file mode 100644 index ffe5f734fa0ea..0000000000000 --- a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/Password.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * 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.secure_sm.policy; - -import java.io.ByteArrayInputStream; -import java.io.Console; -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CodingErrorAction; -import java.util.Arrays; - -/** - * Adapted from: https://github.com/openjdk/jdk23u/blob/master/src/java.base/share/classes/sun/security/util/Password.java - */ -public class Password { - /** Reads user password from given input stream. */ - public static char[] readPassword(InputStream in) throws IOException { - return readPassword(in, false); - } - - /** Reads user password from given input stream. - * @param isEchoOn true if the password should be echoed on the screen - */ - @SuppressWarnings("fallthrough") - public static char[] readPassword(InputStream in, boolean isEchoOn) throws IOException { - - char[] consoleEntered = null; - byte[] consoleBytes = null; - - try { - // Use the new java.io.Console class - Console con = null; - if (!isEchoOn && in == System.in && ((con = System.console()) != null)) { - consoleEntered = con.readPassword(); - // readPassword returns "" if you just print ENTER, - // to be compatible with old Password class, change to null - if (consoleEntered != null && consoleEntered.length == 0) { - return null; - } - consoleBytes = convertToBytes(consoleEntered); - in = new ByteArrayInputStream(consoleBytes); - } - - // Rest of the lines still necessary for KeyStoreLoginModule - // and when there is no console. - - char[] lineBuffer; - char[] buf; - int i; - - buf = lineBuffer = new char[128]; - - int room = buf.length; - int offset = 0; - int c; - - boolean done = false; - while (!done) { - switch (c = in.read()) { - case -1: - case '\n': - done = true; - break; - - case '\r': - int c2 = in.read(); - if ((c2 != '\n') && (c2 != -1)) { - if (!(in instanceof PushbackInputStream)) { - in = new PushbackInputStream(in); - } - ((PushbackInputStream) in).unread(c2); - } else { - done = true; - break; - } - /* fall through */ - default: - if (--room < 0) { - buf = new char[offset + 128]; - room = buf.length - offset - 1; - System.arraycopy(lineBuffer, 0, buf, 0, offset); - Arrays.fill(lineBuffer, ' '); - lineBuffer = buf; - } - buf[offset++] = (char) c; - break; - } - } - - if (offset == 0) { - return null; - } - - char[] ret = new char[offset]; - System.arraycopy(buf, 0, ret, 0, offset); - Arrays.fill(buf, ' '); - - return ret; - } finally { - if (consoleEntered != null) { - Arrays.fill(consoleEntered, ' '); - } - if (consoleBytes != null) { - Arrays.fill(consoleBytes, (byte) 0); - } - } - } - - /** - * Change a password read from Console.readPassword() into - * its original bytes. - * - * @param pass a char[] - * @return its byte[] format, similar to new String(pass).getBytes() - */ - private static byte[] convertToBytes(char[] pass) { - if (enc == null) { - synchronized (Password.class) { - enc = System.console() - .charset() - .newEncoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); - } - } - byte[] ba = new byte[(int) (enc.maxBytesPerChar() * pass.length)]; - ByteBuffer bb = ByteBuffer.wrap(ba); - synchronized (enc) { - enc.reset().encode(CharBuffer.wrap(pass), bb, true); - } - if (bb.position() < ba.length) { - ba[bb.position()] = '\n'; - } - return ba; - } - - private static volatile CharsetEncoder enc; -} diff --git a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PolicyFile.java b/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PolicyFile.java deleted file mode 100644 index 14b1a8f56375c..0000000000000 --- a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PolicyFile.java +++ /dev/null @@ -1,1601 +0,0 @@ -/* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * 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.secure_sm.policy; - -import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; - -import java.io.File; -import java.io.FilePermission; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.ObjectInputStream; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.NetPermission; -import java.net.SocketPermission; -import java.net.URI; -import java.net.URL; -import java.security.AllPermission; -import java.security.CodeSource; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.Permission; -import java.security.PermissionCollection; -import java.security.Permissions; -import java.security.Principal; -import java.security.ProtectionDomain; -import java.security.Security; -import java.security.SecurityPermission; -import java.security.UnresolvedPermission; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.PropertyPermission; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.concurrent.ConcurrentHashMap; - -import static java.nio.charset.StandardCharsets.UTF_8; - -/** - * Adapted from: https://github.com/openjdk/jdk23u/blob/master/src/java.base/share/classes/sun/security/provider/PolicyFile.java - */ -@SuppressWarnings("removal") -public class PolicyFile extends java.security.Policy { - private static final String SELF = "${{self}}"; - private static final String X500PRINCIPAL = "javax.security.auth.x500.X500Principal"; - private static final String POLICY = "java.security.policy"; - private static final String POLICY_URL = "policy.url."; - - private static final int DEFAULT_CACHE_SIZE = 1; - - // contains the policy grant entries, PD cache, and alias mapping - // can be updated if refresh() is called - private volatile PolicyInfo policyInfo; - - private boolean expandProperties = true; - private boolean allowSystemProperties = true; - private boolean notUtf8 = false; - private URL url; - - // for use with the reflection API - private static final Class[] PARAMS0 = {}; - private static final Class[] PARAMS1 = { String.class }; - private static final Class[] PARAMS2 = { String.class, String.class }; - - /** - * When a policy file has a syntax error, the exception code may generate - * another permission check and this can cause the policy file to be parsed - * repeatedly, leading to a StackOverflowError or ClassCircularityError. - * To avoid this, this set is populated with policy files that have been - * previously parsed and have syntax errors, so that they can be - * subsequently ignored. - */ - private static Set badPolicyURLs = Collections.newSetFromMap(new ConcurrentHashMap()); - - /** - * Initializes the Policy object and reads the default policy - * configuration file(s) into the Policy object. - */ - public PolicyFile() { - init((URL) null); - } - - /** - * Initializes the Policy object and reads the default policy - * from the specified URL only. - */ - public PolicyFile(URL url) { - this.url = url; - init(url); - } - - /** - * Initializes the Policy object and reads the default policy - * configuration file(s) into the Policy object. - * - * See the class description for details on the algorithm used to - * initialize the Policy object. - */ - private void init(URL url) { - int numCaches = DEFAULT_CACHE_SIZE; - PolicyInfo newInfo = new PolicyInfo(numCaches); - initPolicyFile(newInfo, url); - policyInfo = newInfo; - } - - private void initPolicyFile(final PolicyInfo newInfo, final URL url) { - if (url != null) { - - /** - * If the caller specified a URL via Policy.getInstance, - * we only read from default.policy and that URL. - */ - - if (init(url, newInfo) == false) { - // use static policy if all else fails - initStaticPolicy(newInfo); - } - - } else { - - /** - * Caller did not specify URL via Policy.getInstance. - * Read from URLs listed in the java.security properties file. - */ - - boolean loaded_one = initPolicyFile(POLICY, POLICY_URL, newInfo); - // To maintain strict backward compatibility - // we load the static policy only if POLICY load failed - if (!loaded_one) { - // use static policy if all else fails - initStaticPolicy(newInfo); - } - } - } - - private boolean initPolicyFile(final String propname, final String urlname, final PolicyInfo newInfo) { - boolean loaded_policy = false; - - if (allowSystemProperties) { - String extra_policy = System.getProperty(propname); - if (extra_policy != null) { - boolean overrideAll = false; - if (extra_policy.startsWith("=")) { - overrideAll = true; - extra_policy = extra_policy.substring(1); - } - try { - extra_policy = PropertyExpander.expand(extra_policy); - URL policyURL; - - File policyFile = new File(extra_policy); - if (policyFile.exists()) { - policyURL = ParseUtil.fileToEncodedURL(new File(policyFile.getCanonicalPath())); - } else { - policyURL = newURL(extra_policy); - } - if (init(policyURL, newInfo)) { - loaded_policy = true; - } - } catch (Exception e) {} - if (overrideAll) { - return Boolean.valueOf(loaded_policy); - } - } - } - - int n = 1; - String policy_uri; - - while ((policy_uri = Security.getProperty(urlname + n)) != null) { - try { - URL policy_url = null; - String expanded_uri = PropertyExpander.expand(policy_uri).replace(File.separatorChar, '/'); - - if (policy_uri.startsWith("file:${java.home}/") || policy_uri.startsWith("file:${user.home}/")) { - - // this special case accommodates - // the situation java.home/user.home - // expand to a single slash, resulting in - // a file://foo URI - policy_url = new File(expanded_uri.substring(5)).toURI().toURL(); - } else { - policy_url = new URI(expanded_uri).toURL(); - } - - if (init(policy_url, newInfo)) { - loaded_policy = true; - } - } catch (Exception e) { - // ignore that policy - } - n++; - } - return Boolean.valueOf(loaded_policy); - } - - /** - * Reads a policy configuration into the Policy object using a - * Reader object. - */ - private boolean init(URL policy, PolicyInfo newInfo) { - - // skip parsing policy file if it has been previously parsed and - // has syntax errors - if (badPolicyURLs.contains(policy)) { - return false; - } - - try (InputStreamReader isr = getInputStreamReader(PolicyUtil.getInputStream(policy))) { - - PolicyParser pp = new PolicyParser(expandProperties); - pp.read(isr); - - KeyStore keyStore = null; - try { - keyStore = PolicyUtil.getKeyStore( - policy, - pp.getKeyStoreUrl(), - pp.getKeyStoreType(), - pp.getKeyStoreProvider(), - pp.getStorePassURL() - ); - } catch (Exception e) { - // ignore, treat it like we have no keystore - } - - Enumeration enum_ = pp.grantElements(); - while (enum_.hasMoreElements()) { - PolicyParser.GrantEntry ge = enum_.nextElement(); - addGrantEntry(ge, keyStore, newInfo); - } - return true; - } catch (PolicyParser.ParsingException pe) { - // record bad policy file to avoid later reparsing it - badPolicyURLs.add(policy); - pe.printStackTrace(System.err); - } catch (Exception e) {} - - return false; - } - - private InputStreamReader getInputStreamReader(InputStream is) { - /* - * Read in policy using UTF-8 by default. - * - * Check non-standard system property to see if the default encoding - * should be used instead. - */ - return (notUtf8) ? new InputStreamReader(is) : new InputStreamReader(is, UTF_8); - } - - private void initStaticPolicy(final PolicyInfo newInfo) { - PolicyEntry pe = new PolicyEntry(new CodeSource(null, (Certificate[]) null)); - pe.add(SecurityConstants.LOCAL_LISTEN_PERMISSION); - pe.add(new PropertyPermission("java.version", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.vendor", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.vendor.url", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.class.version", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("os.name", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("os.version", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("os.arch", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("file.separator", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("path.separator", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("line.separator", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.specification.version", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.specification.maintenance.version", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.specification.vendor", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.specification.name", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.vm.specification.version", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.vm.specification.vendor", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.vm.specification.name", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.vm.version", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.vm.vendor", SecurityConstants.PROPERTY_READ_ACTION)); - pe.add(new PropertyPermission("java.vm.name", SecurityConstants.PROPERTY_READ_ACTION)); - - // No need to sync because no one has access to newInfo yet - newInfo.policyEntries.add(pe); - } - - /** - * Given a GrantEntry, create a codeSource. - * - * @return null if signedBy alias is not recognized - */ - private CodeSource getCodeSource(PolicyParser.GrantEntry ge, KeyStore keyStore, PolicyInfo newInfo) - throws java.net.MalformedURLException { - Certificate[] certs = null; - if (ge.signedBy != null) { - certs = getCertificates(keyStore, ge.signedBy, newInfo); - if (certs == null) { - return null; - } - } - - URL location; - - if (ge.codeBase != null) location = newURL(ge.codeBase); - else location = null; - - return (canonicalizeCodebase(new CodeSource(location, certs), false)); - } - - /** - * Add one policy entry to the list. - */ - private void addGrantEntry(PolicyParser.GrantEntry ge, KeyStore keyStore, PolicyInfo newInfo) { - - try { - CodeSource codesource = getCodeSource(ge, keyStore, newInfo); - // skip if signedBy alias was unknown... - if (codesource == null) return; - - // perform keystore alias principal replacement. - // for example, if alias resolves to X509 certificate, - // replace principal with: - // -- skip if alias is unknown - if (replacePrincipals(ge.principals, keyStore) == false) return; - PolicyEntry entry = new PolicyEntry(codesource, ge.principals); - Enumeration enum_ = ge.permissionElements(); - while (enum_.hasMoreElements()) { - PolicyParser.PermissionEntry pe = enum_.nextElement(); - - try { - // perform ${{ ... }} expansions within permission name - expandPermissionName(pe, keyStore); - - // XXX special case PrivateCredentialPermission-SELF - Permission perm; - if (pe.permission.equals("javax.security.auth.PrivateCredentialPermission") && pe.name.endsWith(" self")) { - pe.name = pe.name.substring(0, pe.name.indexOf("self")) + SELF; - } - // check for self - if (pe.name != null && pe.name.contains(SELF)) { - // Create a "SelfPermission" , it could be an - // an unresolved permission which will be resolved - // when implies is called - // Add it to entry - Certificate[] certs; - if (pe.signedBy != null) { - certs = getCertificates(keyStore, pe.signedBy, newInfo); - } else { - certs = null; - } - perm = new SelfPermission(pe.permission, pe.name, pe.action, certs); - } else { - perm = getInstance(pe.permission, pe.name, pe.action); - } - entry.add(perm); - } catch (ClassNotFoundException cnfe) { - Certificate[] certs; - if (pe.signedBy != null) { - certs = getCertificates(keyStore, pe.signedBy, newInfo); - } else { - certs = null; - } - - // only add if we had no signer or we had - // a signer and found the keys for it. - if (certs != null || pe.signedBy == null) { - Permission perm = new UnresolvedPermission(pe.permission, pe.name, pe.action, certs); - entry.add(perm); - } - } catch (java.lang.reflect.InvocationTargetException ite) { - ite.printStackTrace(System.err); - } catch (Exception e) { - e.printStackTrace(System.err); - } - } - - // No need to sync because no one has access to newInfo yet - newInfo.policyEntries.add(entry); - } catch (Exception e) { - e.printStackTrace(System.err); - } - } - - /** - * Returns a new Permission object of the given Type. The Permission is - * created by getting the - * Class object using the Class.forName method, and using - * the reflection API to invoke the (String name, String actions) - * constructor on the - * object. - * - * @param type the type of Permission being created. - * @param name the name of the Permission being created. - * @param actions the actions of the Permission being created. - * - * @exception ClassNotFoundException if the particular Permission - * class could not be found. - * - * @exception IllegalAccessException if the class or initializer is - * not accessible. - * - * @exception InstantiationException if getInstance tries to - * instantiate an abstract class or an interface, or if the - * instantiation fails for some other reason. - * - * @exception NoSuchMethodException if the (String, String) constructor - * is not found. - * - * @exception InvocationTargetException if the underlying Permission - * constructor throws an exception. - * - */ - - private static final Permission getInstance(String type, String name, String actions) throws ClassNotFoundException, - InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { - Class pc = Class.forName(type, false, null); - Permission answer = getKnownPermission(pc, name, actions); - if (answer != null) { - return answer; - } - if (!Permission.class.isAssignableFrom(pc)) { - // not the right subtype - throw new ClassCastException(type + " is not a Permission"); - } - - if (name == null && actions == null) { - try { - Constructor c = pc.getConstructor(PARAMS0); - return (Permission) c.newInstance(new Object[] {}); - } catch (NoSuchMethodException ne) { - try { - Constructor c = pc.getConstructor(PARAMS1); - return (Permission) c.newInstance(new Object[] { name }); - } catch (NoSuchMethodException ne1) { - Constructor c = pc.getConstructor(PARAMS2); - return (Permission) c.newInstance(new Object[] { name, actions }); - } - } - } else { - if (name != null && actions == null) { - try { - Constructor c = pc.getConstructor(PARAMS1); - return (Permission) c.newInstance(new Object[] { name }); - } catch (NoSuchMethodException ne) { - Constructor c = pc.getConstructor(PARAMS2); - return (Permission) c.newInstance(new Object[] { name, actions }); - } - } else { - Constructor c = pc.getConstructor(PARAMS2); - return (Permission) c.newInstance(new Object[] { name, actions }); - } - } - } - - /** - * Creates one of the well-known permissions in the java.base module - * directly instead of via reflection. Keep list short to not penalize - * permissions from other modules. - */ - private static Permission getKnownPermission(Class claz, String name, String actions) { - if (claz.equals(FilePermission.class)) { - return new FilePermission(name, actions); - } else if (claz.equals(SocketPermission.class)) { - return new SocketPermission(name, actions); - } else if (claz.equals(RuntimePermission.class)) { - return new RuntimePermission(name, actions); - } else if (claz.equals(PropertyPermission.class)) { - return new PropertyPermission(name, actions); - } else if (claz.equals(NetPermission.class)) { - return new NetPermission(name, actions); - } else if (claz.equals(AllPermission.class)) { - return SecurityConstants.ALL_PERMISSION; - } else if (claz.equals(SecurityPermission.class)) { - return new SecurityPermission(name, actions); - } else { - return null; - } - } - - /** - * Creates one of the well-known principals in the java.base module - * directly instead of via reflection. Keep list short to not penalize - * principals from other modules. - */ - private static Principal getKnownPrincipal(Class claz, String name) { - if (claz.equals(X500Principal.class)) { - return new X500Principal(name); - } else { - return null; - } - } - - /** - * Fetch all certs associated with this alias. - */ - private Certificate[] getCertificates(KeyStore keyStore, String aliases, PolicyInfo newInfo) { - - List vcerts = null; - - StringTokenizer st = new StringTokenizer(aliases, ","); - int n = 0; - - while (st.hasMoreTokens()) { - String alias = st.nextToken().trim(); - n++; - Certificate cert = null; - // See if this alias's cert has already been cached - synchronized (newInfo.aliasMapping) { - cert = (Certificate) newInfo.aliasMapping.get(alias); - - if (cert == null && keyStore != null) { - - try { - cert = keyStore.getCertificate(alias); - } catch (KeyStoreException kse) { - // never happens, because keystore has already been loaded - // when we call this - } - if (cert != null) { - newInfo.aliasMapping.put(alias, cert); - newInfo.aliasMapping.put(cert, alias); - } - } - } - - if (cert != null) { - if (vcerts == null) vcerts = new ArrayList<>(); - vcerts.add(cert); - } - } - - // make sure n == vcerts.size, since we are doing a logical *and* - if (vcerts != null && n == vcerts.size()) { - Certificate[] certs = new Certificate[vcerts.size()]; - vcerts.toArray(certs); - return certs; - } else { - return null; - } - } - - /** - * Refreshes the policy object by re-reading all the policy files. - */ - @Override - public void refresh() { - init(url); - } - - /** - * Evaluates the global policy for the permissions granted to - * the ProtectionDomain and tests whether the permission is - * granted. - * - * @param pd the ProtectionDomain to test - * @param p the Permission object to be tested for implication. - * - * @return true if "permission" is a proper subset of a permission - * granted to this ProtectionDomain. - * - * @see java.security.ProtectionDomain - */ - @Override - public boolean implies(ProtectionDomain pd, Permission p) { - PermissionCollection pc = getPermissions(pd); - if (pc == null) { - return false; - } - - // cache mapping of protection domain to its PermissionCollection - return pc.implies(p); - } - - /** - * Examines this Policy and returns the permissions granted - * to the specified ProtectionDomain. This includes - * the permissions currently associated with the domain as well - * as the policy permissions granted to the domain's - * CodeSource, ClassLoader, and Principals. - * - *

Note that this Policy implementation has - * special handling for PrivateCredentialPermissions. - * When this method encounters a PrivateCredentialPermission - * which specifies "self" as the Principal class and name, - * it does not add that Permission to the returned - * PermissionCollection. Instead, it builds - * a new PrivateCredentialPermission - * for each Principal associated with the provided - * Subject. Each new PrivateCredentialPermission - * contains the same Credential class as specified in the - * originally granted permission, as well as the Class and name - * for the respective Principal. - * - * @param domain the Permissions granted to this - * ProtectionDomain are returned. - * - * @return the Permissions granted to the provided - * ProtectionDomain. - */ - @Override - public PermissionCollection getPermissions(ProtectionDomain domain) { - Permissions perms = new Permissions(); - - if (domain == null) return perms; - - // first get policy perms - getPermissions(perms, domain); - - // add static perms - // - adding static perms after policy perms is necessary - // to avoid a regression for 4301064 - PermissionCollection pc = domain.getPermissions(); - if (pc != null) { - synchronized (pc) { - Enumeration e = pc.elements(); - while (e.hasMoreElements()) { - perms.add(e.nextElement()); - } - } - } - - return perms; - } - - /** - * Examines this Policy and creates a PermissionCollection object with - * the set of permissions for the specified CodeSource. - * - * @param codesource the CodeSource associated with the caller. - * This encapsulates the original location of the code (where the code - * came from) and the public key(s) of its signer. - * - * @return the set of permissions according to the policy. - */ - @Override - public PermissionCollection getPermissions(CodeSource codesource) { - return getPermissions(new Permissions(), codesource); - } - - /** - * Examines the global policy and returns the provided Permissions - * object with additional permissions granted to the specified - * ProtectionDomain. - * - * @param perms the Permissions to populate - * @param pd the ProtectionDomain associated with the caller. - * - * @return the set of Permissions according to the policy. - */ - private PermissionCollection getPermissions(Permissions perms, ProtectionDomain pd) { - final CodeSource cs = pd.getCodeSource(); - if (cs == null) return perms; - - CodeSource canonCodeSource = canonicalizeCodebase(cs, true); - return getPermissions(perms, canonCodeSource, pd.getPrincipals()); - } - - /** - * Examines the global policy and returns the provided Permissions - * object with additional permissions granted to the specified - * CodeSource. - * - * @param perms the permissions to populate - * @param cs the codesource associated with the caller. - * This encapsulates the original location of the code (where the code - * came from) and the public key(s) of its signer. - * - * @return the set of permissions according to the policy. - */ - private PermissionCollection getPermissions(Permissions perms, final CodeSource cs) { - - if (cs == null) return perms; - - CodeSource canonCodeSource = canonicalizeCodebase(cs, true); - return getPermissions(perms, canonCodeSource, null); - } - - private Permissions getPermissions(Permissions perms, final CodeSource cs, Principal[] principals) { - for (PolicyEntry entry : policyInfo.policyEntries) { - addPermissions(perms, cs, principals, entry); - } - - return perms; - } - - private void addPermissions(Permissions perms, final CodeSource cs, Principal[] principals, final PolicyEntry entry) { - - // check to see if the CodeSource implies - Boolean imp = entry.getCodeSource().implies(cs); - if (!imp.booleanValue()) { - // CodeSource does not imply - return and try next policy entry - return; - } - - // check to see if the Principals imply - - List entryPs = entry.getPrincipals(); - - if (entryPs == null || entryPs.isEmpty()) { - - // policy entry has no principals - - // add perms regardless of principals in current ACC - - addPerms(perms, principals, entry); - return; - - } else if (principals == null || principals.length == 0) { - - // current thread has no principals but this policy entry - // has principals - perms are not added - - return; - } - - // current thread has principals and this policy entry - // has principals. see if policy entry principals match - // principals in current ACC - - for (PolicyParser.PrincipalEntry pppe : entryPs) { - - // Check for wildcards - if (pppe.isWildcardClass()) { - // a wildcard class matches all principals in current ACC - continue; - } - - if (pppe.isWildcardName()) { - // a wildcard name matches any principal with the same class - if (wildcardPrincipalNameImplies(pppe.principalClass, principals)) { - continue; - } - // policy entry principal not in current ACC - - // immediately return and go to next policy entry - return; - } - - Set pSet = new HashSet<>(Arrays.asList(principals)); - Subject subject = new Subject(true, pSet, Collections.EMPTY_SET, Collections.EMPTY_SET); - try { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - Class pClass = Class.forName(pppe.principalClass, false, cl); - Principal p = getKnownPrincipal(pClass, pppe.principalName); - if (p == null) { - if (!Principal.class.isAssignableFrom(pClass)) { - // not the right subtype - throw new ClassCastException(pppe.principalClass + " is not a Principal"); - } - - Constructor c = pClass.getConstructor(PARAMS1); - p = (Principal) c.newInstance(new Object[] { pppe.principalName }); - - } - - // check if the Principal implies the current - // thread's principals - if (!p.implies(subject)) { - // policy principal does not imply the current Subject - - // immediately return and go to next policy entry - return; - } - } catch (Exception e) { - // fall back to default principal comparison. - // see if policy entry principal is in current ACC - - if (!pppe.implies(subject)) { - // policy entry principal not in current ACC - - // immediately return and go to next policy entry - return; - } - } - - // either the principal information matched, - // or the Principal.implies succeeded. - // continue loop and test the next policy principal - } - - // all policy entry principals were found in the current ACC - - // grant the policy permissions - - addPerms(perms, principals, entry); - } - - /** - * Returns true if the array of principals contains at least one - * principal of the specified class. - */ - private static boolean wildcardPrincipalNameImplies(String principalClass, Principal[] principals) { - for (Principal p : principals) { - if (principalClass.equals(p.getClass().getName())) { - return true; - } - } - return false; - } - - private void addPerms(Permissions perms, Principal[] accPs, PolicyEntry entry) { - for (int i = 0; i < entry.permissions.size(); i++) { - Permission p = entry.permissions.get(i); - - if (p instanceof SelfPermission) { - // handle "SELF" permissions - expandSelf((SelfPermission) p, entry.getPrincipals(), accPs, perms); - } else { - perms.add(p); - } - } - } - - /** - * @param sp the SelfPermission that needs to be expanded. - * - * @param entryPs list of principals for the Policy entry. - * - * @param pdp Principal array from the current ProtectionDomain. - * - * @param perms the PermissionCollection where the individual - * Permissions will be added after expansion. - */ - - private void expandSelf(SelfPermission sp, List entryPs, Principal[] pdp, Permissions perms) { - - if (entryPs == null || entryPs.isEmpty()) { - return; - } - int startIndex = 0; - int v; - StringBuilder sb = new StringBuilder(); - while ((v = sp.getSelfName().indexOf(SELF, startIndex)) != -1) { - - // add non-SELF string - sb.append(sp.getSelfName().substring(startIndex, v)); - - // expand SELF - Iterator pli = entryPs.iterator(); - while (pli.hasNext()) { - PolicyParser.PrincipalEntry pppe = pli.next(); - String[][] principalInfo = getPrincipalInfo(pppe, pdp); - for (int i = 0; i < principalInfo.length; i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(principalInfo[i][0] + " " + "\"" + principalInfo[i][1] + "\""); - } - if (pli.hasNext()) { - sb.append(", "); - } - } - startIndex = v + SELF.length(); - } - // add remaining string (might be the entire string) - sb.append(sp.getSelfName().substring(startIndex)); - - try { - // first try to instantiate the permission - perms.add(getInstance(sp.getSelfType(), sb.toString(), sp.getSelfActions())); - } catch (ClassNotFoundException cnfe) { - // ok, the permission is not in the bootclasspath. - // before we add an UnresolvedPermission, check to see - // whether this perm already belongs to the collection. - // if so, use that perm's ClassLoader to create a new - // one. - Class pc = null; - synchronized (perms) { - Enumeration e = perms.elements(); - while (e.hasMoreElements()) { - Permission pElement = e.nextElement(); - if (pElement.getClass().getName().equals(sp.getSelfType())) { - pc = pElement.getClass(); - break; - } - } - } - if (pc == null) { - // create an UnresolvedPermission - perms.add(new UnresolvedPermission(sp.getSelfType(), sb.toString(), sp.getSelfActions(), sp.getCerts())); - } else { - try { - // we found an instantiated permission. - // use its class loader to instantiate a new permission. - Constructor c; - // name parameter can not be null - if (sp.getSelfActions() == null) { - try { - c = pc.getConstructor(PARAMS1); - perms.add((Permission) c.newInstance(new Object[] { sb.toString() })); - } catch (NoSuchMethodException ne) { - c = pc.getConstructor(PARAMS2); - perms.add((Permission) c.newInstance(new Object[] { sb.toString(), sp.getSelfActions() })); - } - } else { - c = pc.getConstructor(PARAMS2); - perms.add((Permission) c.newInstance(new Object[] { sb.toString(), sp.getSelfActions() })); - } - } catch (Exception nme) {} - } - } catch (Exception e) {} - } - - /** - * return the principal class/name pair in the 2D array. - * array[x][y]: x corresponds to the array length. - * if (y == 0), it's the principal class. - * if (y == 1), it's the principal name. - */ - private String[][] getPrincipalInfo(PolicyParser.PrincipalEntry pe, Principal[] pdp) { - - // there are 3 possibilities: - // 1) the entry's Principal class and name are not wildcarded - // 2) the entry's Principal name is wildcarded only - // 3) the entry's Principal class and name are wildcarded - - if (!pe.isWildcardClass() && !pe.isWildcardName()) { - - // build an info array for the principal - // from the Policy entry - String[][] info = new String[1][2]; - info[0][0] = pe.principalClass; - info[0][1] = pe.principalName; - return info; - - } else if (!pe.isWildcardClass() && pe.isWildcardName()) { - - // build an info array for every principal - // in the current domain which has a principal class - // that is equal to policy entry principal class name - List plist = new ArrayList<>(); - for (int i = 0; i < pdp.length; i++) { - if (pe.principalClass.equals(pdp[i].getClass().getName())) plist.add(pdp[i]); - } - String[][] info = new String[plist.size()][2]; - int i = 0; - for (Principal p : plist) { - info[i][0] = p.getClass().getName(); - info[i][1] = p.getName(); - i++; - } - return info; - - } else { - - // build an info array for every - // one of the current Domain's principals - - String[][] info = new String[pdp.length][2]; - - for (int i = 0; i < pdp.length; i++) { - info[i][0] = pdp[i].getClass().getName(); - info[i][1] = pdp[i].getName(); - } - return info; - } - } - - /* - * Returns the signer certificates from the list of certificates - * associated with the given code source. - * - * The signer certificates are those certificates that were used - * to verify signed code originating from the codesource location. - * - * This method assumes that in the given code source, each signer - * certificate is followed by its supporting certificate chain - * (which may be empty), and that the signer certificate and its - * supporting certificate chain are ordered bottom-to-top - * (i.e., with the signer certificate first and the (root) certificate - * authority last). - */ - protected Certificate[] getSignerCertificates(CodeSource cs) { - Certificate[] certs = null; - if ((certs = cs.getCertificates()) == null) return null; - for (int i = 0; i < certs.length; i++) { - if (!(certs[i] instanceof X509Certificate)) return cs.getCertificates(); - } - - // Do we have to do anything? - int i = 0; - int count = 0; - while (i < certs.length) { - count++; - while (((i + 1) < certs.length) - && ((X509Certificate) certs[i]).getIssuerX500Principal() - .equals(((X509Certificate) certs[i + 1]).getSubjectX500Principal())) { - i++; - } - i++; - } - if (count == certs.length) - // Done - return certs; - - List userCertList = new ArrayList<>(); - i = 0; - while (i < certs.length) { - userCertList.add(certs[i]); - while (((i + 1) < certs.length) - && ((X509Certificate) certs[i]).getIssuerX500Principal() - .equals(((X509Certificate) certs[i + 1]).getSubjectX500Principal())) { - i++; - } - i++; - } - Certificate[] userCerts = new Certificate[userCertList.size()]; - userCertList.toArray(userCerts); - return userCerts; - } - - private CodeSource canonicalizeCodebase(CodeSource cs, boolean extractSignerCerts) { - - String path = null; - - CodeSource canonCs = cs; - URL u = cs.getLocation(); - if (u != null) { - if (u.getProtocol().equals("jar")) { - // unwrap url embedded inside jar url - String spec = u.getFile(); - int separator = spec.indexOf("!/"); - if (separator != -1) { - try { - u = newURL(spec.substring(0, separator)); - } catch (MalformedURLException e) { - // Fail silently. In this case, url stays what - // it was above - } - } - } - if (u.getProtocol().equals("file")) { - boolean isLocalFile = false; - String host = u.getHost(); - isLocalFile = (host == null || host.isEmpty() || host.equals("~") || host.equalsIgnoreCase("localhost")); - - if (isLocalFile) { - path = u.getFile().replace('/', File.separatorChar); - path = ParseUtil.decode(path); - } - } - } - - if (path != null) { - try { - URL csUrl = null; - path = canonPath(path); - csUrl = ParseUtil.fileToEncodedURL(new File(path)); - - if (extractSignerCerts) { - canonCs = new CodeSource(csUrl, getSignerCertificates(cs)); - } else { - canonCs = new CodeSource(csUrl, cs.getCertificates()); - } - } catch (IOException ioe) { - // leave codesource as it is, unless we have to extract its - // signer certificates - if (extractSignerCerts) { - canonCs = new CodeSource(cs.getLocation(), getSignerCertificates(cs)); - } - } - } else { - if (extractSignerCerts) { - canonCs = new CodeSource(cs.getLocation(), getSignerCertificates(cs)); - } - } - return canonCs; - } - - // Wrapper to return a canonical path that avoids calling getCanonicalPath() - // with paths that are intended to match all entries in the directory - private static String canonPath(String path) throws IOException { - if (path.endsWith("*")) { - path = path.substring(0, path.length() - 1) + "-"; - path = new File(path).getCanonicalPath(); - return path.substring(0, path.length() - 1) + "*"; - } else { - return new File(path).getCanonicalPath(); - } - } - - /** - * return true if no replacement was performed, - * or if replacement succeeded. - */ - private boolean replacePrincipals(List principals, KeyStore keystore) { - - if (principals == null || principals.isEmpty() || keystore == null) return true; - - for (PolicyParser.PrincipalEntry pppe : principals) { - if (pppe.isReplaceName()) { - - // perform replacement - // (only X509 replacement is possible now) - String name; - if ((name = getDN(pppe.principalName, keystore)) == null) { - return false; - } - - pppe.principalClass = X500PRINCIPAL; - pppe.principalName = name; - } - } - // return true if no replacement was performed, - // or if replacement succeeded - return true; - } - - private void expandPermissionName(PolicyParser.PermissionEntry pe, KeyStore keystore) throws Exception { - // short cut the common case - if (pe.name == null || pe.name.indexOf("${{", 0) == -1) { - return; - } - - int startIndex = 0; - int b, e; - StringBuilder sb = new StringBuilder(); - while ((b = pe.name.indexOf("${{", startIndex)) != -1) { - e = pe.name.indexOf("}}", b); - if (e < 1) { - break; - } - sb.append(pe.name.substring(startIndex, b)); - - // get the value in ${{...}} - String value = pe.name.substring(b + 3, e); - - // parse up to the first ':' - int colonIndex; - String prefix = value; - String suffix; - if ((colonIndex = value.indexOf(':')) != -1) { - prefix = value.substring(0, colonIndex); - } - - // handle different prefix possibilities - if (prefix.equalsIgnoreCase("self")) { - // do nothing - handled later - sb.append(pe.name.substring(b, e + 2)); - startIndex = e + 2; - continue; - } else if (prefix.equalsIgnoreCase("alias")) { - // get the suffix and perform keystore alias replacement - if (colonIndex == -1) { - throw new Exception("Alias name not provided pe.name: " + pe.name); - } - suffix = value.substring(colonIndex + 1); - if ((suffix = getDN(suffix, keystore)) == null) { - throw new Exception("Unable to perform substitution on alias suffix: " + value.substring(colonIndex + 1)); - } - - sb.append(X500PRINCIPAL + " \"" + suffix + "\""); - startIndex = e + 2; - } else { - throw new Exception("Substitution value prefix unsupported: " + prefix); - } - } - - // copy the rest of the value - sb.append(pe.name.substring(startIndex)); - - pe.name = sb.toString(); - } - - private String getDN(String alias, KeyStore keystore) { - Certificate cert = null; - try { - cert = keystore.getCertificate(alias); - } catch (Exception e) { - return null; - } - - if (!(cert instanceof X509Certificate x509Cert)) { - return null; - } else { - // 4702543: X500 names with an EmailAddress - // were encoded incorrectly. create new - // X500Principal name with correct encoding - - X500Principal p = new X500Principal(x509Cert.getSubjectX500Principal().toString()); - return p.getName(); - } - } - - /** - * Each entry in the policy configuration file is represented by a - * PolicyEntry object.

- * - * A PolicyEntry is a (CodeSource,Permission) pair. The - * CodeSource contains the (URL, PublicKey) that together identify - * where the Java bytecodes come from and who (if anyone) signed - * them. The URL could refer to localhost. The URL could also be - * null, meaning that this policy entry is given to all comers, as - * long as they match the signer field. The signer could be null, - * meaning the code is not signed.

- * - * The Permission contains the (Type, Name, Action) triplet.

- * - * For now, the Policy object retrieves the public key from the - * X.509 certificate on disk that corresponds to the signedBy - * alias specified in the Policy config file. For reasons of - * efficiency, the Policy object keeps a hashtable of certs already - * read in. This could be replaced by a secure internal key - * store. - * - *

- * For example, the entry - *

-     *          permission java.io.File "/tmp", "read,write",
-     *          signedBy "Duke";
-     * 
- * is represented internally - *
-     *
-     * FilePermission f = new FilePermission("/tmp", "read,write");
-     * PublicKey p = publickeys.get("Duke");
-     * URL u = InetAddress.getLocalHost();
-     * CodeBase c = new CodeBase( p, u );
-     * pe = new PolicyEntry(f, c);
-     * 
- * - * @author Marianne Mueller - * @author Roland Schemers - * @see java.security.CodeSource - * @see java.security.Policy - * @see java.security.Permissions - * @see java.security.ProtectionDomain - */ - private static class PolicyEntry { - - private final CodeSource codesource; - final List permissions; - private final List principals; - - /** - * Given a Permission and a CodeSource, create a policy entry. - * - * XXX Decide if/how to add validity fields and "purpose" fields to - * XXX policy entries - * - * @param cs the CodeSource, which encapsulates the URL and the - * public key - * attributes from the policy config file. Validity checks - * are performed on the public key before PolicyEntry is - * called. - * - */ - PolicyEntry(CodeSource cs, List principals) { - this.codesource = cs; - this.permissions = new ArrayList(); - this.principals = principals; // can be null - } - - PolicyEntry(CodeSource cs) { - this(cs, null); - } - - List getPrincipals() { - return principals; // can be null - } - - /** - * add a Permission object to this entry. - * No need to sync add op because perms are added to entry only - * while entry is being initialized - */ - void add(Permission p) { - permissions.add(p); - } - - /** - * Return the CodeSource for this policy entry - */ - CodeSource getCodeSource() { - return codesource; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("{"); - sb.append(getCodeSource()); - sb.append("\n"); - for (int j = 0; j < permissions.size(); j++) { - Permission p = permissions.get(j); - sb.append(" "); - sb.append(" "); - sb.append(p); - sb.append("\n"); - } - sb.append("}"); - sb.append("\n"); - return sb.toString(); - } - } - - private static class SelfPermission extends Permission { - - @java.io.Serial - private static final long serialVersionUID = -8315562579967246806L; - - /** - * The class name of the Permission class that will be - * created when this self permission is expanded . - * - * @serial - */ - private String type; - - /** - * The permission name. - * - * @serial - */ - private String name; - - /** - * The actions of the permission. - * - * @serial - */ - private String actions; - - /** - * The certs of the permission. - * - * @serial - */ - private Certificate[] certs; - - /** - * Creates a new SelfPermission containing the permission - * information needed later to expand the self - * @param type the class name of the Permission class that will be - * created when this permission is expanded and if necessary resolved. - * @param name the name of the permission. - * @param actions the actions of the permission. - * @param certs the certificates the permission's class was signed with. - * This is a list of certificate chains, where each chain is composed of - * a signer certificate and optionally its supporting certificate chain. - * Each chain is ordered bottom-to-top (i.e., with the signer - * certificate first and the (root) certificate authority last). - */ - public SelfPermission(String type, String name, String actions, Certificate[] certs) { - super(type); - if (type == null) { - throw new NullPointerException("Ttype cannot be null"); - } - this.type = type; - this.name = name; - this.actions = actions; - if (certs != null) { - // Extract the signer certs from the list of certificates. - for (int i = 0; i < certs.length; i++) { - if (!(certs[i] instanceof X509Certificate)) { - // there is no concept of signer certs, so we store the - // entire cert array - this.certs = certs.clone(); - break; - } - } - - if (this.certs == null) { - // Go through the list of certs and see if all the certs are - // signer certs. - int i = 0; - int count = 0; - while (i < certs.length) { - count++; - while (((i + 1) < certs.length) - && ((X509Certificate) certs[i]).getIssuerX500Principal() - .equals(((X509Certificate) certs[i + 1]).getSubjectX500Principal())) { - i++; - } - i++; - } - if (count == certs.length) { - // All the certs are signer certs, so we store the - // entire array - this.certs = certs.clone(); - } - - if (this.certs == null) { - // extract the signer certs - List signerCerts = new ArrayList<>(); - i = 0; - while (i < certs.length) { - signerCerts.add(certs[i]); - while (((i + 1) < certs.length) - && ((X509Certificate) certs[i]).getIssuerX500Principal() - .equals(((X509Certificate) certs[i + 1]).getSubjectX500Principal())) { - i++; - } - i++; - } - this.certs = new Certificate[signerCerts.size()]; - signerCerts.toArray(this.certs); - } - } - } - } - - /** - * This method always returns false for SelfPermission permissions. - * That is, an SelfPermission never considered to - * imply another permission. - * - * @param p the permission to check against. - * - * @return false. - */ - @Override - public boolean implies(Permission p) { - return false; - } - - /** - * Checks two SelfPermission objects for equality. - * - * Checks that obj is an SelfPermission, and has - * the same type (class) name, permission name, actions, and - * certificates as this object. - * - * @param obj the object we are testing for equality with this object. - * - * @return true if obj is an SelfPermission, and has the same - * type (class) name, permission name, actions, and - * certificates as this object. - */ - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - - if (!(obj instanceof SelfPermission)) return false; - SelfPermission that = (SelfPermission) obj; - - if (!(this.type.equals(that.type) && this.name.equals(that.name) && this.actions.equals(that.actions))) return false; - - if ((this.certs == null) && (that.certs == null)) { - return true; - } - - if ((this.certs == null) || (that.certs == null)) { - return false; - } - - if (this.certs.length != that.certs.length) { - return false; - } - - int i, j; - boolean match; - - for (i = 0; i < this.certs.length; i++) { - match = false; - for (j = 0; j < that.certs.length; j++) { - if (this.certs[i].equals(that.certs[j])) { - match = true; - break; - } - } - if (!match) return false; - } - - for (i = 0; i < that.certs.length; i++) { - match = false; - for (j = 0; j < this.certs.length; j++) { - if (that.certs[i].equals(this.certs[j])) { - match = true; - break; - } - } - if (!match) return false; - } - return true; - } - - /** - * Returns the hash code value for this object. - * - * @return a hash code value for this object. - */ - @Override - public int hashCode() { - int hash = type.hashCode(); - if (name != null) hash ^= name.hashCode(); - if (actions != null) hash ^= actions.hashCode(); - return hash; - } - - /** - * Returns the canonical string representation of the actions, - * which currently is the empty string "", since there are no actions - * for an SelfPermission. That is, the actions for the - * permission that will be created when this SelfPermission - * is resolved may be non-null, but an SelfPermission - * itself is never considered to have any actions. - * - * @return the empty string "". - */ - @Override - public String getActions() { - return ""; - } - - public String getSelfType() { - return type; - } - - public String getSelfName() { - return name; - } - - public String getSelfActions() { - return actions; - } - - public Certificate[] getCerts() { - return (certs == null ? null : certs.clone()); - } - - /** - * Returns a string describing this SelfPermission. The convention - * is to specify the class name, the permission name, and the actions, - * in the following format: '(unresolved "ClassName" "name" "actions")'. - * - * @return information about this SelfPermission. - */ - @Override - public String toString() { - return "(SelfPermission " + type + " " + name + " " + actions + ")"; - } - - /** - * Restores the state of this object from the stream. - * - * @param stream the {@code ObjectInputStream} from which data is read - * @throws IOException if an I/O error occurs - * @throws ClassNotFoundException if a serialized class cannot be loaded - */ - @java.io.Serial - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - if (certs != null) { - this.certs = certs.clone(); - } - } - } - - /** - * holds policy information that we need to synch on - */ - private static class PolicyInfo { - // Stores grant entries in the policy - final List policyEntries; - - // Maps aliases to certs - final Map aliasMapping; - - PolicyInfo(int numCaches) { - policyEntries = new ArrayList<>(); - aliasMapping = Collections.synchronizedMap(new HashMap<>(11)); - } - } - - @SuppressWarnings("deprecation") - private static URL newURL(String spec) throws MalformedURLException { - return new URL(spec); - } -} diff --git a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PolicyParser.java b/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PolicyParser.java deleted file mode 100644 index 9d5b0d5a13722..0000000000000 --- a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PolicyParser.java +++ /dev/null @@ -1,1163 +0,0 @@ -/* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * 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.secure_sm.policy; - -import javax.security.auth.x500.X500Principal; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.StreamTokenizer; -import java.io.Writer; -import java.security.GeneralSecurityException; -import java.security.Principal; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Locale; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.TreeMap; -import java.util.Vector; - -/** - * Adapted from: https://github.com/openjdk/jdk23u/blob/master/src/java.base/share/classes/sun/security/provider/PolicyParser.java - */ -public class PolicyParser { - - private final Vector grantEntries; - private Map domainEntries; - - private StreamTokenizer st; - private int lookahead; - private boolean expandProp = false; - private String keyStoreUrlString = null; // unexpanded - private String keyStoreType = null; - private String keyStoreProvider = null; - private String storePassURL = null; - - private String expand(String value) throws PropertyExpander.ExpandException { - return expand(value, false); - } - - private String expand(String value, boolean encodeURL) throws PropertyExpander.ExpandException { - if (!expandProp) { - return value; - } else { - return PropertyExpander.expand(value, encodeURL); - } - } - - /** - * Creates a PolicyParser object. - */ - - public PolicyParser() { - grantEntries = new Vector<>(); - } - - public PolicyParser(boolean expandProp) { - this(); - this.expandProp = expandProp; - } - - /** - * Reads a policy configuration into the Policy object using a - * Reader object. - * - * @param policy the policy Reader object. - * - * @exception ParsingException if the policy configuration contains - * a syntax error. - * - * @exception IOException if an error occurs while reading the policy - * configuration. - */ - - public void read(Reader policy) throws ParsingException, IOException { - if (!(policy instanceof BufferedReader)) { - policy = new BufferedReader(policy); - } - - /* - * Configure the stream tokenizer: - * Recognize strings between "..." - * Don't convert words to lowercase - * Recognize both C-style and C++-style comments - * Treat end-of-line as white space, not as a token - */ - st = new StreamTokenizer(policy); - - st.resetSyntax(); - st.wordChars('a', 'z'); - st.wordChars('A', 'Z'); - st.wordChars('.', '.'); - st.wordChars('0', '9'); - st.wordChars('_', '_'); - st.wordChars('$', '$'); - st.wordChars(128 + 32, 255); - st.whitespaceChars(0, ' '); - st.commentChar('/'); - st.quoteChar('\''); - st.quoteChar('"'); - st.lowerCaseMode(false); - st.ordinaryChar('/'); - st.slashSlashComments(true); - st.slashStarComments(true); - - /* - * The main parsing loop. The loop is executed once - * for each entry in the config file. The entries - * are delimited by semicolons. Once we've read in - * the information for an entry, go ahead and try to - * add it to the policy vector. - * - */ - - lookahead = st.nextToken(); - GrantEntry ge = null; - while (lookahead != StreamTokenizer.TT_EOF) { - if (peek("grant")) { - ge = parseGrantEntry(); - // could be null if we couldn't expand a property - if (ge != null) add(ge); - } else if (peek("keystore") && keyStoreUrlString == null) { - // only one keystore entry per policy file, others will be - // ignored - parseKeyStoreEntry(); - } else if (peek("keystorePasswordURL") && storePassURL == null) { - // only one keystore passwordURL per policy file, others will be - // ignored - parseStorePassURL(); - } else if (ge == null && keyStoreUrlString == null && storePassURL == null && peek("domain")) { - if (domainEntries == null) { - domainEntries = new TreeMap<>(); - } - DomainEntry de = parseDomainEntry(); - String domainName = de.getName(); - if (domainEntries.putIfAbsent(domainName, de) != null) { - Object[] source = { domainName }; - String msg = "duplicate keystore domain name: " + domainName; - throw new ParsingException(msg, source); - } - } else { - // error? - } - match(";"); - } - - if (keyStoreUrlString == null && storePassURL != null) { - throw new ParsingException("Keystore Password URL cannot be specified without also specifying keystore"); - } - } - - public void add(GrantEntry ge) { - grantEntries.addElement(ge); - } - - public void replace(GrantEntry origGe, GrantEntry newGe) { - grantEntries.setElementAt(newGe, grantEntries.indexOf(origGe)); - } - - public boolean remove(GrantEntry ge) { - return grantEntries.removeElement(ge); - } - - /** - * Returns the (possibly expanded) keystore location, or null if the - * expansion fails. - */ - public String getKeyStoreUrl() { - try { - if (keyStoreUrlString != null && keyStoreUrlString.length() != 0) { - return expand(keyStoreUrlString, true).replace(File.separatorChar, '/'); - } - } catch (PropertyExpander.ExpandException peee) { - return null; - } - return null; - } - - public void setKeyStoreUrl(String url) { - keyStoreUrlString = url; - } - - public String getKeyStoreType() { - return keyStoreType; - } - - public void setKeyStoreType(String type) { - keyStoreType = type; - } - - public String getKeyStoreProvider() { - return keyStoreProvider; - } - - public void setKeyStoreProvider(String provider) { - keyStoreProvider = provider; - } - - public String getStorePassURL() { - try { - if (storePassURL != null && storePassURL.length() != 0) { - return expand(storePassURL, true).replace(File.separatorChar, '/'); - } - } catch (PropertyExpander.ExpandException peee) { - return null; - } - return null; - } - - public void setStorePassURL(String storePassURL) { - this.storePassURL = storePassURL; - } - - /** - * Enumerate all the entries in the global policy object. - * This method is used by policy admin tools. The tools - * should use the Enumeration methods on the returned object - * to fetch the elements sequentially. - */ - public Enumeration grantElements() { - return grantEntries.elements(); - } - - public Collection getDomainEntries() { - return domainEntries.values(); - } - - /** - * write out the policy - */ - - public void write(Writer policy) { - PrintWriter out = new PrintWriter(new BufferedWriter(policy)); - - out.println("/* AUTOMATICALLY GENERATED ON " + (new java.util.Date()) + "*/"); - out.println("/* DO NOT EDIT */"); - out.println(); - - // write the (unexpanded) keystore entry as the first entry of the - // policy file - if (keyStoreUrlString != null) { - writeKeyStoreEntry(out); - } - if (storePassURL != null) { - writeStorePassURL(out); - } - - // write "grant" entries - for (GrantEntry ge : grantEntries) { - ge.write(out); - out.println(); - } - out.flush(); - } - - /** - * parses a keystore entry - */ - private void parseKeyStoreEntry() throws ParsingException, IOException { - match("keystore"); - keyStoreUrlString = match("quoted string"); - - // parse keystore type - if (!peek(",")) { - return; // default type - } - match(","); - - if (peek("\"")) { - keyStoreType = match("quoted string"); - } else { - throw new ParsingException(st.lineno(), "Expected keystore type"); - } - - // parse keystore provider - if (!peek(",")) { - return; // provider optional - } - match(","); - - if (peek("\"")) { - keyStoreProvider = match("quoted string"); - } else { - throw new ParsingException(st.lineno(), "Keystore provider expected"); - } - } - - private void parseStorePassURL() throws ParsingException, IOException { - match("keyStorePasswordURL"); - storePassURL = match("quoted string"); - } - - /** - * writes the (unexpanded) keystore entry - */ - private void writeKeyStoreEntry(PrintWriter out) { - out.print("keystore \""); - out.print(keyStoreUrlString); - out.print('"'); - if (keyStoreType != null && !keyStoreType.isEmpty()) out.print(", \"" + keyStoreType + "\""); - if (keyStoreProvider != null && !keyStoreProvider.isEmpty()) out.print(", \"" + keyStoreProvider + "\""); - out.println(";"); - out.println(); - } - - private void writeStorePassURL(PrintWriter out) { - out.print("keystorePasswordURL \""); - out.print(storePassURL); - out.print('"'); - out.println(";"); - out.println(); - } - - /** - * parse a Grant entry - */ - private GrantEntry parseGrantEntry() throws ParsingException, IOException { - GrantEntry e = new GrantEntry(); - LinkedList principals = null; - boolean ignoreEntry = false; - - match("grant"); - - while (!peek("{")) { - - if (peekAndMatch("Codebase")) { - if (e.codeBase != null) throw new ParsingException(st.lineno(), "Multiple Codebase expressions"); - e.codeBase = match("quoted string"); - peekAndMatch(","); - } else if (peekAndMatch("SignedBy")) { - if (e.signedBy != null) throw new ParsingException(st.lineno(), "Multiple SignedBy expressions"); - e.signedBy = match("quoted string"); - - // verify syntax of the aliases - StringTokenizer aliases = new StringTokenizer(e.signedBy, ",", true); - int actr = 0; - int cctr = 0; - while (aliases.hasMoreTokens()) { - String alias = aliases.nextToken().trim(); - if (alias.equals(",")) cctr++; - else if (!alias.isEmpty()) actr++; - } - if (actr <= cctr) throw new ParsingException(st.lineno(), "SignedBy has an empty alias"); - - peekAndMatch(","); - } else if (peekAndMatch("Principal")) { - if (principals == null) { - principals = new LinkedList<>(); - } - - String principalClass; - String principalName; - - if (peek("\"")) { - // both the principalClass and principalName - // will be replaced later - principalClass = PrincipalEntry.REPLACE_NAME; - principalName = match("principal type"); - } else { - // check for principalClass wildcard - if (peek("*")) { - match("*"); - principalClass = PrincipalEntry.WILDCARD_CLASS; - } else { - principalClass = match("principal type"); - } - - // check for principalName wildcard - if (peek("*")) { - match("*"); - principalName = PrincipalEntry.WILDCARD_NAME; - } else { - principalName = match("quoted string"); - } - - // disallow WILDCARD_CLASS && actual name - if (principalClass.equals(PrincipalEntry.WILDCARD_CLASS) && !principalName.equals(PrincipalEntry.WILDCARD_NAME)) { - throw new ParsingException(st.lineno(), "Cannot specify Principal with a wildcard class without a wildcard name"); - } - } - - try { - principalName = expand(principalName); - - if (principalClass.equals("javax.security.auth.x500.X500Principal") - && !principalName.equals(PrincipalEntry.WILDCARD_NAME)) { - - // 4702543: X500 names with an EmailAddress - // were encoded incorrectly. construct a new - // X500Principal with correct encoding. - - X500Principal p = new X500Principal((new X500Principal(principalName)).toString()); - principalName = p.getName(); - } - - principals.add(new PrincipalEntry(principalClass, principalName)); - } catch (PropertyExpander.ExpandException peee) { - ignoreEntry = true; - } - peekAndMatch(","); - - } else { - throw new ParsingException(st.lineno(), "Expected codeBase or SignedBy or Principal"); - } - } - - if (principals != null) e.principals = principals; - match("{"); - - while (!peek("}")) { - if (peek("Permission")) { - try { - PermissionEntry pe = parsePermissionEntry(); - e.add(pe); - } catch (PropertyExpander.ExpandException peee) { - skipEntry(); // BugId 4219343 - } - match(";"); - } else { - throw new ParsingException(st.lineno(), "Expected permission entry"); - } - } - match("}"); - - try { - if (e.signedBy != null) e.signedBy = expand(e.signedBy); - if (e.codeBase != null) { - e.codeBase = expand(e.codeBase, true).replace(File.separatorChar, '/'); - } - } catch (PropertyExpander.ExpandException peee) { - return null; - } - - return (ignoreEntry) ? null : e; - } - - /** - * parse a Permission entry - */ - private PermissionEntry parsePermissionEntry() throws ParsingException, IOException, PropertyExpander.ExpandException { - PermissionEntry e = new PermissionEntry(); - - // Permission - match("Permission"); - e.permission = match("permission type"); - - if (peek("\"")) { - // Permission name - e.name = expand(match("quoted string")); - } - - if (!peek(",")) { - return e; - } - match(","); - - if (peek("\"")) { - e.action = expand(match("quoted string")); - if (!peek(",")) { - return e; - } - match(","); - } - - if (peekAndMatch("SignedBy")) { - e.signedBy = expand(match("quoted string")); - } - return e; - } - - /** - * parse a domain entry - */ - private DomainEntry parseDomainEntry() throws ParsingException, IOException { - DomainEntry domainEntry; - String name; - Map properties = new HashMap<>(); - - match("domain"); - name = match("domain name"); - - while (!peek("{")) { - // get the domain properties - properties = parseProperties("{"); - } - match("{"); - domainEntry = new DomainEntry(name, properties); - - while (!peek("}")) { - - match("keystore"); - name = match("keystore name"); - // get the keystore properties - if (!peek("}")) { - properties = parseProperties(";"); - } - match(";"); - domainEntry.add(new KeyStoreEntry(name, properties)); - } - match("}"); - - return domainEntry; - } - - /* - * Return a collection of domain properties or keystore properties. - */ - private Map parseProperties(String terminator) throws ParsingException, IOException { - - Map properties = new HashMap<>(); - String key; - String value; - while (!peek(terminator)) { - key = match("property name"); - match("="); - - try { - value = expand(match("quoted string")); - } catch (PropertyExpander.ExpandException peee) { - throw new IOException(peee.getLocalizedMessage()); - } - properties.put(key.toLowerCase(Locale.ENGLISH), value); - } - - return properties; - } - - private boolean peekAndMatch(String expect) throws ParsingException, IOException { - if (peek(expect)) { - match(expect); - return true; - } else { - return false; - } - } - - private boolean peek(String expect) { - boolean found = false; - - switch (lookahead) { - - case StreamTokenizer.TT_WORD: - if (expect.equalsIgnoreCase(st.sval)) found = true; - break; - case ',': - if (expect.equalsIgnoreCase(",")) found = true; - break; - case '{': - if (expect.equalsIgnoreCase("{")) found = true; - break; - case '}': - if (expect.equalsIgnoreCase("}")) found = true; - break; - case '"': - if (expect.equalsIgnoreCase("\"")) found = true; - break; - case '*': - if (expect.equalsIgnoreCase("*")) found = true; - break; - case ';': - if (expect.equalsIgnoreCase(";")) found = true; - break; - default: - - } - return found; - } - - private String match(String expect) throws ParsingException, IOException { - String value = null; - - switch (lookahead) { - case StreamTokenizer.TT_NUMBER: - throw new ParsingException(st.lineno(), expect); - case StreamTokenizer.TT_EOF: - Object[] source = { expect }; - String msg = "expected [" + expect + "], read [end of file]"; - throw new ParsingException(msg, source); - case StreamTokenizer.TT_WORD: - if (expect.equalsIgnoreCase(st.sval)) { - lookahead = st.nextToken(); - } else if (expect.equalsIgnoreCase("permission type")) { - value = st.sval; - lookahead = st.nextToken(); - } else if (expect.equalsIgnoreCase("principal type")) { - value = st.sval; - lookahead = st.nextToken(); - } else if (expect.equalsIgnoreCase("domain name") - || expect.equalsIgnoreCase("keystore name") - || expect.equalsIgnoreCase("property name")) { - value = st.sval; - lookahead = st.nextToken(); - } else { - throw new ParsingException(st.lineno(), expect, st.sval); - } - break; - case '"': - if (expect.equalsIgnoreCase("quoted string")) { - value = st.sval; - lookahead = st.nextToken(); - } else if (expect.equalsIgnoreCase("permission type")) { - value = st.sval; - lookahead = st.nextToken(); - } else if (expect.equalsIgnoreCase("principal type")) { - value = st.sval; - lookahead = st.nextToken(); - } else { - throw new ParsingException(st.lineno(), expect, st.sval); - } - break; - case ',': - if (expect.equalsIgnoreCase(",")) lookahead = st.nextToken(); - else throw new ParsingException(st.lineno(), expect, ","); - break; - case '{': - if (expect.equalsIgnoreCase("{")) lookahead = st.nextToken(); - else throw new ParsingException(st.lineno(), expect, "{"); - break; - case '}': - if (expect.equalsIgnoreCase("}")) lookahead = st.nextToken(); - else throw new ParsingException(st.lineno(), expect, "}"); - break; - case ';': - if (expect.equalsIgnoreCase(";")) lookahead = st.nextToken(); - else throw new ParsingException(st.lineno(), expect, ";"); - break; - case '*': - if (expect.equalsIgnoreCase("*")) lookahead = st.nextToken(); - else throw new ParsingException(st.lineno(), expect, "*"); - break; - case '=': - if (expect.equalsIgnoreCase("=")) lookahead = st.nextToken(); - else throw new ParsingException(st.lineno(), expect, "="); - break; - default: - throw new ParsingException(st.lineno(), expect, String.valueOf((char) lookahead)); - } - return value; - } - - /** - * skip all tokens for this entry leaving the delimiter ";" - * in the stream. - */ - private void skipEntry() throws ParsingException, IOException { - while (lookahead != ';') { - switch (lookahead) { - case StreamTokenizer.TT_NUMBER: - throw new ParsingException(st.lineno(), ";"); - case StreamTokenizer.TT_EOF: - throw new ParsingException("Expected read end of file"); - default: - lookahead = st.nextToken(); - } - } - } - - /** - * Each grant entry in the policy configuration file is - * represented by a GrantEntry object. - * - *

- * For example, the entry - *

-     *      grant signedBy "Duke" {
-     *          permission java.io.FilePermission "/tmp", "read,write";
-     *      };
-     *
-     * 
- * is represented internally - *
-     *
-     * pe = new PermissionEntry("java.io.FilePermission",
-     *                           "/tmp", "read,write");
-     *
-     * ge = new GrantEntry("Duke", null);
-     *
-     * ge.add(pe);
-     *
-     * 
- * - * @author Roland Schemers - * - * version 1.19, 05/21/98 - */ - - public static class GrantEntry { - - public String signedBy; - public String codeBase; - public LinkedList principals; - public Vector permissionEntries; - - public GrantEntry() { - principals = new LinkedList<>(); - permissionEntries = new Vector<>(); - } - - public GrantEntry(String signedBy, String codeBase) { - this.codeBase = codeBase; - this.signedBy = signedBy; - principals = new LinkedList<>(); - permissionEntries = new Vector<>(); - } - - public void add(PermissionEntry pe) { - permissionEntries.addElement(pe); - } - - public boolean remove(PrincipalEntry pe) { - return principals.remove(pe); - } - - public boolean remove(PermissionEntry pe) { - return permissionEntries.removeElement(pe); - } - - public boolean contains(PrincipalEntry pe) { - return principals.contains(pe); - } - - public boolean contains(PermissionEntry pe) { - return permissionEntries.contains(pe); - } - - /** - * Enumerate all the permission entries in this GrantEntry. - */ - public Enumeration permissionElements() { - return permissionEntries.elements(); - } - - public void write(PrintWriter out) { - out.print("grant"); - if (signedBy != null) { - out.print(" signedBy \""); - out.print(signedBy); - out.print('"'); - if (codeBase != null) out.print(", "); - } - if (codeBase != null) { - out.print(" codeBase \""); - out.print(codeBase); - out.print('"'); - if (principals != null && principals.size() > 0) out.print(",\n"); - } - if (principals != null && principals.size() > 0) { - Iterator pli = principals.iterator(); - while (pli.hasNext()) { - out.print(" "); - PrincipalEntry pe = pli.next(); - pe.write(out); - if (pli.hasNext()) out.print(",\n"); - } - } - out.println(" {"); - for (PermissionEntry pe : permissionEntries) { - out.write(" "); - pe.write(out); - } - out.println("};"); - } - - public Object clone() { - GrantEntry ge = new GrantEntry(); - ge.codeBase = this.codeBase; - ge.signedBy = this.signedBy; - ge.principals = new LinkedList<>(this.principals); - ge.permissionEntries = new Vector<>(this.permissionEntries); - return ge; - } - } - - /** - * Principal info (class and name) in a grant entry - */ - public static class PrincipalEntry implements Principal { - - public static final String WILDCARD_CLASS = "WILDCARD_PRINCIPAL_CLASS"; - public static final String WILDCARD_NAME = "WILDCARD_PRINCIPAL_NAME"; - public static final String REPLACE_NAME = "PolicyParser.REPLACE_NAME"; - - String principalClass; - String principalName; - - /** - * A PrincipalEntry consists of the Principal class and Principal name. - * - * @param principalClass the Principal class - * @param principalName the Principal name - * @throws NullPointerException if principalClass or principalName - * are null - */ - public PrincipalEntry(String principalClass, String principalName) { - if (principalClass == null || principalName == null) throw new NullPointerException("principalClass or principalName is null"); - this.principalClass = principalClass; - this.principalName = principalName; - } - - boolean isWildcardName() { - return principalName.equals(WILDCARD_NAME); - } - - boolean isWildcardClass() { - return principalClass.equals(WILDCARD_CLASS); - } - - boolean isReplaceName() { - return principalClass.equals(REPLACE_NAME); - } - - public String getPrincipalClass() { - return principalClass; - } - - public String getPrincipalName() { - return principalName; - } - - public String getDisplayClass() { - if (isWildcardClass()) { - return "*"; - } else if (isReplaceName()) { - return ""; - } else return principalClass; - } - - public String getDisplayName() { - return getDisplayName(false); - } - - public String getDisplayName(boolean addQuote) { - if (isWildcardName()) { - return "*"; - } else { - if (addQuote) return "\"" + principalName + "\""; - else return principalName; - } - } - - @Override - public String getName() { - return principalName; - } - - @Override - public String toString() { - if (!isReplaceName()) { - return getDisplayClass() + "/" + getDisplayName(); - } else { - return getDisplayName(); - } - } - - /** - * Test for equality between the specified object and this object. - * Two PrincipalEntries are equal if their class and name values - * are equal. - * - * @param obj the object to test for equality with this object - * @return true if the objects are equal, false otherwise - */ - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - - if (!(obj instanceof PrincipalEntry that)) return false; - - return (principalClass.equals(that.principalClass) && principalName.equals(that.principalName)); - } - - /** - * Return a hashcode for this PrincipalEntry. - * - * @return a hashcode for this PrincipalEntry - */ - @Override - public int hashCode() { - return principalClass.hashCode(); - } - - public void write(PrintWriter out) { - out.print("principal " + getDisplayClass() + " " + getDisplayName(true)); - } - } - - /** - * Each permission entry in the policy configuration file is - * represented by a - * PermissionEntry object. - * - *

- * For example, the entry - *

-     *          permission java.io.FilePermission "/tmp", "read,write";
-     * 
- * is represented internally - *
-     *
-     * pe = new PermissionEntry("java.io.FilePermission",
-     *                           "/tmp", "read,write");
-     * 
- * - * @author Roland Schemers - * - * version 1.19, 05/21/98 - */ - - public static class PermissionEntry { - - public String permission; - public String name; - public String action; - public String signedBy; - - public PermissionEntry() {} - - public PermissionEntry(String permission, String name, String action) { - this.permission = permission; - this.name = name; - this.action = action; - } - - /** - * Calculates a hash code value for the object. Objects - * which are equal will also have the same hashcode. - */ - @Override - public int hashCode() { - int retval = permission.hashCode(); - if (name != null) retval ^= name.hashCode(); - if (action != null) retval ^= action.hashCode(); - return retval; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - - if (!(obj instanceof PermissionEntry that)) return false; - - if (this.permission == null) { - if (that.permission != null) return false; - } else { - if (!this.permission.equals(that.permission)) return false; - } - - if (this.name == null) { - if (that.name != null) return false; - } else { - if (!this.name.equals(that.name)) return false; - } - - if (this.action == null) { - if (that.action != null) return false; - } else { - if (!this.action.equals(that.action)) return false; - } - - if (this.signedBy == null) { - return that.signedBy == null; - } else { - return this.signedBy.equals(that.signedBy); - } - } - - public void write(PrintWriter out) { - out.print("permission "); - out.print(permission); - if (name != null) { - out.print(" \""); - - // ATTENTION: regex with double escaping, - // the normal forms look like: - // $name =~ s/\\/\\\\/g; and - // $name =~ s/\"/\\\"/g; - // and then in a java string, it's escaped again - - out.print(name.replaceAll("\\\\", "\\\\\\\\").replaceAll("\"", "\\\\\\\"")); - out.print('"'); - } - if (action != null) { - out.print(", \""); - out.print(action); - out.print('"'); - } - if (signedBy != null) { - out.print(", signedBy \""); - out.print(signedBy); - out.print('"'); - } - out.println(";"); - } - } - - /** - * Each domain entry in the keystore domain configuration file is - * represented by a DomainEntry object. - */ - static class DomainEntry { - private final String name; - private final Map properties; - private final Map entries; - - DomainEntry(String name, Map properties) { - this.name = name; - this.properties = properties; - entries = new HashMap<>(); - } - - String getName() { - return name; - } - - Map getProperties() { - return properties; - } - - Collection getEntries() { - return entries.values(); - } - - void add(KeyStoreEntry entry) throws ParsingException { - String keystoreName = entry.getName(); - if (!entries.containsKey(keystoreName)) { - entries.put(keystoreName, entry); - } else { - Object[] source = { keystoreName }; - String msg = "duplicate keystore name: " + keystoreName; - throw new ParsingException(msg, source); - } - } - - @Override - public String toString() { - StringBuilder s = new StringBuilder("\ndomain ").append(name); - - if (properties != null) { - for (Map.Entry property : properties.entrySet()) { - s.append("\n ").append(property.getKey()).append('=').append(property.getValue()); - } - } - s.append(" {\n"); - - for (KeyStoreEntry entry : entries.values()) { - s.append(entry).append("\n"); - } - s.append("}"); - - return s.toString(); - } - } - - /** - * Each keystore entry in the keystore domain configuration file is - * represented by a KeyStoreEntry object. - */ - - static class KeyStoreEntry { - private final String name; - private final Map properties; - - KeyStoreEntry(String name, Map properties) { - this.name = name; - this.properties = properties; - } - - String getName() { - return name; - } - - Map getProperties() { - return properties; - } - - @Override - public String toString() { - StringBuilder s = new StringBuilder("\n keystore ").append(name); - if (properties != null) { - for (Map.Entry property : properties.entrySet()) { - s.append("\n ").append(property.getKey()).append('=').append(property.getValue()); - } - } - s.append(";"); - - return s.toString(); - } - } - - public static class ParsingException extends GeneralSecurityException { - - @java.io.Serial - private static final long serialVersionUID = -4330692689482574072L; - - @SuppressWarnings("serial") // Not statically typed as Serializable - private Object[] source; - - /** - * Constructs a ParsingException with the specified - * detail message. A detail message is a String that describes - * this particular exception, which may, for example, specify which - * algorithm is not available. - * - * @param msg the detail message. - */ - public ParsingException(String msg) { - super(msg); - } - - public ParsingException(String msg, Object[] source) { - super(msg); - this.source = source; - } - - public ParsingException(int line, String msg) { - super("line " + line + ": " + msg); - source = new Object[] { line, msg }; - } - - public ParsingException(int line, String expect, String actual) { - super("line " + line + ": expected [" + expect + "], found [" + actual + "]"); - source = new Object[] { line, expect, actual }; - } - } -} diff --git a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PolicyUtil.java b/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PolicyUtil.java deleted file mode 100644 index ed19379b697c0..0000000000000 --- a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PolicyUtil.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * 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.secure_sm.policy; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.Arrays; - -/** - * Adapted from: https://github.com/openjdk/jdk23u/blob/master/src/java.base/share/classes/sun/security/util/PolicyUtil.java - */ -public class PolicyUtil { - - // standard PKCS11 KeyStore type - private static final String P11KEYSTORE = "PKCS11"; - - // reserved word - private static final String NONE = "NONE"; - - /* - * Fast path reading from file urls in order to avoid calling - * FileURLConnection.connect() which can be quite slow the first time - * it is called. We really should clean up FileURLConnection so that - * this is not a problem but in the meantime this fix helps reduce - * start up time noticeably for the new launcher. -- DAC - */ - public static InputStream getInputStream(URL url) throws IOException { - if ("file".equals(url.getProtocol())) { - String path = url.getFile().replace('/', File.separatorChar); - path = ParseUtil.decode(path); - return new FileInputStream(path); - } else { - return url.openStream(); - } - } - - /** - * this is intended for use by the policy parser to - * instantiate a KeyStore from the information in the GUI/policy file - */ - public static KeyStore getKeyStore( - URL policyUrl, // URL of policy file - String keyStoreName, // input: keyStore URL - String keyStoreType, // input: keyStore type - String keyStoreProvider, // input: keyStore provider - String storePassURL // input: keyStore password - ) throws KeyStoreException, IOException, NoSuchProviderException, NoSuchAlgorithmException, java.security.cert.CertificateException { - - if (keyStoreName == null) { - throw new IllegalArgumentException("null KeyStore name"); - } - - char[] keyStorePassword = null; - try { - KeyStore ks; - if (keyStoreType == null) { - keyStoreType = KeyStore.getDefaultType(); - } - - if (P11KEYSTORE.equalsIgnoreCase(keyStoreType) && !NONE.equals(keyStoreName)) { - throw new IllegalArgumentException( - "Invalid value (" - + keyStoreName - + ") for keystore URL. If the keystore type is \"" - + P11KEYSTORE - + "\", the keystore url must be \"" - + NONE - + "\"" - ); - } - - if (keyStoreProvider != null) { - ks = KeyStore.getInstance(keyStoreType, keyStoreProvider); - } else { - ks = KeyStore.getInstance(keyStoreType); - } - - if (storePassURL != null) { - URL passURL; - try { - @SuppressWarnings("deprecation") - var _unused = passURL = new URL(storePassURL); - // absolute URL - } catch (MalformedURLException e) { - // relative URL - if (policyUrl == null) { - throw e; - } - @SuppressWarnings("deprecation") - var _unused = passURL = new URL(policyUrl, storePassURL); - } - - try (InputStream in = passURL.openStream()) { - keyStorePassword = Password.readPassword(in); - } - } - - if (NONE.equals(keyStoreName)) { - ks.load(null, keyStorePassword); - } else { - /* - * location of keystore is specified as absolute URL in policy - * file, or is relative to URL of policy file - */ - URL keyStoreUrl; - try { - @SuppressWarnings("deprecation") - var _unused = keyStoreUrl = new URL(keyStoreName); - // absolute URL - } catch (MalformedURLException e) { - // relative URL - if (policyUrl == null) { - throw e; - } - @SuppressWarnings("deprecation") - var _unused = keyStoreUrl = new URL(policyUrl, keyStoreName); - } - - try (InputStream inStream = new BufferedInputStream(getInputStream(keyStoreUrl))) { - ks.load(inStream, keyStorePassword); - } - } - return ks; - } finally { - if (keyStorePassword != null) { - Arrays.fill(keyStorePassword, ' '); - } - } - } -} diff --git a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PropertyExpander.java b/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PropertyExpander.java deleted file mode 100644 index 759822b0ef2b5..0000000000000 --- a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/PropertyExpander.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * 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.secure_sm.policy; - -import java.net.URI; -import java.net.URISyntaxException; -import java.security.GeneralSecurityException; - -/** - * Adapted from: https://github.com/openjdk/jdk23u/blob/master/src/java.base/share/classes/sun/security/util/PropertyExpander.java - */ -public class PropertyExpander { - - public static class ExpandException extends GeneralSecurityException { - private static final long serialVersionUID = -1L; - - public ExpandException(String msg) { - super(msg); - } - } - - public static String expand(String value) throws ExpandException { - return expand(value, false); - } - - public static String expand(String value, boolean encodeURL) throws ExpandException { - if (value == null) return null; - - int p = value.indexOf("${"); - - // no special characters - if (p == -1) return value; - - StringBuilder sb = new StringBuilder(value.length()); - int max = value.length(); - int i = 0; // index of last character we copied - - scanner: while (p < max) { - if (p > i) { - // copy in anything before the special stuff - sb.append(value.substring(i, p)); - } - int pe = p + 2; - - // do not expand ${{ ... }} - if (pe < max && value.charAt(pe) == '{') { - pe = value.indexOf("}}", pe); - if (pe == -1 || pe + 2 == max) { - // append remaining chars - sb.append(value.substring(p)); - break scanner; - } else { - // append as normal text - pe++; - sb.append(value.substring(p, pe + 1)); - } - } else { - while ((pe < max) && (value.charAt(pe) != '}')) { - pe++; - } - if (pe == max) { - // no matching '}' found, just add in as normal text - sb.append(value.substring(p, pe)); - break scanner; - } - String prop = value.substring(p + 2, pe); - if (prop.equals("/")) { - sb.append(java.io.File.separatorChar); - } else { - String val = System.getProperty(prop); - if (val != null) { - if (encodeURL) { - // encode 'val' unless it's an absolute URI - // at the beginning of the string buffer - try { - if (sb.length() > 0 || !(new URI(val)).isAbsolute()) { - val = ParseUtil.encodePath(val); - } - } catch (URISyntaxException use) { - val = ParseUtil.encodePath(val); - } - } - sb.append(val); - } else { - throw new ExpandException("unable to expand property " + prop); - } - } - } - i = pe + 1; - p = value.indexOf("${", i); - if (p == -1) { - // no more to expand. copy in any extra - if (i < max) { - sb.append(value.substring(i, max)); - } - // break out of loop - break scanner; - } - } - return sb.toString(); - } -} diff --git a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/SecurityConstants.java b/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/SecurityConstants.java deleted file mode 100644 index 39e8efd87868c..0000000000000 --- a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/SecurityConstants.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * 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.secure_sm.policy; - -import java.lang.reflect.ReflectPermission; -import java.net.NetPermission; -import java.net.SocketPermission; -import java.security.AllPermission; -import java.security.SecurityPermission; - -/** - * Adapted from: https://github.com/openjdk/jdk23u/blob/master/src/java.base/share/classes/sun/security/util/SecurityConstants.java - */ -public final class SecurityConstants { - // Cannot create one of these - private SecurityConstants() {} - - // Commonly used string constants for permission actions used by - // SecurityManager. Declare here for shortcut when checking permissions - // in FilePermission, SocketPermission, and PropertyPermission. - - public static final String FILE_DELETE_ACTION = "delete"; - public static final String FILE_EXECUTE_ACTION = "execute"; - public static final String FILE_READ_ACTION = "read"; - public static final String FILE_WRITE_ACTION = "write"; - public static final String FILE_READLINK_ACTION = "readlink"; - - public static final String SOCKET_RESOLVE_ACTION = "resolve"; - public static final String SOCKET_CONNECT_ACTION = "connect"; - public static final String SOCKET_LISTEN_ACTION = "listen"; - public static final String SOCKET_ACCEPT_ACTION = "accept"; - public static final String SOCKET_CONNECT_ACCEPT_ACTION = "connect,accept"; - - public static final String PROPERTY_RW_ACTION = "read,write"; - public static final String PROPERTY_READ_ACTION = "read"; - public static final String PROPERTY_WRITE_ACTION = "write"; - - // Permission constants used in the various checkPermission() calls in JDK. - - // java.lang.Class, java.lang.SecurityManager, java.lang.System, - // java.net.URLConnection, java.security.AllPermission, java.security.Policy, - // sun.security.provider.PolicyFile - public static final AllPermission ALL_PERMISSION = new AllPermission(); - - // java.net.URL - public static final NetPermission SPECIFY_HANDLER_PERMISSION = new NetPermission("specifyStreamHandler"); - - // java.net.ProxySelector - public static final NetPermission SET_PROXYSELECTOR_PERMISSION = new NetPermission("setProxySelector"); - - // java.net.ProxySelector - public static final NetPermission GET_PROXYSELECTOR_PERMISSION = new NetPermission("getProxySelector"); - - // java.net.CookieHandler - public static final NetPermission SET_COOKIEHANDLER_PERMISSION = new NetPermission("setCookieHandler"); - - // java.net.CookieHandler - public static final NetPermission GET_COOKIEHANDLER_PERMISSION = new NetPermission("getCookieHandler"); - - // java.net.ResponseCache - public static final NetPermission SET_RESPONSECACHE_PERMISSION = new NetPermission("setResponseCache"); - - // java.net.ResponseCache - public static final NetPermission GET_RESPONSECACHE_PERMISSION = new NetPermission("getResponseCache"); - - // java.net.ServerSocket, java.net.Socket - public static final NetPermission SET_SOCKETIMPL_PERMISSION = new NetPermission("setSocketImpl"); - - // java.lang.SecurityManager, sun.applet.AppletPanel - public static final RuntimePermission CREATE_CLASSLOADER_PERMISSION = new RuntimePermission("createClassLoader"); - - // java.lang.SecurityManager - public static final RuntimePermission CHECK_MEMBER_ACCESS_PERMISSION = new RuntimePermission("accessDeclaredMembers"); - - // java.lang.SecurityManager, sun.applet.AppletSecurity - public static final RuntimePermission MODIFY_THREAD_PERMISSION = new RuntimePermission("modifyThread"); - - // java.lang.SecurityManager, sun.applet.AppletSecurity - public static final RuntimePermission MODIFY_THREADGROUP_PERMISSION = new RuntimePermission("modifyThreadGroup"); - - // java.lang.Class - public static final RuntimePermission GET_PD_PERMISSION = new RuntimePermission("getProtectionDomain"); - - // java.lang.Class, java.lang.ClassLoader, java.lang.Thread - public static final RuntimePermission GET_CLASSLOADER_PERMISSION = new RuntimePermission("getClassLoader"); - - // java.lang.Thread - public static final RuntimePermission STOP_THREAD_PERMISSION = new RuntimePermission("stopThread"); - - // java.lang.Thread - public static final RuntimePermission GET_STACK_TRACE_PERMISSION = new RuntimePermission("getStackTrace"); - - // java.lang.Thread - public static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION = new RuntimePermission("enableContextClassLoaderOverride"); - - // java.security.AccessControlContext - public static final SecurityPermission CREATE_ACC_PERMISSION = new SecurityPermission("createAccessControlContext"); - - // java.security.AccessControlContext - public static final SecurityPermission GET_COMBINER_PERMISSION = new SecurityPermission("getDomainCombiner"); - - // java.security.Policy, java.security.ProtectionDomain - public static final SecurityPermission GET_POLICY_PERMISSION = new SecurityPermission("getPolicy"); - - // java.lang.SecurityManager - public static final SocketPermission LOCAL_LISTEN_PERMISSION = new SocketPermission("localhost:0", SOCKET_LISTEN_ACTION); - - // java.lang.reflect.AccessibleObject - public static final ReflectPermission ACCESS_PERMISSION = new ReflectPermission("suppressAccessChecks"); - - // sun.reflect.ReflectionFactory - public static final RuntimePermission REFLECTION_FACTORY_ACCESS_PERMISSION = new RuntimePermission("reflectionFactoryAccess"); - -} diff --git a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/package-info.java b/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/package-info.java deleted file mode 100644 index d182490b8d173..0000000000000 --- a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/package-info.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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. - */ - -/** - * Java Agent Policy - */ -package org.opensearch.secure_sm.policy; diff --git a/libs/agent-sm/bootstrap/build.gradle b/libs/agent-sm/bootstrap/build.gradle deleted file mode 100644 index 1757e3cd75c99..0000000000000 --- a/libs/agent-sm/bootstrap/build.gradle +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -apply plugin: 'opensearch.build' -apply plugin: 'opensearch.publish' - -base { - archivesName = 'opensearch-agent-bootstrap' -} - -tasks.named('forbiddenApisMain').configure { - replaceSignatureFiles 'jdk-signatures' -} - -test.enabled = false -testingConventions.enabled = false diff --git a/libs/agent-sm/bootstrap/src/main/java/org/opensearch/javaagent/bootstrap/AgentPolicy.java b/libs/agent-sm/bootstrap/src/main/java/org/opensearch/javaagent/bootstrap/AgentPolicy.java deleted file mode 100644 index d2c77fac011b5..0000000000000 --- a/libs/agent-sm/bootstrap/src/main/java/org/opensearch/javaagent/bootstrap/AgentPolicy.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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.javaagent.bootstrap; - -import java.lang.StackWalker.Option; -import java.lang.StackWalker.StackFrame; -import java.security.Permission; -import java.security.Policy; -import java.security.ProtectionDomain; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -/** - * Agent Policy - */ -@SuppressWarnings("removal") -public class AgentPolicy { - private static final Logger LOGGER = Logger.getLogger(AgentPolicy.class.getName()); - private static volatile Policy policy; - private static volatile Set trustedHosts; - - private AgentPolicy() {} - - /** - * Set Agent policy - * @param policy policy - */ - public static void setPolicy(Policy policy) { - setPolicy(policy, Set.of()); - } - - /** - * Set Agent policy - * @param policy policy - * @param trustedHosts trusted hosts - */ - public static void setPolicy(Policy policy, final Set trustedHosts) { - if (AgentPolicy.policy == null) { - AgentPolicy.policy = policy; - AgentPolicy.trustedHosts = Collections.unmodifiableSet(trustedHosts); - LOGGER.info("Policy attached successfully: " + policy); - } else { - throw new SecurityException("The Policy has been set already: " + AgentPolicy.policy); - } - } - - /** - * Check permissions - * @param permission permission - */ - public static void checkPermission(Permission permission) { - final StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE); - final List callers = walker.walk( - frames -> frames.map(StackFrame::getDeclaringClass).map(Class::getProtectionDomain).distinct().collect(Collectors.toList()) - ); - - for (final ProtectionDomain domain : callers) { - if (!policy.implies(domain, permission)) { - throw new SecurityException("Denied access: " + permission); - } - } - } - - /** - * Get policy - * @return policy - */ - public static Policy getPolicy() { - return policy; - } - - /** - * Check if hostname is trusted - * @param hostname hostname - * @return is trusted or not - */ - public static boolean isTrustedHost(String hostname) { - return AgentPolicy.trustedHosts.contains(hostname); - } -} diff --git a/libs/agent-sm/bootstrap/src/main/java/org/opensearch/javaagent/bootstrap/package-info.java b/libs/agent-sm/bootstrap/src/main/java/org/opensearch/javaagent/bootstrap/package-info.java deleted file mode 100644 index 6172ae511a8f7..0000000000000 --- a/libs/agent-sm/bootstrap/src/main/java/org/opensearch/javaagent/bootstrap/package-info.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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. - */ - -/** - * Java Agent Policy - */ -package org.opensearch.javaagent.bootstrap; diff --git a/libs/agent-sm/bootstrap/src/main/java/org/opensearch/package-info.java b/libs/agent-sm/bootstrap/src/main/java/org/opensearch/package-info.java deleted file mode 100644 index 8fb377151ae39..0000000000000 --- a/libs/agent-sm/bootstrap/src/main/java/org/opensearch/package-info.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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. - */ - -/** - * Java Agent Policy Bootstrap - */ -package org.opensearch; diff --git a/libs/agent-sm/build.gradle b/libs/agent-sm/build.gradle deleted file mode 100644 index 656411a08080f..0000000000000 --- a/libs/agent-sm/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -// This file is intentionally blank. All configuration of the -// distribution is done in the parent project. - -// See please https://docs.gradle.org/8.5/userguide/upgrading_version_8.html#deprecated_missing_project_directory - -base { - archivesName = 'opensearch-agent-sm' -} - -test.enabled = false -testingConventions.enabled = false