diff --git a/qa/os/src/test/java/org/elasticsearch/packaging/test/ArchiveGenerateInitialPasswordTests.java b/qa/os/src/test/java/org/elasticsearch/packaging/test/ArchiveGenerateInitialPasswordTests.java index b58af66096890..1de93698b5c9c 100644 --- a/qa/os/src/test/java/org/elasticsearch/packaging/test/ArchiveGenerateInitialPasswordTests.java +++ b/qa/os/src/test/java/org/elasticsearch/packaging/test/ArchiveGenerateInitialPasswordTests.java @@ -10,6 +10,7 @@ import org.apache.http.client.fluent.Request; import org.elasticsearch.packaging.util.Distribution; +import org.elasticsearch.packaging.util.FileUtils; import org.elasticsearch.packaging.util.ServerUtils; import org.elasticsearch.packaging.util.Shell; import org.junit.BeforeClass; @@ -21,9 +22,11 @@ import static org.elasticsearch.packaging.util.Archives.installArchive; import static org.elasticsearch.packaging.util.Archives.verifyArchiveInstallation; +import static org.elasticsearch.packaging.util.FileExistenceMatchers.fileExists; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; import static org.junit.Assume.assumeTrue; public class ArchiveGenerateInitialPasswordTests extends PackagingTestCase { @@ -65,7 +68,18 @@ public void test30NoAutoGenerationWhenAutoConfigurationDisabled() throws Excepti assertThat(usersAndPasswords.isEmpty(), is(true)); } - public void test40VerifyAutogeneratedCredentials() throws Exception { + public void test40NoAutogenerationWhenDaemonized() throws Exception { + /* Windows issue awaits fix: https://github.com/elastic/elasticsearch/issues/49340 */ + assumeTrue("expect command isn't on Windows", distribution.platform != Distribution.Platform.WINDOWS); + stopElasticsearch(); + ServerUtils.enableSecurityAutoConfiguration(installation); + awaitElasticsearchStartup(runElasticsearchStartCommand(null, true, true)); + assertThat(installation.logs.resolve("elasticsearch.log"), fileExists()); + String logfile = FileUtils.slurp(installation.logs.resolve("elasticsearch.log")); + assertThat(logfile, not(containsString("Password for the elastic user is"))); + } + + public void test50VerifyAutogeneratedCredentials() throws Exception { /* Windows issue awaits fix: https://github.com/elastic/elasticsearch/issues/49340 */ assumeTrue("expect command isn't on Windows", distribution.platform != Distribution.Platform.WINDOWS); stopElasticsearch(); @@ -81,7 +95,7 @@ public void test40VerifyAutogeneratedCredentials() throws Exception { } } - public void test50PasswordAutogenerationOnlyOnce() throws Exception { + public void test60PasswordAutogenerationOnlyOnce() throws Exception { /* Windows issue awaits fix: https://github.com/elastic/elasticsearch/issues/49340 */ assumeTrue("expect command isn't on Windows", distribution.platform != Distribution.Platform.WINDOWS); stopElasticsearch(); diff --git a/server/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java b/server/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java index 00ccac0d4bf04..b302dfb555958 100644 --- a/server/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java +++ b/server/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java @@ -316,7 +316,7 @@ static void init( final Environment initialEnv) throws BootstrapException, NodeValidationException, UserException { // force the class initializer for BootstrapInfo to run before // the security manager is installed - BootstrapInfo.init(); + BootstrapInfo.init(getSysOutReference()); INSTANCE = new Bootstrap(); @@ -424,6 +424,11 @@ static void init( } } + @SuppressForbidden(reason = "Retain reference for System.out") + private static PrintStream getSysOutReference() { + return System.out; + } + @SuppressForbidden(reason = "System#out") private static Runnable getSysOutCloser() { return System.out::close; diff --git a/server/src/main/java/org/elasticsearch/bootstrap/BootstrapInfo.java b/server/src/main/java/org/elasticsearch/bootstrap/BootstrapInfo.java index 5c14450b3c76f..663f4a0caf872 100644 --- a/server/src/main/java/org/elasticsearch/bootstrap/BootstrapInfo.java +++ b/server/src/main/java/org/elasticsearch/bootstrap/BootstrapInfo.java @@ -10,6 +10,7 @@ import org.elasticsearch.core.SuppressForbidden; +import java.io.PrintStream; import java.util.Dictionary; import java.util.Enumeration; @@ -19,6 +20,8 @@ @SuppressForbidden(reason = "exposes read-only view of system properties") public final class BootstrapInfo { + private static PrintStream originalStandardOut; + /** no instantiation */ private BootstrapInfo() {} @@ -46,6 +49,11 @@ public static boolean isSystemCallFilterInstalled() { return Natives.isSystemCallFilterInstalled(); } + /** + * Returns a reference to the original System.out + */ + public static PrintStream getOriginalStandardOut() { return originalStandardOut; } + /** * codebase location for untrusted scripts (provide some additional safety) *

@@ -110,7 +118,8 @@ public static Dictionary getSystemProperties() { return SYSTEM_PROPERTIES; } - public static void init() { + public static void init(PrintStream originalStandardOut) { + BootstrapInfo.originalStandardOut = originalStandardOut; } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/GenerateInitialBuiltinUsersPasswordListener.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/GenerateInitialBuiltinUsersPasswordListener.java index 586a7f084c978..bc11a678bdb16 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/GenerateInitialBuiltinUsersPasswordListener.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/GenerateInitialBuiltinUsersPasswordListener.java @@ -12,13 +12,16 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.support.WriteRequest; +import org.elasticsearch.bootstrap.BootstrapInfo; import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.core.Nullable; import org.elasticsearch.index.engine.VersionConflictEngineException; import org.elasticsearch.xpack.core.security.user.ElasticUser; import org.elasticsearch.xpack.core.security.user.KibanaSystemUser; import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore; import org.elasticsearch.xpack.security.support.SecurityIndexManager; +import java.io.PrintStream; import java.util.function.BiConsumer; import static org.elasticsearch.xpack.security.tool.CommandUtils.generatePassword; @@ -26,8 +29,8 @@ public class GenerateInitialBuiltinUsersPasswordListener implements BiConsumer { private static final Logger LOGGER = LogManager.getLogger(GenerateInitialBuiltinUsersPasswordListener.class); - private NativeUsersStore nativeUsersStore; - private SecurityIndexManager securityIndexManager; + private final NativeUsersStore nativeUsersStore; + private final SecurityIndexManager securityIndexManager; public GenerateInitialBuiltinUsersPasswordListener(NativeUsersStore nativeUsersStore, SecurityIndexManager securityIndexManager) { this.nativeUsersStore = nativeUsersStore; @@ -36,6 +39,13 @@ public GenerateInitialBuiltinUsersPasswordListener(NativeUsersStore nativeUsersS @Override public void accept(SecurityIndexManager.State previousState, SecurityIndexManager.State currentState) { + final PrintStream out = BootstrapInfo.getOriginalStandardOut(); + // Check if it has been closed, try to write something so that we trigger PrintStream#ensureOpen + out.println(); + if (out.checkError()) { + outputOnError(null); + return; + } if (previousState.equals(SecurityIndexManager.State.UNRECOVERED_STATE) && currentState.equals(SecurityIndexManager.State.UNRECOVERED_STATE) == false && securityIndexManager.indexExists() == false) { @@ -57,7 +67,7 @@ public void accept(SecurityIndexManager.State previousState, SecurityIndexManage WriteRequest.RefreshPolicy.IMMEDIATE, ActionListener.wrap( r -> { - outputOnSuccess(elasticPassword, kibanaSystemPassword); + outputOnSuccess(elasticPassword, kibanaSystemPassword, out); }, this::outputOnError ) ); @@ -66,55 +76,46 @@ public void accept(SecurityIndexManager.State previousState, SecurityIndexManage } } - private void outputOnSuccess(SecureString elasticPassword, SecureString kibanaSystemPassword) { - LOGGER.info(""); - LOGGER.info("-----------------------------------------------------------------"); - LOGGER.info(""); - LOGGER.info(""); - LOGGER.info(""); - LOGGER.info("Password for the elastic user is: " + elasticPassword); - LOGGER.info(""); - LOGGER.info(""); - LOGGER.info(""); - LOGGER.info("Password for the kibana_system user is: " + kibanaSystemPassword); - LOGGER.info(""); - LOGGER.info(""); - LOGGER.info("Please note these down as they will not be shown again."); - LOGGER.info(""); - LOGGER.info("You can use 'bin/elasticsearch-reset-elastic-password' at any time"); - LOGGER.info("in order to reset the password for the elastic user."); - LOGGER.info(""); - LOGGER.info(""); - LOGGER.info("You can use 'bin/elasticsearch-reset-kibana-system-password' at any time"); - LOGGER.info("in order to reset the password for the kibana_system user."); - LOGGER.info(""); - LOGGER.info(""); - LOGGER.info(""); - LOGGER.info("-----------------------------------------------------------------"); - LOGGER.info(""); + private void outputOnSuccess(SecureString elasticPassword, SecureString kibanaSystemPassword, PrintStream out) { + out.println(); + out.println("-----------------------------------------------------------------"); + out.println(); + out.println("Password for the elastic user is: " + elasticPassword); + out.println(); + out.println("Password for the kibana_system user is: " + kibanaSystemPassword); + out.println(); + out.println("Please note these down as they will not be shown again."); + out.println(); + out.println(); + out.println("You can use 'bin/elasticsearch-reset-elastic-password' at any time"); + out.println("in order to reset the password for the elastic user."); + out.println(); + out.println("You can use 'bin/elasticsearch-reset-kibana-system-password' at any time"); + out.println("in order to reset the password for the kibana_system user."); + out.println(); + out.println("-----------------------------------------------------------------"); + out.println(); } - private void outputOnError(Exception e) { + private void outputOnError(@Nullable Exception e) { if (e instanceof VersionConflictEngineException == false) { LOGGER.info(""); LOGGER.info("-----------------------------------------------------------------"); LOGGER.info(""); - LOGGER.info(""); - LOGGER.info(""); - LOGGER.info("Failed to set the password for the elastic and kibana-system users "); - LOGGER.info("automatically"); + LOGGER.info("Unable set the password for the elastic and kibana_system users "); + LOGGER.info("automatically."); LOGGER.info(""); LOGGER.info("You can use 'bin/elasticsearch-reset-elastic-password'"); LOGGER.info("in order to set the password for the elastic user."); LOGGER.info(""); - LOGGER.info(""); LOGGER.info("You can use 'bin/elasticsearch-reset-kibana-system-password'"); LOGGER.info("in order to set the password for the kibana_system user."); LOGGER.info(""); - LOGGER.info(""); - LOGGER.info(""); LOGGER.info("-----------------------------------------------------------------"); LOGGER.info(""); } + if (null != e) { + LOGGER.warn("Error initializing passwords for elastic and kibana_system users", e); + } } }