diff --git a/plugin-security.policy b/plugin-security.policy index 6a78a5cc91..9c96e5e4a1 100644 --- a/plugin-security.policy +++ b/plugin-security.policy @@ -78,6 +78,7 @@ grant { //Enable this permission to debug unauthorized de-serialization attempt //permission java.io.SerializablePermission "enableSubstitution"; + permission java.net.NetPermission "accessUnixDomainSocket"; }; grant codeBase "${codebase.netty-common}" { diff --git a/src/main/java/org/opensearch/security/ssl/OpenSearchSecureSettingsFactory.java b/src/main/java/org/opensearch/security/ssl/OpenSearchSecureSettingsFactory.java index 3b511ba002..129382b5ec 100644 --- a/src/main/java/org/opensearch/security/ssl/OpenSearchSecureSettingsFactory.java +++ b/src/main/java/org/opensearch/security/ssl/OpenSearchSecureSettingsFactory.java @@ -23,6 +23,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.http.HttpServerTransport; import org.opensearch.http.netty4.ssl.SecureNetty4HttpServerTransport; +import org.opensearch.plugins.SecureAuxTransportSettingsProvider; import org.opensearch.plugins.SecureHttpTransportSettingsProvider; import org.opensearch.plugins.SecureSettingsFactory; import org.opensearch.plugins.SecureTransportSettingsProvider; @@ -185,4 +186,9 @@ public Optional buildSecureHttpServerEngine(Settings settings, HttpSe } }); } + + @Override + public Optional getSecureAuxTransportSettingsProvider(Settings settings) { + return Optional.empty(); + } } diff --git a/src/main/java/org/opensearch/security/tools/democonfig/CertificateGenerator.java b/src/main/java/org/opensearch/security/tools/democonfig/CertificateGenerator.java index 077bf4610f..c1e4b43cd2 100644 --- a/src/main/java/org/opensearch/security/tools/democonfig/CertificateGenerator.java +++ b/src/main/java/org/opensearch/security/tools/democonfig/CertificateGenerator.java @@ -33,23 +33,14 @@ public CertificateGenerator(Installer installer) { public void createDemoCertificates() { for (Certificates cert : Certificates.values()) { String filePath = this.installer.OPENSEARCH_CONF_DIR + File.separator + cert.getFileName(); - writeCertificateToFile(filePath, cert.getContent()); - } - } - - /** - * Helper method to write the certificates to their own file - * @param filePath the file which needs to be written - * @param content the content which needs to be written to this file - */ - static void writeCertificateToFile(String filePath, String content) { - try { - FileWriter fileWriter = new FileWriter(filePath, StandardCharsets.UTF_8); - fileWriter.write(content); - fileWriter.close(); - } catch (IOException e) { - System.err.println("Error writing certificate file: " + filePath); - System.exit(-1); + try { + FileWriter fileWriter = new FileWriter(filePath, StandardCharsets.UTF_8); + fileWriter.write(cert.getContent()); + fileWriter.close(); + } catch (IOException e) { + System.err.println("Error writing certificate file: " + filePath); + installer.getExitHandler().exit(-1); + } } } } diff --git a/src/main/java/org/opensearch/security/tools/democonfig/DefaultExitHandler.java b/src/main/java/org/opensearch/security/tools/democonfig/DefaultExitHandler.java new file mode 100644 index 0000000000..85a5cbae18 --- /dev/null +++ b/src/main/java/org/opensearch/security/tools/democonfig/DefaultExitHandler.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package org.opensearch.security.tools.democonfig; + +/** + * Default ExitHandler implementation that calls System.exit. + */ +public final class DefaultExitHandler implements ExitHandler { + @Override + public void exit(int status) { + System.exit(status); + } +} diff --git a/src/main/java/org/opensearch/security/tools/democonfig/ExitHandler.java b/src/main/java/org/opensearch/security/tools/democonfig/ExitHandler.java new file mode 100644 index 0000000000..5aba3b2915 --- /dev/null +++ b/src/main/java/org/opensearch/security/tools/democonfig/ExitHandler.java @@ -0,0 +1,19 @@ +/* + * 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. + */ + +package org.opensearch.security.tools.democonfig; + +/** + * An interface to handle exit behavior. + */ +public interface ExitHandler { + void exit(int status); +} diff --git a/src/main/java/org/opensearch/security/tools/democonfig/Installer.java b/src/main/java/org/opensearch/security/tools/democonfig/Installer.java index 6c3e9b3eed..a56af90d2d 100644 --- a/src/main/java/org/opensearch/security/tools/democonfig/Installer.java +++ b/src/main/java/org/opensearch/security/tools/democonfig/Installer.java @@ -11,6 +11,7 @@ package org.opensearch.security.tools.democonfig; +// CS-SUPPRESS-SINGLE: RegexpSingleline Extension is used to refer to file extensions, keeping this rule disable for the whole file import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -40,7 +41,6 @@ public class Installer { private static Installer instance; private static SecuritySettingsConfigurer securitySettingsConfigurer; - private static CertificateGenerator certificateGenerator; boolean assumeyes = false; @@ -71,19 +71,37 @@ public class Installer { // To print help information for this script private final HelpFormatter formatter = new HelpFormatter(); + private ExitHandler exitHandler; + /** * We do not want this class to be instantiated more than once, - * as we are following Singleton Factory pattern + * as we are following the Singleton pattern. */ private Installer() { this.OS = System.getProperty("os.name") + " " + System.getProperty("os.version") + " " + System.getProperty("os.arch"); FILE_EXTENSION = OS.toLowerCase().contains("win") ? ".bat" : ".sh"; options = new Options(); + // Use the default exit handler (simply calls System.exit) + this.exitHandler = new DefaultExitHandler(); + } + + /** + * Allows dependency injection of an ExitHandler. + */ + public void setExitHandler(ExitHandler exitHandler) { + this.exitHandler = exitHandler; } /** - * Returns a singleton instance of this class - * @return an existing instance OR a new instance if there was no existing instance + * Returns current exit handler + */ + public ExitHandler getExitHandler() { + return this.exitHandler; + } + + /** + * Returns a singleton instance of this class. + * @return an existing instance OR a new instance if there was no existing instance. */ public static Installer getInstance() { if (instance == null) { @@ -95,8 +113,8 @@ public static Installer getInstance() { } /** - * Installs the demo security configuration - * @param options the options passed to the script + * Installs the demo security configuration. + * @param options the options passed to the script. */ public void installDemoConfiguration(String[] options) throws IOException { readOptions(options); @@ -116,7 +134,7 @@ public static void main(String[] options) throws IOException { } /** - * Builds options supported by this tool + * Builds options supported by this tool. */ void buildOptions() { options.addOption("h", "show-help", false, "Shows help for this tool."); @@ -148,7 +166,7 @@ void buildOptions() { } /** - * Prints headers that indicate the start of script execution + * Prints headers that indicate the start of script execution. */ static void printScriptHeaders() { System.out.println("### OpenSearch Security Demo Installer"); @@ -156,8 +174,8 @@ static void printScriptHeaders() { } /** - * Reads the options passed to the script - * @param args an array of strings containing options passed to the script + * Reads the options passed to the script. + * @param args an array of strings containing options passed to the script. */ void readOptions(String[] args) { // set script execution dir @@ -179,28 +197,28 @@ void readOptions(String[] args) { } catch (ParseException exp) { System.out.println("ERR: Parsing failed. Reason: " + exp.getMessage()); - System.exit(-1); + exitHandler.exit(-1); } } /** - * Prints the help menu when -h option is passed + * Prints the help menu when -h option is passed. */ void showHelp() { formatter.printHelp("install_demo_configuration" + FILE_EXTENSION, options, true); - System.exit(0); + exitHandler.exit(0); } /** - * Prompt the user and collect user inputs - * Input collection will be skipped if -y option was passed + * Prompt the user and collect user inputs. + * Input collection will be skipped if -y option was passed. */ void gatherUserInputs() { if (!assumeyes) { try (Scanner scanner = new Scanner(System.in, StandardCharsets.UTF_8)) { if (!confirmAction(scanner, "Install demo certificates?")) { - System.exit(0); + exitHandler.exit(0); } if (!initsecurity) { @@ -218,9 +236,9 @@ void gatherUserInputs() { /** * Helper method to scan user inputs. - * @param scanner object to be used for scanning user input - * @param message prompt question - * @return true or false based on user input + * @param scanner object to be used for scanning user input. + * @param message prompt question. + * @return true or false based on user input. */ boolean confirmAction(Scanner scanner, String message) { System.out.print(message + " [y/N] "); @@ -229,7 +247,7 @@ boolean confirmAction(Scanner scanner, String message) { } /** - * Initialize all class level variables required + * Initialize all class level variables required. */ void initializeVariables() { setBaseDir(); @@ -238,7 +256,7 @@ void initializeVariables() { } /** - * Sets the base directory to be used by the script + * Sets the base directory to be used by the script. */ void setBaseDir() { File baseDirFile = new File(SCRIPT_DIR).getParentFile().getParentFile().getParentFile(); @@ -246,14 +264,14 @@ void setBaseDir() { if (BASE_DIR == null || !new File(BASE_DIR).isDirectory()) { System.out.println("DEBUG: basedir does not exist"); - System.exit(-1); + exitHandler.exit(-1); } BASE_DIR += File.separator; } /** - * Sets the variables for items at OpenSearch level + * Sets the variables for items at OpenSearch level. */ void setOpenSearchVariables() { OPENSEARCH_CONF_FILE = BASE_DIR + "config" + File.separator + "opensearch.yml"; @@ -266,7 +284,7 @@ void setOpenSearchVariables() { if (!errorMessages.isEmpty()) { errorMessages.forEach(System.out::println); - System.exit(-1); + exitHandler.exit(-1); } OPENSEARCH_CONF_DIR = new File(OPENSEARCH_CONF_FILE).getParent(); @@ -274,9 +292,9 @@ void setOpenSearchVariables() { } /** - * Helper method - * Returns a set of error messages for the paths that didn't contain files/directories - * @return a set containing error messages if any, empty otherwise + * Helper method. + * Returns a set of error messages for the paths that didn't contain files/directories. + * @return a set containing error messages if any, empty otherwise. */ private Set validatePaths() { Set errorMessages = new HashSet<>(); @@ -299,8 +317,8 @@ private Set validatePaths() { } /** - * Returns the installation type based on the underlying operating system - * @return will be one of `.zip`, `.tar.gz` or `rpm/deb` + * Returns the installation type based on the underlying operating system. + * @return will be one of `.zip`, `.tar.gz` or `rpm/deb`. */ String determineInstallType() { // windows (.bat execution) @@ -320,12 +338,12 @@ String determineInstallType() { } /** - * Sets the path variables for items at OpenSearch security plugin level + * Sets the path variables for items at OpenSearch security plugin level. */ void setSecurityVariables() { if (!(new File(OPENSEARCH_PLUGINS_DIR + "opensearch-security").exists())) { System.out.println("OpenSearch Security plugin not installed. Quit."); - System.exit(-1); + exitHandler.exit(-1); } // Extract OpenSearch version and Security version @@ -349,7 +367,7 @@ void setSecurityVariables() { } /** - * Prints the initialized variables + * Prints the initialized variables. */ void printVariables() { System.out.println("OpenSearch install type: " + OPENSEARCH_INSTALL_TYPE + " on " + OS); @@ -439,9 +457,11 @@ void finishScriptExecution() { /** * FOR TESTS ONLY - * resets the installer state to allow testing with fresh instance for the next test. + * Resets the installer state to allow testing with a fresh instance for the next test. */ static void resetInstance() { instance = null; } + } +// CS-ENFORCE-SINGLE diff --git a/src/main/java/org/opensearch/security/tools/democonfig/SecuritySettingsConfigurer.java b/src/main/java/org/opensearch/security/tools/democonfig/SecuritySettingsConfigurer.java index 572773095a..9513f355b3 100644 --- a/src/main/java/org/opensearch/security/tools/democonfig/SecuritySettingsConfigurer.java +++ b/src/main/java/org/opensearch/security/tools/democonfig/SecuritySettingsConfigurer.java @@ -118,7 +118,7 @@ void checkIfSecurityPluginIsAlreadyConfigured() { for (String key : yamlData.keySet()) { if (key.startsWith("plugins.security")) { System.out.println(installer.OPENSEARCH_CONF_FILE + " seems to be already configured for Security. Quit."); - System.exit(installer.skip_updates); + installer.getExitHandler().exit(installer.skip_updates); } } // Check for nested keys @@ -127,18 +127,18 @@ void checkIfSecurityPluginIsAlreadyConfigured() { for (String key : plugins.keySet()) { if (key.startsWith("security")) { System.out.println(installer.OPENSEARCH_CONF_FILE + " seems to be already configured for Security. Quit."); - System.exit(installer.skip_updates); + installer.getExitHandler().exit(installer.skip_updates); } } } } } catch (IOException e) { System.err.println("Error reading configuration file."); - System.exit(-1); + installer.getExitHandler().exit(-1); } } else { System.err.println("OpenSearch configuration file does not exist. Quit."); - System.exit(-1); + installer.getExitHandler().exit(-1); } } @@ -155,7 +155,6 @@ void updateAdminPassword() throws IOException { return; } - // if hashed value for default password "admin" is found, update it with the custom password. try { final PasswordValidator passwordValidator = PasswordValidator.of( Settings.builder() @@ -185,7 +184,7 @@ void updateAdminPassword() throws IOException { DEFAULT_PASSWORD_MIN_LENGTH ) ); - System.exit(-1); + installer.getExitHandler().exit(-1); } } @@ -197,7 +196,7 @@ void updateAdminPassword() throws IOException { ConfigConstants.OPENSEARCH_INITIAL_ADMIN_PASSWORD ) ); - System.exit(-1); + installer.getExitHandler().exit(-1); } // Update the custom password in internal_users.yml file @@ -207,7 +206,7 @@ void updateAdminPassword() throws IOException { } catch (IOException e) { System.out.println("Exception updating the admin password : " + e.getMessage()); - System.exit(-1); + installer.getExitHandler().exit(-1); } } @@ -234,7 +233,7 @@ void writePasswordToInternalUsersFile(String adminPassword, String internalUsers if (hashedAdminPassword.isEmpty()) { System.out.println("Failure while hashing the admin password, see console for details."); - System.exit(-1); + installer.getExitHandler().exit(-1); } try { @@ -277,7 +276,7 @@ void writeSecurityConfigToOpenSearchYML() { writer.write(configFooter); } catch (IOException e) { System.err.println("Exception writing security configuration to opensearch.yml : " + e.getMessage()); - System.exit(-1); + installer.getExitHandler().exit(-1); } } diff --git a/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java b/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java index 0220bd37af..fc9d02deb8 100644 --- a/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java +++ b/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java @@ -35,7 +35,6 @@ import org.junit.Test; import org.opensearch.OpenSearchSecurityException; -import org.opensearch.SpecialPermission; import org.opensearch.common.settings.Settings; import org.opensearch.security.authtoken.jwt.EncryptionDecryptionUtil; import org.opensearch.security.filter.SecurityRequest; @@ -60,11 +59,8 @@ import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @SuppressWarnings("removal") @@ -314,24 +310,6 @@ public void testBearerWrongPosition() throws Exception { assertNull(credentials); } - @Test - public void testSecurityManagerCheck() { - SecurityManager mockSecurityManager = mock(SecurityManager.class); - System.setSecurityManager(mockSecurityManager); - - OnBehalfOfAuthenticator jwtAuth = new OnBehalfOfAuthenticator(defaultSettings(), clusterName); - Map headers = new HashMap<>(); - headers.put("Authorization", "Bearer someToken"); - - try { - jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap<>()).asSecurityRequest(), null); - } finally { - System.setSecurityManager(null); - } - - verify(mockSecurityManager, times(3)).checkPermission(any(SpecialPermission.class)); - } - @Test public void testBasicAuthHeader() throws Exception { String jwsToken = Jwts.builder() diff --git a/src/test/java/org/opensearch/security/tools/democonfig/CertificateGeneratorTests.java b/src/test/java/org/opensearch/security/tools/democonfig/CertificateGeneratorTests.java index f7f13988c8..18b857cf84 100644 --- a/src/test/java/org/opensearch/security/tools/democonfig/CertificateGeneratorTests.java +++ b/src/test/java/org/opensearch/security/tools/democonfig/CertificateGeneratorTests.java @@ -32,8 +32,6 @@ import org.junit.Before; import org.junit.Test; -import org.opensearch.security.tools.democonfig.util.NoExitSecurityManager; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo; @@ -42,11 +40,27 @@ import static org.opensearch.security.tools.democonfig.util.DemoConfigHelperUtil.deleteDirectoryRecursive; import static org.junit.Assert.fail; -@SuppressWarnings("removal") +/** + * Tests for the CertificateGenerator. + */ public class CertificateGeneratorTests { private static Installer installer; + // Custom exception to simulate an exit via the exit handler. + public static class TestExitException extends RuntimeException { + private final int status; + + public TestExitException(int status) { + super("Exit code " + status); + this.status = status; + } + + public int getStatus() { + return status; + } + } + @Before public void setUp() { installer = Installer.getInstance(); @@ -68,9 +82,8 @@ public void testCreateDemoCertificates() throws Exception { certificateGenerator.createDemoCertificates(); - // root-ca.pem, esnode.pem, esnode-key.pem, kirk.pem, kirk-key.pem + // Expect five certificate files: root-ca.pem, esnode.pem, esnode-key.pem, kirk.pem, kirk-key.pem int expectedNumberOfCertificateFiles = 5; - int certsFound = 0; for (Certificates cert : certificatesArray) { @@ -84,9 +97,7 @@ public void testCreateDemoCertificates() throws Exception { } else { checkCertificateValidity(certFilePath); } - - // increment a count since a valid certificate was found - certsFound++; + certsFound++; // count valid file } assertThat(certsFound, equalTo(expectedNumberOfCertificateFiles)); @@ -94,15 +105,15 @@ public void testCreateDemoCertificates() throws Exception { @Test public void testCreateDemoCertificates_invalidPath() { + // Use an invalid directory path so that certificate creation fails installer.OPENSEARCH_CONF_DIR = "invalidPath"; CertificateGenerator certificateGenerator = new CertificateGenerator(installer); + installer.setExitHandler(status -> { throw new TestExitException(status); }); try { - System.setSecurityManager(new NoExitSecurityManager()); certificateGenerator.createDemoCertificates(); - } catch (SecurityException e) { - assertThat(e.getMessage(), equalTo("System.exit(-1) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); + fail("Expected exit handler to be invoked"); + } catch (TestExitException e) { + assertThat(e.getStatus(), equalTo(-1)); } } @@ -118,11 +129,11 @@ private static void checkCertificateValidity(String certPath) throws Exception { Period duration = getPeriodBetween(x509Certificate.getNotBefore().toInstant(), expiry); - // we check that cert is valid for total of ~10 yrs - // we don't check days as leaps years may cause flaky-ness + // Check that certificate lifetime is roughly 10 years (9 years and 11 months) assertThat(duration.getYears(), equalTo(9)); assertThat(duration.getMonths(), equalTo(11)); + // Ensure certificate is currently valid and will remain valid at least one year from now x509Certificate.checkValidity(); verifyExpiryAtLeastAYearFromNow(expiry); @@ -139,16 +150,14 @@ private static void verifyExpiryAtLeastAYearFromNow(Instant expiry) { private static Period getPeriodBetween(Instant start, Instant end) { LocalDate startDate = LocalDate.ofInstant(start, TimeZone.getTimeZone("EDT").toZoneId()); LocalDate endDate = LocalDate.ofInstant(end, TimeZone.getTimeZone("EDT").toZoneId()); - return Period.between(startDate, endDate); } private void checkPrivateKeyValidity(String keyPath) { try { String pemContent = readPEMFile(keyPath); - + // Remove the BEGIN/END markers and whitespace String base64Data = pemContent.replaceAll("-----BEGIN PRIVATE KEY-----|-----END PRIVATE KEY-----", "").replaceAll("\\s", ""); - byte[] keyBytes = Base64.getDecoder().decode(base64Data); KeyFactory kf = KeyFactory.getInstance("RSA"); PrivateKey key = kf.generatePrivate(new PKCS8EncodedKeySpec(keyBytes)); diff --git a/src/test/java/org/opensearch/security/tools/democonfig/InstallerTests.java b/src/test/java/org/opensearch/security/tools/democonfig/InstallerTests.java index 4aaaf0e45e..1de4a0d7e4 100644 --- a/src/test/java/org/opensearch/security/tools/democonfig/InstallerTests.java +++ b/src/test/java/org/opensearch/security/tools/democonfig/InstallerTests.java @@ -11,7 +11,7 @@ package org.opensearch.security.tools.democonfig; -// CS-SUPPRESS-SINGLE: RegexpSingleline extension key-word is used in file ext variable +// CS-SUPPRESS-SINGLE: RegexpSingleline Extension is used to refer to file extensions, keeping this rule disable for the whole file import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -29,8 +29,6 @@ import org.junit.Before; import org.junit.Test; -import org.opensearch.security.tools.democonfig.util.NoExitSecurityManager; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -42,9 +40,7 @@ import static org.opensearch.security.tools.democonfig.util.DemoConfigHelperUtil.createFile; import static org.opensearch.security.tools.democonfig.util.DemoConfigHelperUtil.deleteDirectoryRecursive; import static org.junit.Assert.assertThrows; -import static org.junit.Assert.fail; -@SuppressWarnings("removal") public class InstallerTests { private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); private final PrintStream originalOut = System.out; @@ -52,6 +48,20 @@ public class InstallerTests { private static Installer installer; + // Custom exception to simulate an exit call. + public static class TestExitException extends RuntimeException { + private final int status; + + public TestExitException(int status) { + super("Exit code " + status); + this.status = status; + } + + public int getStatus() { + return status; + } + } + @Before public void setUpStreams() { System.setOut(new PrintStream(outContent)); @@ -63,6 +73,7 @@ public void setUpStreams() { public void restoreStreams() { System.setOut(originalOut); System.setIn(originalIn); + // Reset installer state to avoid cross-test contamination. Installer.resetInstance(); } @@ -79,7 +90,7 @@ public void testPrintScriptHeaders() { @Test public void testReadOptions_withoutHelpOption() { - // All options except Help `-h` + // All options except Help "-h" String[] validOptions = { "/scriptDir", "-y", "-i", "-c", "-s", "-t" }; installer.readOptions(validOptions); @@ -93,32 +104,31 @@ public void testReadOptions_withoutHelpOption() { @Test public void testReadOptions_help() { - try { - System.setSecurityManager(new NoExitSecurityManager()); - String[] helpOption = { "/scriptDir", "-h" }; - installer.readOptions(helpOption); - } catch (SecurityException e) { - // if help text printed correctly then exit code 0 is expected - assertThat(e.getMessage(), equalTo("System.exit(0) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); - } + // Set exit handler that throws TestExitException instead of exiting. + installer.setExitHandler(status -> { throw new TestExitException(status); }); + + String[] helpOption = { "/scriptDir", "-h" }; + TestExitException ex = assertThrows( + "Expected exit with status 0", + TestExitException.class, + () -> { installer.readOptions(helpOption); } + ); + assertThat(ex.getStatus(), equalTo(0)); verifyStdOutContainsString("usage: install_demo_configuration" + installer.FILE_EXTENSION + " [-c] [-h] [-i] [-s] [-t] [-y]"); } @Test public void testGatherUserInputs_withoutAssumeYes() { - // -i & -c option is not passed + // -i & -c options are not passed String[] validOptions = { "/scriptDir" }; installer.readOptions(validOptions); assertThat(installer.assumeyes, is(false)); assertThat(installer.initsecurity, is(false)); assertThat(installer.cluster_mode, is(false)); - // set initsecurity and cluster_mode to no - readInputStream("y" + System.lineSeparator() + "n" + System.lineSeparator() + "n" + System.lineSeparator()); // pass all 3 inputs as - // y + // Provide inputs: "y" then "n", then "n". + readInputStream("y" + System.lineSeparator() + "n" + System.lineSeparator() + "n" + System.lineSeparator()); installer.gatherUserInputs(); verifyStdOutContainsString("Install demo certificates?"); @@ -132,9 +142,8 @@ public void testGatherUserInputs_withoutAssumeYes() { outContent.reset(); - // set initsecurity and cluster_mode to no - readInputStream("y" + System.lineSeparator() + "y" + System.lineSeparator() + "y" + System.lineSeparator()); // pass all 3 inputs as - // y + // Provide inputs: "y", "y", "y". + readInputStream("y" + System.lineSeparator() + "y" + System.lineSeparator() + "y" + System.lineSeparator()); installer.gatherUserInputs(); verifyStdOutContainsString("Install demo certificates?"); @@ -148,17 +157,16 @@ public void testGatherUserInputs_withoutAssumeYes() { outContent.reset(); - // no to demo certificates - try { - System.setSecurityManager(new NoExitSecurityManager()); + // Now test if the first prompt (demo certificates) is answered "n". + installer.setExitHandler(status -> { throw new TestExitException(status); }); + readInputStream("n" + System.lineSeparator() + "n" + System.lineSeparator() + "n" + System.lineSeparator()); + TestExitException ex = assertThrows( + "Expected exit with status 0", + TestExitException.class, + () -> { installer.gatherUserInputs(); } + ); + assertThat(ex.getStatus(), equalTo(0)); - readInputStream("n" + System.lineSeparator() + "n" + System.lineSeparator() + "n" + System.lineSeparator()); - installer.gatherUserInputs(); - } catch (SecurityException e) { - assertThat(e.getMessage(), equalTo("System.exit(0) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); - } verifyStdOutContainsString("Install demo certificates?"); verifyStdOutDoesNotContainString("Initialize Security Modules?"); verifyStdOutDoesNotContainString("Cluster mode requires additional setup of:"); @@ -167,15 +175,15 @@ public void testGatherUserInputs_withoutAssumeYes() { outContent.reset(); - // pass initsecurity and cluster_mode options + // Now test with -i and -c passed; prompts should not occur. String[] validOptionsIC = { "/scriptDir", "-i", "-c" }; installer.readOptions(validOptionsIC); assertThat(installer.assumeyes, is(false)); assertThat(installer.initsecurity, is(true)); assertThat(installer.cluster_mode, is(true)); - readInputStream("y" + System.lineSeparator() + "y" + System.lineSeparator() + "y" + System.lineSeparator()); // pass all 3 inputs as - // y + // Even if input is provided, it should skip further prompts. + readInputStream("y" + System.lineSeparator() + "y" + System.lineSeparator() + "y" + System.lineSeparator()); installer.gatherUserInputs(); verifyStdOutContainsString("Install demo certificates?"); @@ -194,6 +202,7 @@ public void testGatherInputs_withAssumeYes() { installer.gatherUserInputs(); + // With assume yes (-y), no further prompts occur. assertThat(installer.initsecurity, is(false)); assertThat(installer.cluster_mode, is(false)); } @@ -203,19 +212,15 @@ public void testInitializeVariables_setBaseDir_invalidPath() { String[] invalidScriptDirPath = { "/scriptDir", "-y" }; installer.readOptions(invalidScriptDirPath); + // If BASE_DIR cannot be determined, a NullPointerException is expected. assertThrows("Expected NullPointerException to be thrown", NullPointerException.class, installer::initializeVariables); String[] invalidScriptDirPath2 = { "/opensearch/plugins/opensearch-security/tools", "-y" }; installer.readOptions(invalidScriptDirPath2); - try { - System.setSecurityManager(new NoExitSecurityManager()); - installer.initializeVariables(); - } catch (SecurityException e) { - assertThat(e.getMessage(), equalTo("System.exit(-1) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); - } + installer.setExitHandler(status -> { throw new TestExitException(status); }); + TestExitException ex = assertThrows("Expected exit with status -1", TestExitException.class, installer::initializeVariables); + assertThat(ex.getStatus(), equalTo(-1)); verifyStdOutContainsString("DEBUG: basedir does not exist"); } @@ -241,16 +246,13 @@ public void testSetOpenSearchVariables_invalidPath() { String[] validBaseDir = { currentDir, "-y" }; installer.readOptions(validBaseDir); - try { - System.setSecurityManager(new NoExitSecurityManager()); + installer.setExitHandler(status -> { throw new TestExitException(status); }); + TestExitException ex = assertThrows("Expected exit with status -1", TestExitException.class, () -> { installer.setBaseDir(); installer.setOpenSearchVariables(); - } catch (SecurityException e) { - assertThat(e.getMessage(), equalTo("System.exit(-1) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); + }); + assertThat(ex.getStatus(), equalTo(-1)); - } verifyStdOutContainsString("Unable to determine OpenSearch config file. Quit."); verifyStdOutContainsString("Unable to determine OpenSearch bin directory. Quit."); verifyStdOutContainsString("Unable to determine OpenSearch plugins directory. Quit."); @@ -269,7 +271,6 @@ public void testSetOpenSearchVariables_invalidPath() { assertThat(installer.OPENSEARCH_PLUGINS_DIR, equalTo(expectedOpensearchPluginDirPath)); assertThat(installer.OPENSEARCH_LIB_PATH, equalTo(expectedOpensearchLibDirPath)); assertThat(installer.OPENSEARCH_INSTALL_TYPE, equalTo(expectedOpensearchInstallType)); - } @Test @@ -314,16 +315,10 @@ public void testSetSecurityVariables() { @Test public void testSetSecurityVariables_noSecurityPlugin() { - try { - System.setSecurityManager(new NoExitSecurityManager()); - - installer.setSecurityVariables(); - fail("Expected System.exit(-1) to be called"); - } catch (SecurityException e) { - assertThat(e.getMessage(), equalTo("System.exit(-1) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); - } + installer.setExitHandler(status -> { throw new TestExitException(status); }); + + TestExitException ex = assertThrows("Expected exit with status -1", TestExitException.class, installer::setSecurityVariables); + assertThat(ex.getStatus(), equalTo(-1)); } @Test @@ -490,7 +485,7 @@ public void setUpSecurityDirectories() { } public void tearDownSecurityDirectories() { - // Clean up testing directories or files + // Clean up testing directories or files. deleteDirectoryRecursive(installer.OPENSEARCH_PLUGINS_DIR); deleteDirectoryRecursive(installer.OPENSEARCH_LIB_PATH); deleteDirectoryRecursive(installer.OPENSEARCH_CONF_DIR); @@ -517,3 +512,4 @@ private void verifyStdOutDoesNotContainString(String s) { assertThat(outContent.toString(), not(containsString(s))); } } +// CS-ENFORCE-SINGLE diff --git a/src/test/java/org/opensearch/security/tools/democonfig/SecuritySettingsConfigurerTests.java b/src/test/java/org/opensearch/security/tools/democonfig/SecuritySettingsConfigurerTests.java index afb0e44f1e..040f0ef6a7 100644 --- a/src/test/java/org/opensearch/security/tools/democonfig/SecuritySettingsConfigurerTests.java +++ b/src/test/java/org/opensearch/security/tools/democonfig/SecuritySettingsConfigurerTests.java @@ -11,7 +11,7 @@ package org.opensearch.security.tools.democonfig; -// CS-SUPPRESS-SINGLE: RegexpSingleline extension key-word is used in file ext variable +// CS-SUPPRESS-SINGLE: RegexpSingleline Extension is used to refer to file extensions, keeping this rule disable for the whole file import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; @@ -29,6 +29,7 @@ import java.util.List; import java.util.Map; +import com.carrotsearch.randomizedtesting.RandomizedRunner; import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Before; @@ -37,7 +38,6 @@ import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.tools.Hasher; -import org.opensearch.security.tools.democonfig.util.NoExitSecurityManager; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; @@ -53,10 +53,11 @@ import static org.opensearch.security.tools.democonfig.util.DemoConfigHelperUtil.createDirectory; import static org.opensearch.security.tools.democonfig.util.DemoConfigHelperUtil.createFile; import static org.opensearch.security.tools.democonfig.util.DemoConfigHelperUtil.deleteDirectoryRecursive; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; @SuppressWarnings("removal") -@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) +@RunWith(RandomizedRunner.class) public class SecuritySettingsConfigurerTests { private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); @@ -70,9 +71,22 @@ public class SecuritySettingsConfigurerTests { "Password %s failed validation: \"%s\". Please re-try with a minimum %d character password and must contain at least one uppercase letter, one lowercase letter, one digit, and one special character that is strong. Password strength can be tested here: https://lowe.github.io/tryzxcvbn"; private static SecuritySettingsConfigurer securitySettingsConfigurer; - private static Installer installer; + // Custom exception thrown by the test exit handler + public static class TestExitException extends RuntimeException { + private final int status; + + public TestExitException(int status) { + super("Exit code " + status); + this.status = status; + } + + public int getStatus() { + return status; + } + } + @Before public void setUp() throws IOException { System.setOut(new PrintStream(outContent)); @@ -102,22 +116,17 @@ public void testUpdateAdminPasswordWithCustomPassword() throws NoSuchFieldExcept securitySettingsConfigurer.updateAdminPassword(); - assertThat(customPassword, is(equalTo(SecuritySettingsConfigurer.ADMIN_PASSWORD))); - + assertThat(customPassword, equalTo(SecuritySettingsConfigurer.ADMIN_PASSWORD)); verifyStdOutContainsString("Admin password set successfully."); } @Test - public void testUpdateAdminPassword_noPasswordSupplied() { - SecuritySettingsConfigurer.ADMIN_PASSWORD = ""; // to ensure 0 flaky-ness - try { - System.setSecurityManager(new NoExitSecurityManager()); - securitySettingsConfigurer.updateAdminPassword(); - } catch (SecurityException | IOException e) { - assertThat(e.getMessage(), equalTo("System.exit(-1) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); - } + public void testUpdateAdminPassword_noPasswordSupplied() throws IOException { + // Ensure ADMIN_PASSWORD is empty so that no custom password is supplied + SecuritySettingsConfigurer.ADMIN_PASSWORD = ""; + installer.setExitHandler(status -> { throw new TestExitException(status); }); + TestExitException ex = assertThrows(TestExitException.class, () -> securitySettingsConfigurer.updateAdminPassword()); + assertThat(ex.getStatus(), equalTo(-1)); verifyStdOutContainsString( String.format( @@ -129,16 +138,10 @@ public void testUpdateAdminPassword_noPasswordSupplied() { @Test public void testUpdateAdminPasswordWithWeakPassword() throws NoSuchFieldException, IllegalAccessException { - setEnv(adminPasswordKey, "weakpassword"); - try { - System.setSecurityManager(new NoExitSecurityManager()); - securitySettingsConfigurer.updateAdminPassword(); - } catch (SecurityException | IOException e) { - assertThat(e.getMessage(), equalTo("System.exit(-1) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); - } + installer.setExitHandler(status -> { throw new TestExitException(status); }); + TestExitException ex = assertThrows(TestExitException.class, () -> securitySettingsConfigurer.updateAdminPassword()); + assertThat(ex.getStatus(), equalTo(-1)); verifyStdOutContainsString( String.format( @@ -152,17 +155,10 @@ public void testUpdateAdminPasswordWithWeakPassword() throws NoSuchFieldExceptio @Test public void testUpdateAdminPasswordWithShortPassword() throws NoSuchFieldException, IllegalAccessException { - setEnv(adminPasswordKey, "short"); - try { - System.setSecurityManager(new NoExitSecurityManager()); - securitySettingsConfigurer.updateAdminPassword(); - } catch (SecurityException | IOException e) { - assertThat(e.getMessage(), equalTo("System.exit(-1) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); - } - + installer.setExitHandler(status -> { throw new TestExitException(status); }); + TestExitException ex = assertThrows(TestExitException.class, () -> securitySettingsConfigurer.updateAdminPassword()); + assertThat(ex.getStatus(), equalTo(-1)); verifyStdOutContainsString( String.format(PASSWORD_VALIDATION_FAILURE_MESSAGE, "short", INVALID_PASSWORD_TOO_SHORT.message(), DEFAULT_PASSWORD_MIN_LENGTH) ); @@ -173,10 +169,10 @@ public void testUpdateAdminPasswordWithWeakPassword_skipPasswordValidation() thr IOException { setEnv(adminPasswordKey, "weakpassword"); installer.environment = ExecutionEnvironment.TEST; + // In test environment, password validation is skipped. securitySettingsConfigurer.updateAdminPassword(); - assertThat("weakpassword", is(equalTo(SecuritySettingsConfigurer.ADMIN_PASSWORD))); - + assertThat("weakpassword", equalTo(SecuritySettingsConfigurer.ADMIN_PASSWORD)); verifyStdOutContainsString("Admin password set successfully."); } @@ -194,26 +190,19 @@ public void testUpdateAdminPasswordWithCustomInternalUsersYML() throws IOExcepti " backend_roles:", " - \"admin\"" ); - // overwriting existing content + // Overwrite existing content Files.write(internalUsersFilePath, newContent, StandardCharsets.UTF_8); securitySettingsConfigurer.updateAdminPassword(); - verifyStdOutContainsString("Admin password seems to be custom configured. Skipping update to admin password."); } @Test public void testUpdateAdminPasswordWithDefaultInternalUsersYml() { - - SecuritySettingsConfigurer.ADMIN_PASSWORD = ""; // to ensure 0 flaky-ness - try { - System.setSecurityManager(new NoExitSecurityManager()); - securitySettingsConfigurer.updateAdminPassword(); - } catch (SecurityException | IOException e) { - assertThat(e.getMessage(), equalTo("System.exit(-1) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); - } + SecuritySettingsConfigurer.ADMIN_PASSWORD = ""; + installer.setExitHandler(status -> { throw new TestExitException(status); }); + TestExitException ex = assertThrows(TestExitException.class, () -> securitySettingsConfigurer.updateAdminPassword()); + assertThat(ex.getStatus(), equalTo(-1)); verifyStdOutContainsString( String.format( @@ -227,19 +216,19 @@ public void testUpdateAdminPasswordWithDefaultInternalUsersYml() { public void testSecurityPluginAlreadyConfigured() { securitySettingsConfigurer.writeSecurityConfigToOpenSearchYML(); String expectedMessage = installer.OPENSEARCH_CONF_FILE + " seems to be already configured for Security. Quit."; - try { - System.setSecurityManager(new NoExitSecurityManager()); - securitySettingsConfigurer.checkIfSecurityPluginIsAlreadyConfigured(); - } catch (SecurityException e) { - assertThat(e.getMessage(), equalTo("System.exit(-1) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); - } + installer.setExitHandler(status -> { throw new TestExitException(status); }); + TestExitException ex = assertThrows( + TestExitException.class, + () -> securitySettingsConfigurer.checkIfSecurityPluginIsAlreadyConfigured() + ); + // Expecting exit code -1 + assertThat(ex.getStatus(), equalTo(-1)); verifyStdOutContainsString(expectedMessage); } @Test public void testSecurityPluginNotConfigured() { + // In case no security settings are in the configuration file the check method should complete without exiting. try { securitySettingsConfigurer.checkIfSecurityPluginIsAlreadyConfigured(); } catch (Exception e) { @@ -251,18 +240,14 @@ public void testSecurityPluginNotConfigured() { public void testConfigFileDoesNotExist() { installer.OPENSEARCH_CONF_FILE = "path/to/nonexistentfile"; String expectedMessage = "OpenSearch configuration file does not exist. Quit."; - try { - System.setSecurityManager(new NoExitSecurityManager()); - securitySettingsConfigurer.checkIfSecurityPluginIsAlreadyConfigured(); - } catch (SecurityException e) { - assertThat(e.getMessage(), equalTo("System.exit(-1) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); - } - + installer.setExitHandler(status -> { throw new TestExitException(status); }); + TestExitException ex = assertThrows( + TestExitException.class, + () -> securitySettingsConfigurer.checkIfSecurityPluginIsAlreadyConfigured() + ); + assertThat(ex.getStatus(), equalTo(-1)); verifyStdOutContainsString(expectedMessage); - - // reset the file pointer + // Reset the file pointer installer.OPENSEARCH_CONF_FILE = installer.OPENSEARCH_CONF_DIR + "opensearch.yml"; } @@ -271,33 +256,33 @@ public void testBuildSecurityConfigMap() { Map actual = securitySettingsConfigurer.buildSecurityConfigMap(); assertThat(actual.size(), is(17)); - assertThat(actual.get("plugins.security.ssl.transport.pemcert_filepath"), is(equalTo(Certificates.NODE_CERT.getFileName()))); - assertThat(actual.get("plugins.security.ssl.transport.pemkey_filepath"), is(equalTo(Certificates.NODE_KEY.getFileName()))); - assertThat(actual.get("plugins.security.ssl.transport.pemtrustedcas_filepath"), is(equalTo(Certificates.ROOT_CA.getFileName()))); - assertThat(actual.get("plugins.security.ssl.transport.enforce_hostname_verification"), is(equalTo(false))); - assertThat(actual.get("plugins.security.ssl.http.enabled"), is(equalTo(true))); - assertThat(actual.get("plugins.security.ssl.http.pemcert_filepath"), is(equalTo(Certificates.NODE_CERT.getFileName()))); - assertThat(actual.get("plugins.security.ssl.http.pemkey_filepath"), is(equalTo(Certificates.NODE_KEY.getFileName()))); - assertThat(actual.get("plugins.security.ssl.http.pemtrustedcas_filepath"), is(equalTo(Certificates.ROOT_CA.getFileName()))); - assertThat(actual.get("plugins.security.allow_unsafe_democertificates"), is(equalTo(true))); - assertThat(actual.get("plugins.security.authcz.admin_dn"), is(equalTo(List.of("CN=kirk,OU=client,O=client,L=test,C=de")))); - assertThat(actual.get("plugins.security.audit.type"), is(equalTo("internal_opensearch"))); - assertThat(actual.get("plugins.security.enable_snapshot_restore_privilege"), is(equalTo(true))); - assertThat(actual.get("plugins.security.check_snapshot_restore_write_privileges"), is(equalTo(true))); - assertThat(actual.get("plugins.security.restapi.roles_enabled"), is(equalTo(REST_ENABLED_ROLES))); - assertThat(actual.get("plugins.security.system_indices.enabled"), is(equalTo(true))); - assertThat(actual.get("plugins.security.system_indices.indices"), is(equalTo(SYSTEM_INDICES))); - assertThat(actual.get("node.max_local_storage_nodes"), is(equalTo(3))); + assertThat(actual.get("plugins.security.ssl.transport.pemcert_filepath"), equalTo(Certificates.NODE_CERT.getFileName())); + assertThat(actual.get("plugins.security.ssl.transport.pemkey_filepath"), equalTo(Certificates.NODE_KEY.getFileName())); + assertThat(actual.get("plugins.security.ssl.transport.pemtrustedcas_filepath"), equalTo(Certificates.ROOT_CA.getFileName())); + assertThat(actual.get("plugins.security.ssl.transport.enforce_hostname_verification"), equalTo(false)); + assertThat(actual.get("plugins.security.ssl.http.enabled"), equalTo(true)); + assertThat(actual.get("plugins.security.ssl.http.pemcert_filepath"), equalTo(Certificates.NODE_CERT.getFileName())); + assertThat(actual.get("plugins.security.ssl.http.pemkey_filepath"), equalTo(Certificates.NODE_KEY.getFileName())); + assertThat(actual.get("plugins.security.ssl.http.pemtrustedcas_filepath"), equalTo(Certificates.ROOT_CA.getFileName())); + assertThat(actual.get("plugins.security.allow_unsafe_democertificates"), equalTo(true)); + assertThat(actual.get("plugins.security.authcz.admin_dn"), equalTo(List.of("CN=kirk,OU=client,O=client,L=test,C=de"))); + assertThat(actual.get("plugins.security.audit.type"), equalTo("internal_opensearch")); + assertThat(actual.get("plugins.security.enable_snapshot_restore_privilege"), equalTo(true)); + assertThat(actual.get("plugins.security.check_snapshot_restore_write_privileges"), equalTo(true)); + assertThat(actual.get("plugins.security.restapi.roles_enabled"), equalTo(REST_ENABLED_ROLES)); + assertThat(actual.get("plugins.security.system_indices.enabled"), equalTo(true)); + assertThat(actual.get("plugins.security.system_indices.indices"), equalTo(SYSTEM_INDICES)); + assertThat(actual.get("node.max_local_storage_nodes"), equalTo(3)); installer.initsecurity = true; actual = securitySettingsConfigurer.buildSecurityConfigMap(); - assertThat(actual.get("plugins.security.allow_default_init_securityindex"), is(equalTo(true))); + assertThat(actual.get("plugins.security.allow_default_init_securityindex"), equalTo(true)); installer.cluster_mode = true; actual = securitySettingsConfigurer.buildSecurityConfigMap(); - assertThat(actual.get("network.host"), is(equalTo("0.0.0.0"))); - assertThat(actual.get("node.name"), is(equalTo("smoketestnode"))); - assertThat(actual.get("cluster.initial_cluster_manager_nodes"), is(equalTo("smoketestnode"))); + assertThat(actual.get("network.host"), equalTo("0.0.0.0")); + assertThat(actual.get("node.name"), equalTo("smoketestnode")); + assertThat(actual.get("cluster.initial_cluster_manager_nodes"), equalTo("smoketestnode")); } @Test @@ -308,8 +293,8 @@ public void testIsStringAlreadyPresentInFile_isNotPresent() throws IOException { installer.initsecurity = true; securitySettingsConfigurer.writeSecurityConfigToOpenSearchYML(); - assertThat(isKeyPresentInYMLFile(installer.OPENSEARCH_CONF_FILE, str1), is(equalTo(false))); - assertThat(isKeyPresentInYMLFile(installer.OPENSEARCH_CONF_FILE, str2), is(equalTo(false))); + assertThat(isKeyPresentInYMLFile(installer.OPENSEARCH_CONF_FILE, str1), equalTo(false)); + assertThat(isKeyPresentInYMLFile(installer.OPENSEARCH_CONF_FILE, str2), equalTo(false)); } @Test @@ -321,8 +306,8 @@ public void testIsStringAlreadyPresentInFile_isPresent() throws IOException { installer.cluster_mode = true; securitySettingsConfigurer.writeSecurityConfigToOpenSearchYML(); - assertThat(isKeyPresentInYMLFile(installer.OPENSEARCH_CONF_FILE, str1), is(equalTo(true))); - assertThat(isKeyPresentInYMLFile(installer.OPENSEARCH_CONF_FILE, str2), is(equalTo(false))); + assertThat(isKeyPresentInYMLFile(installer.OPENSEARCH_CONF_FILE, str1), equalTo(true)); + assertThat(isKeyPresentInYMLFile(installer.OPENSEARCH_CONF_FILE, str2), equalTo(false)); } @Test @@ -333,8 +318,8 @@ public void testAssumeYesDoesNotInitializeClusterMode() throws IOException { installer.assumeyes = true; securitySettingsConfigurer.writeSecurityConfigToOpenSearchYML(); - assertThat(isKeyPresentInYMLFile(installer.OPENSEARCH_CONF_FILE, nodeName), is(false)); - assertThat(isKeyPresentInYMLFile(installer.OPENSEARCH_CONF_FILE, securityIndex), is(false)); + assertThat(isKeyPresentInYMLFile(installer.OPENSEARCH_CONF_FILE, nodeName), equalTo(false)); + assertThat(isKeyPresentInYMLFile(installer.OPENSEARCH_CONF_FILE, securityIndex), equalTo(false)); } @Test @@ -342,13 +327,13 @@ public void testCreateSecurityAdminDemoScriptAndGetSecurityAdminCommands() throw String demoPath = installer.OPENSEARCH_CONF_DIR + "securityadmin_demo" + installer.FILE_EXTENSION; securitySettingsConfigurer.createSecurityAdminDemoScript("scriptPath", demoPath); - assertThat(new File(demoPath).exists(), is(equalTo(true))); + assertThat(new File(demoPath).exists(), equalTo(true)); String[] commands = securitySettingsConfigurer.getSecurityAdminCommands("scriptPath"); try (BufferedReader reader = new BufferedReader(new FileReader(demoPath, StandardCharsets.UTF_8))) { - assertThat(reader.readLine(), is(commands[0])); - assertThat(reader.readLine(), is(equalTo(commands[1]))); + assertThat(reader.readLine(), equalTo(commands[0])); + assertThat(reader.readLine(), equalTo(commands[1])); } } @@ -367,17 +352,15 @@ public void testCreateSecurityAdminDemoScript_invalidPath() { public void testReadNonFlatYamlAlreadyConfigured() throws IOException { installer.OPENSEARCH_CONF_FILE = Paths.get("src/test/resources/opensearch-config-non-flat.yaml").toFile().getAbsolutePath(); String expectedMessage = installer.OPENSEARCH_CONF_FILE + " seems to be already configured for Security. Quit."; - try { - System.setSecurityManager(new NoExitSecurityManager()); - securitySettingsConfigurer.checkIfSecurityPluginIsAlreadyConfigured(); - } catch (SecurityException e) { - assertThat(e.getMessage(), equalTo("System.exit(-1) blocked to allow print statement testing.")); - } finally { - System.setSecurityManager(null); - } + installer.setExitHandler(status -> { throw new TestExitException(status); }); + TestExitException ex = assertThrows( + TestExitException.class, + () -> securitySettingsConfigurer.checkIfSecurityPluginIsAlreadyConfigured() + ); + assertThat(ex.getStatus(), equalTo(-1)); verifyStdOutContainsString(expectedMessage); - // reset the file pointer + // Reset the configuration file pointer installer.OPENSEARCH_CONF_FILE = installer.OPENSEARCH_CONF_DIR + "opensearch.yml"; } @@ -434,7 +417,7 @@ private void setUpInternalUsersYML() throws IOException { " config_version: 2", "admin:", " hash: " + Hasher.hash(DEFAULT_ADMIN_PASSWORD.toCharArray()), - " reserved: " + true, + " reserved: true", " backend_roles:", " - \"admin\"", " description: Demo admin user" @@ -442,3 +425,4 @@ private void setUpInternalUsersYML() throws IOException { Files.write(internalUsersFilePath, defaultContent, StandardCharsets.UTF_8); } } +// CS-ENFORCE-SINGLE