Check for existing x-pack directory when running the `users` CLI tool (elastic/x-pack-elasticsearch#3271)
Verify that the configuration directory `$ES_PATH_CONF/x-pack` exists before attempting to run any of the `users` commands, and return a helpful error message to the user if it doesn't. Original commit: elastic/x-pack-elasticsearch@6d663b6654
This commit is contained in:
parent
876fc5612a
commit
d24921ea60
|
@ -7,17 +7,17 @@ package org.elasticsearch.xpack.security.authc.file.tool;
|
||||||
|
|
||||||
import joptsimple.OptionSet;
|
import joptsimple.OptionSet;
|
||||||
import joptsimple.OptionSpec;
|
import joptsimple.OptionSpec;
|
||||||
import org.elasticsearch.cli.ExitCodes;
|
|
||||||
import org.elasticsearch.cli.LoggingAwareMultiCommand;
|
|
||||||
import org.elasticsearch.cli.MultiCommand;
|
|
||||||
import org.elasticsearch.cli.EnvironmentAwareCommand;
|
import org.elasticsearch.cli.EnvironmentAwareCommand;
|
||||||
|
import org.elasticsearch.cli.LoggingAwareMultiCommand;
|
||||||
import org.elasticsearch.cli.Terminal;
|
import org.elasticsearch.cli.Terminal;
|
||||||
import org.elasticsearch.cli.UserException;
|
import org.elasticsearch.cli.UserException;
|
||||||
|
import org.elasticsearch.cli.ExitCodes;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.settings.SecureString;
|
import org.elasticsearch.common.settings.SecureString;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.util.set.Sets;
|
import org.elasticsearch.common.util.set.Sets;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
|
import org.elasticsearch.xpack.XPackPlugin;
|
||||||
import org.elasticsearch.xpack.XPackSettings;
|
import org.elasticsearch.xpack.XPackSettings;
|
||||||
import org.elasticsearch.xpack.security.authc.file.FileUserPasswdStore;
|
import org.elasticsearch.xpack.security.authc.file.FileUserPasswdStore;
|
||||||
import org.elasticsearch.xpack.security.authc.file.FileUserRolesStore;
|
import org.elasticsearch.xpack.security.authc.file.FileUserRolesStore;
|
||||||
|
@ -75,7 +75,7 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
||||||
return new ListCommand();
|
return new ListCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class AddUserCommand extends EnvironmentAwareCommand {
|
static class AddUserCommand extends XPackConfigurationAwareCommand {
|
||||||
|
|
||||||
private final OptionSpec<String> passwordOption;
|
private final OptionSpec<String> passwordOption;
|
||||||
private final OptionSpec<String> rolesOption;
|
private final OptionSpec<String> rolesOption;
|
||||||
|
@ -83,6 +83,7 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
||||||
|
|
||||||
AddUserCommand() {
|
AddUserCommand() {
|
||||||
super("Adds a native user");
|
super("Adds a native user");
|
||||||
|
|
||||||
this.passwordOption = parser.acceptsAll(Arrays.asList("p", "password"),
|
this.passwordOption = parser.acceptsAll(Arrays.asList("p", "password"),
|
||||||
"The user password")
|
"The user password")
|
||||||
.withRequiredArg();
|
.withRequiredArg();
|
||||||
|
@ -104,7 +105,7 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(Terminal terminal, OptionSet options, Environment env) throws Exception {
|
protected void executeCommand(Terminal terminal, OptionSet options, Environment env) throws Exception {
|
||||||
|
|
||||||
String username = parseUsername(arguments.values(options), env.settings());
|
String username = parseUsername(arguments.values(options), env.settings());
|
||||||
final boolean allowReserved = XPackSettings.RESERVED_REALM_ENABLED_SETTING.get(env.settings()) == false;
|
final boolean allowReserved = XPackSettings.RESERVED_REALM_ENABLED_SETTING.get(env.settings()) == false;
|
||||||
|
@ -138,7 +139,7 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class DeleteUserCommand extends EnvironmentAwareCommand {
|
static class DeleteUserCommand extends XPackConfigurationAwareCommand {
|
||||||
|
|
||||||
private final OptionSpec<String> arguments;
|
private final OptionSpec<String> arguments;
|
||||||
|
|
||||||
|
@ -159,7 +160,8 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(Terminal terminal, OptionSet options, Environment env) throws Exception {
|
protected void executeCommand(Terminal terminal, OptionSet options, Environment env) throws Exception {
|
||||||
|
|
||||||
String username = parseUsername(arguments.values(options), env.settings());
|
String username = parseUsername(arguments.values(options), env.settings());
|
||||||
Path passwordFile = FileUserPasswdStore.resolveFile(env);
|
Path passwordFile = FileUserPasswdStore.resolveFile(env);
|
||||||
Path rolesFile = FileUserRolesStore.resolveFile(env);
|
Path rolesFile = FileUserRolesStore.resolveFile(env);
|
||||||
|
@ -188,7 +190,7 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class PasswordCommand extends EnvironmentAwareCommand {
|
static class PasswordCommand extends XPackConfigurationAwareCommand {
|
||||||
|
|
||||||
private final OptionSpec<String> passwordOption;
|
private final OptionSpec<String> passwordOption;
|
||||||
private final OptionSpec<String> arguments;
|
private final OptionSpec<String> arguments;
|
||||||
|
@ -213,7 +215,8 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(Terminal terminal, OptionSet options, Environment env) throws Exception {
|
protected void executeCommand(Terminal terminal, OptionSet options, Environment env) throws Exception {
|
||||||
|
|
||||||
String username = parseUsername(arguments.values(options), env.settings());
|
String username = parseUsername(arguments.values(options), env.settings());
|
||||||
char[] password = parsePassword(terminal, passwordOption.value(options));
|
char[] password = parsePassword(terminal, passwordOption.value(options));
|
||||||
|
|
||||||
|
@ -230,7 +233,7 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class RolesCommand extends EnvironmentAwareCommand {
|
static class RolesCommand extends XPackConfigurationAwareCommand {
|
||||||
|
|
||||||
private final OptionSpec<String> addOption;
|
private final OptionSpec<String> addOption;
|
||||||
private final OptionSpec<String> removeOption;
|
private final OptionSpec<String> removeOption;
|
||||||
|
@ -256,7 +259,8 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(Terminal terminal, OptionSet options, Environment env) throws Exception {
|
protected void executeCommand(Terminal terminal, OptionSet options, Environment env) throws Exception {
|
||||||
|
|
||||||
String username = parseUsername(arguments.values(options), env.settings());
|
String username = parseUsername(arguments.values(options), env.settings());
|
||||||
String[] addRoles = parseRoles(terminal, env, addOption.value(options));
|
String[] addRoles = parseRoles(terminal, env, addOption.value(options));
|
||||||
String[] removeRoles = parseRoles(terminal, env, removeOption.value(options));
|
String[] removeRoles = parseRoles(terminal, env, removeOption.value(options));
|
||||||
|
@ -299,7 +303,7 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ListCommand extends EnvironmentAwareCommand {
|
static class ListCommand extends XPackConfigurationAwareCommand {
|
||||||
|
|
||||||
private final OptionSpec<String> arguments;
|
private final OptionSpec<String> arguments;
|
||||||
|
|
||||||
|
@ -315,7 +319,8 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(Terminal terminal, OptionSet options, Environment env) throws Exception {
|
protected void executeCommand(Terminal terminal, OptionSet options, Environment env) throws Exception {
|
||||||
|
|
||||||
String username = null;
|
String username = null;
|
||||||
if (options.has(arguments)) {
|
if (options.has(arguments)) {
|
||||||
username = arguments.value(options);
|
username = arguments.value(options);
|
||||||
|
@ -475,4 +480,35 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
||||||
|
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private abstract static class XPackConfigurationAwareCommand extends EnvironmentAwareCommand {
|
||||||
|
|
||||||
|
XPackConfigurationAwareCommand(final String description) {
|
||||||
|
super(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void execute(Terminal terminal, OptionSet options, Environment env) throws Exception {
|
||||||
|
checkConfigurationDir(env);
|
||||||
|
executeCommand(terminal, options, env);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure the X-Pack configuration directory exists as a child of $ES_CONF_DIR or return a helpful error message.
|
||||||
|
*/
|
||||||
|
private void checkConfigurationDir(Environment env) throws Exception {
|
||||||
|
Path configDir = env.configFile().resolve(XPackPlugin.NAME);
|
||||||
|
if (Files.exists(configDir) == false) {
|
||||||
|
throw new UserException(ExitCodes.CONFIG, String.format(Locale.ROOT,
|
||||||
|
"Directory %s does not exist. Please ensure " +
|
||||||
|
"that %s is the configuration directory for Elasticsearch and create directory %s/x-pack manually",
|
||||||
|
configDir.toString(),
|
||||||
|
configDir.getParent().toString(),
|
||||||
|
configDir.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void executeCommand(Terminal terminal, OptionSet options, Environment env) throws Exception;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import org.apache.lucene.util.IOUtils;
|
||||||
import org.elasticsearch.cli.Command;
|
import org.elasticsearch.cli.Command;
|
||||||
import org.elasticsearch.cli.CommandTestCase;
|
import org.elasticsearch.cli.CommandTestCase;
|
||||||
import org.elasticsearch.cli.ExitCodes;
|
import org.elasticsearch.cli.ExitCodes;
|
||||||
import org.elasticsearch.cli.Terminal;
|
|
||||||
import org.elasticsearch.cli.UserException;
|
import org.elasticsearch.cli.UserException;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.io.PathUtilsForTesting;
|
import org.elasticsearch.common.io.PathUtilsForTesting;
|
||||||
|
@ -41,6 +40,8 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
|
||||||
public class UsersToolTests extends CommandTestCase {
|
public class UsersToolTests extends CommandTestCase {
|
||||||
|
|
||||||
// the mock filesystem we use so permissions/users/groups can be modified
|
// the mock filesystem we use so permissions/users/groups can be modified
|
||||||
|
@ -488,4 +489,56 @@ public class UsersToolTests extends CommandTestCase {
|
||||||
// output should not contain '*' which indicates unknown role
|
// output should not contain '*' which indicates unknown role
|
||||||
assertFalse(output, output.contains("*"));
|
assertFalse(output, output.contains("*"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testUserAddNoConfig() throws Exception {
|
||||||
|
Path homeDir = jimfs.getPath("eshome");
|
||||||
|
Path xpackConfDir = homeDir.resolve("config").resolve(XPackPlugin.NAME);
|
||||||
|
IOUtils.rm(confDir);
|
||||||
|
pathHomeParameter = "-Epath.home=" + homeDir;
|
||||||
|
fileTypeParameter = "-Expack.security.authc.realms.file.type=file";
|
||||||
|
UserException e = expectThrows(UserException.class, () -> {
|
||||||
|
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSource.TEST_PASSWORD);
|
||||||
|
});
|
||||||
|
assertEquals(ExitCodes.CONFIG, e.exitCode);
|
||||||
|
assertThat(e.getMessage(), containsString("is the configuration directory for Elasticsearch and create directory"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testUserListNoConfig() throws Exception {
|
||||||
|
Path homeDir = jimfs.getPath("eshome");
|
||||||
|
Path xpackConfDir = homeDir.resolve("config").resolve(XPackPlugin.NAME);
|
||||||
|
IOUtils.rm(confDir);
|
||||||
|
pathHomeParameter = "-Epath.home=" + homeDir;
|
||||||
|
fileTypeParameter = "-Expack.security.authc.realms.file.type=file";
|
||||||
|
UserException e = expectThrows(UserException.class, () -> {
|
||||||
|
execute("list", pathHomeParameter, fileTypeParameter);
|
||||||
|
});
|
||||||
|
assertEquals(ExitCodes.CONFIG, e.exitCode);
|
||||||
|
assertThat(e.getMessage(), containsString("is the configuration directory for Elasticsearch and create directory"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testUserDelNoConfig() throws Exception {
|
||||||
|
Path homeDir = jimfs.getPath("eshome");
|
||||||
|
Path xpackConfDir = homeDir.resolve("config").resolve(XPackPlugin.NAME);
|
||||||
|
IOUtils.rm(confDir);
|
||||||
|
pathHomeParameter = "-Epath.home=" + homeDir;
|
||||||
|
fileTypeParameter = "-Expack.security.authc.realms.file.type=file";
|
||||||
|
UserException e = expectThrows(UserException.class, () -> {
|
||||||
|
execute("userdel", pathHomeParameter, fileTypeParameter, "username");
|
||||||
|
});
|
||||||
|
assertEquals(ExitCodes.CONFIG, e.exitCode);
|
||||||
|
assertThat(e.getMessage(), containsString("is the configuration directory for Elasticsearch and create directory"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testListUserRolesNoConfig() throws Exception {
|
||||||
|
Path homeDir = jimfs.getPath("eshome");
|
||||||
|
Path xpackConfDir = homeDir.resolve("config").resolve(XPackPlugin.NAME);
|
||||||
|
IOUtils.rm(confDir);
|
||||||
|
pathHomeParameter = "-Epath.home=" + homeDir;
|
||||||
|
fileTypeParameter = "-Expack.security.authc.realms.file.type=file";
|
||||||
|
UserException e = expectThrows(UserException.class, () -> {
|
||||||
|
execute("roles", pathHomeParameter, fileTypeParameter, "username");
|
||||||
|
});
|
||||||
|
assertEquals(ExitCodes.CONFIG, e.exitCode);
|
||||||
|
assertThat(e.getMessage(), containsString("is the configuration directory for Elasticsearch and create directory"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue