Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import org.elasticsearch.core.SuppressForbidden;

import java.io.PrintStream;
import java.util.Dictionary;
import java.util.Enumeration;

Expand All @@ -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() {}

Expand Down Expand Up @@ -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)
* <p>
Expand Down Expand Up @@ -110,7 +118,8 @@ public static Dictionary<Object,Object> getSystemProperties() {
return SYSTEM_PROPERTIES;
}

public static void init() {
public static void init(PrintStream originalStandardOut) {
BootstrapInfo.originalStandardOut = originalStandardOut;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,25 @@
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;

public class GenerateInitialBuiltinUsersPasswordListener implements BiConsumer<SecurityIndexManager.State, SecurityIndexManager.State> {

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;
Expand All @@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if there is any other way to check if stdout is closed

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) {
Expand All @@ -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
)
);
Expand All @@ -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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stream could still have been closed, in which case we are not attached to a terminal. So we need to catch that case, and probably log a warning?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll check this first before even generating the passwords. If we can't show them, there is no need to even generate them

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);
}
}
}