Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add secure setting for watcher email password #31620

Merged
merged 5 commits into from
Jul 13, 2018
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 @@ -7,6 +7,9 @@

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;
Expand All @@ -24,10 +27,13 @@
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();
Expand Down Expand Up @@ -101,7 +107,7 @@ public Email send(Email email, Authentication auth, Profile profile) throws Mess
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) {
Expand Down Expand Up @@ -199,18 +205,40 @@ static class Smtp {
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
Expand All @@ -231,7 +259,9 @@ static Properties loadSmtpProperties(Settings settings) {

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

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;
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -111,6 +117,7 @@ public EmailService(Settings settings, @Nullable CryptoService cryptoService, Cl
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) -> {});
Expand Down Expand Up @@ -172,7 +179,8 @@ public static List<Setting<?>> getSettings() {
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);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -16,7 +17,6 @@
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;
Expand Down Expand Up @@ -149,7 +149,7 @@ public void testConfig() throws Exception {
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());
}
Expand Down Expand Up @@ -292,4 +292,30 @@ public void testAccountTimeoutsConfiguredAsNumberAreRejected() {
.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()));
}
}