Add secure setting for watcher email password (#31620)

Other watcher actions already account for secure settings in their
sensitive settings, whereas the email sending action did not. This adds
the ability to optionally set a secure_password for email accounts.
This commit is contained in:
Michael Basnight 2018-07-13 11:13:10 -05:00 committed by GitHub
parent c1a81e552f
commit bf7689071b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 8 deletions

View File

@ -7,6 +7,9 @@ package org.elasticsearch.xpack.watcher.notification.email;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.SpecialPermission;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.common.unit.TimeValue;
@ -24,10 +27,13 @@ import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Properties;
import java.util.Set;
public class Account {
static final String SMTP_PROTOCOL = "smtp";
private static final String SMTP_PASSWORD = "password";
private static final Setting<SecureString> SECURE_PASSWORD_SETTING = SecureSetting.secureString("secure_" + SMTP_PASSWORD, null);
static {
SecurityManager sm = System.getSecurityManager();
@ -101,7 +107,7 @@ public class Account {
if (auth != null && auth.password() != null) {
password = new String(auth.password().text(cryptoService));
} else if (config.smtp.password != null) {
password = new String(config.smtp.password);
password = new String(config.smtp.password.getChars());
}
if (profile == null) {
@ -199,18 +205,40 @@ public class Account {
final String host;
final int port;
final String user;
final char[] password;
final SecureString password;
final Properties properties;
Smtp(Settings settings) {
host = settings.get("host", settings.get("localaddress", settings.get("local_address")));
port = settings.getAsInt("port", settings.getAsInt("localport", settings.getAsInt("local_port", 25)));
user = settings.get("user", settings.get("from", null));
String passStr = settings.get("password", null);
password = passStr != null ? passStr.toCharArray() : null;
password = getSecureSetting(SMTP_PASSWORD, settings, SECURE_PASSWORD_SETTING);
//password = passStr != null ? passStr.toCharArray() : null;
properties = loadSmtpProperties(settings);
}
/**
* Finds a setting, and then a secure setting if the setting is null, or returns null if one does not exist. This differs
* from other getSetting calls in that it allows for null whereas the other methods throw an exception.
*
* Note: if your setting was not previously secure, than the string reference that is in the setting object is still
* insecure. This is only constructing a new SecureString with the char[] of the insecure setting.
*/
private static SecureString getSecureSetting(String settingName, Settings settings, Setting<SecureString> secureSetting) {
String value = settings.get(settingName);
if (value == null) {
SecureString secureString = secureSetting.get(settings);
if (secureString != null && secureString.length() > 0) {
return secureString;
} else {
return null;
}
} else {
return new SecureString(value.toCharArray());
}
}
/**
* loads the standard Java Mail properties as settings from the given account settings.
* The standard settings are not that readable, therefore we enabled the user to configure
@ -231,7 +259,9 @@ public class Account {
settings = builder.build();
Properties props = new Properties();
for (String key : settings.keySet()) {
// Secure strings can not be retreived out of a settings object and should be handled differently
Set<String> insecureSettings = settings.filter(s -> s.startsWith("secure_") == false).keySet();
for (String key : insecureSettings) {
props.setProperty(SMTP_SETTINGS_PREFIX + key, settings.get(key));
}
return props;

View File

@ -7,6 +7,8 @@ package org.elasticsearch.xpack.watcher.notification.email;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
@ -63,6 +65,10 @@ public class EmailService extends NotificationService<Account> {
Setting.affixKeySetting("xpack.notification.email.account.", "smtp.password",
(key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered));
private static final Setting.AffixSetting<SecureString> SETTING_SECURE_PASSWORD =
Setting.affixKeySetting("xpack.notification.email.account.", "smtp.secure_password",
(key) -> SecureSetting.secureString(key, null));
private static final Setting.AffixSetting<TimeValue> SETTING_SMTP_TIMEOUT =
Setting.affixKeySetting("xpack.notification.email.account.", "smtp.timeout",
(key) -> Setting.timeSetting(key, TimeValue.timeValueMinutes(2), Property.Dynamic, Property.NodeScope));
@ -111,6 +117,7 @@ public class EmailService extends NotificationService<Account> {
clusterSettings.addAffixUpdateConsumer(SETTING_SMTP_PORT, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_SMTP_USER, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_SMTP_PASSWORD, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_SECURE_PASSWORD, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_SMTP_TIMEOUT, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_SMTP_CONNECTION_TIMEOUT, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_SMTP_WRITE_TIMEOUT, (s, o) -> {}, (s, o) -> {});
@ -172,7 +179,8 @@ public class EmailService extends NotificationService<Account> {
return Arrays.asList(SETTING_DEFAULT_ACCOUNT, SETTING_PROFILE, SETTING_EMAIL_DEFAULTS, SETTING_SMTP_AUTH, SETTING_SMTP_HOST,
SETTING_SMTP_PASSWORD, SETTING_SMTP_PORT, SETTING_SMTP_STARTTLS_ENABLE, SETTING_SMTP_USER, SETTING_SMTP_STARTTLS_REQUIRED,
SETTING_SMTP_TIMEOUT, SETTING_SMTP_CONNECTION_TIMEOUT, SETTING_SMTP_WRITE_TIMEOUT, SETTING_SMTP_LOCAL_ADDRESS,
SETTING_SMTP_LOCAL_PORT, SETTING_SMTP_SEND_PARTIAL, SETTING_SMTP_WAIT_ON_QUIT, SETTING_SMTP_SSL_TRUST_ADDRESS);
SETTING_SMTP_LOCAL_PORT, SETTING_SMTP_SEND_PARTIAL, SETTING_SMTP_WAIT_ON_QUIT, SETTING_SMTP_SSL_TRUST_ADDRESS,
SETTING_SECURE_PASSWORD);
}
}

View File

@ -5,6 +5,7 @@
*/
package org.elasticsearch.xpack.watcher.notification.email;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.test.ESTestCase;
@ -16,7 +17,6 @@ import org.junit.Before;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.internet.InternetAddress;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -149,7 +149,7 @@ public class AccountTests extends ESTestCase {
assertThat(config.smtp.host, is(host));
assertThat(config.smtp.user, is(user));
if (password != null) {
assertThat(config.smtp.password, is(password.toCharArray()));
assertThat(config.smtp.password.getChars(), is(password.toCharArray()));
} else {
assertThat(config.smtp.password, nullValue());
}
@ -292,4 +292,30 @@ public class AccountTests extends ESTestCase {
.build()), null, logger);
});
}
public void testEnsurePasswordSetAsSecureSetting() {
String password = "password";
MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString("smtp.secure_password", password);
Settings settings = Settings.builder()
.put("smtp.host", "localhost")
.put("smtp.port", server.port())
.put("smtp.connection_timeout", TimeValue.timeValueMinutes(4))
.setSecureSettings(secureSettings)
.build();
Account.Config config = new Account.Config("default", settings);
assertThat(config.smtp.password.getChars(), equalTo(password.toCharArray()));
settings = Settings.builder()
.put("smtp.host", "localhost")
.put("smtp.port", server.port())
.put("smtp.connection_timeout", TimeValue.timeValueMinutes(4))
.put("smtp.password", password)
.build();
config = new Account.Config("default", settings);
assertThat(config.smtp.password.getChars(), equalTo(password.toCharArray()));
}
}