Add SSL/TLS settings for watcher email (#45836)
This change adds a new SSL context xpack.notification.email.ssl.* that supports the standard SSL configuration settings (truststore, verification_mode, etc). This SSL context is used when configuring outbound SMTP properties for watcher email notifications. Backport of: #45272
This commit is contained in:
parent
e38289b94c
commit
029725fc35
|
@ -76,7 +76,7 @@ corresponding endpoints are whitelisted as well.
|
||||||
|
|
||||||
[[ssl-notification-settings]]
|
[[ssl-notification-settings]]
|
||||||
:ssl-prefix: xpack.http
|
:ssl-prefix: xpack.http
|
||||||
:component: {watcher}
|
:component: {watcher} HTTP
|
||||||
:verifies:
|
:verifies:
|
||||||
:server!:
|
:server!:
|
||||||
:ssl-context: watcher
|
:ssl-context: watcher
|
||||||
|
@ -215,6 +215,15 @@ HTML feature groups>>.
|
||||||
Set to `false` to completely disable HTML sanitation. Not recommended.
|
Set to `false` to completely disable HTML sanitation. Not recommended.
|
||||||
Defaults to `true`.
|
Defaults to `true`.
|
||||||
|
|
||||||
|
[[ssl-notification-smtp-settings]]
|
||||||
|
:ssl-prefix: xpack.notification.email
|
||||||
|
:component: {watcher} Email
|
||||||
|
:verifies:
|
||||||
|
:server!:
|
||||||
|
:ssl-context: watcher-email
|
||||||
|
|
||||||
|
include::ssl-settings.asciidoc[]
|
||||||
|
|
||||||
[float]
|
[float]
|
||||||
[[slack-notification-settings]]
|
[[slack-notification-settings]]
|
||||||
==== Slack Notification Settings
|
==== Slack Notification Settings
|
||||||
|
@ -334,4 +343,4 @@ The default event type. Valid values: `trigger`,`resolve`, `acknowledge`.
|
||||||
`attach_payload`::
|
`attach_payload`::
|
||||||
Whether or not to provide the watch payload as context for
|
Whether or not to provide the watch payload as context for
|
||||||
the event by default. Valid values: `true`, `false`.
|
the event by default. Valid values: `true`, `false`.
|
||||||
--
|
--
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.xpack.core.XPackSettings;
|
import org.elasticsearch.xpack.core.XPackSettings;
|
||||||
import org.elasticsearch.xpack.core.common.socket.SocketAccess;
|
import org.elasticsearch.xpack.core.common.socket.SocketAccess;
|
||||||
import org.elasticsearch.xpack.core.ssl.cert.CertificateInfo;
|
import org.elasticsearch.xpack.core.ssl.cert.CertificateInfo;
|
||||||
|
import org.elasticsearch.xpack.core.watcher.WatcherField;
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
import javax.net.ssl.HostnameVerifier;
|
||||||
import javax.net.ssl.KeyManagerFactory;
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
|
@ -420,6 +421,7 @@ public class SSLService {
|
||||||
sslSettingsMap.put("xpack.http.ssl", settings.getByPrefix("xpack.http.ssl."));
|
sslSettingsMap.put("xpack.http.ssl", settings.getByPrefix("xpack.http.ssl."));
|
||||||
sslSettingsMap.putAll(getRealmsSSLSettings(settings));
|
sslSettingsMap.putAll(getRealmsSSLSettings(settings));
|
||||||
sslSettingsMap.putAll(getMonitoringExporterSettings(settings));
|
sslSettingsMap.putAll(getMonitoringExporterSettings(settings));
|
||||||
|
sslSettingsMap.put(WatcherField.EMAIL_NOTIFICATION_SSL_PREFIX, settings.getByPrefix(WatcherField.EMAIL_NOTIFICATION_SSL_PREFIX));
|
||||||
|
|
||||||
sslSettingsMap.forEach((key, sslSettings) -> loadConfiguration(key, sslSettings, sslContextHolders));
|
sslSettingsMap.forEach((key, sslSettings) -> loadConfiguration(key, sslSettings, sslContextHolders));
|
||||||
|
|
||||||
|
|
|
@ -15,5 +15,7 @@ public final class WatcherField {
|
||||||
public static final Setting<InputStream> ENCRYPTION_KEY_SETTING =
|
public static final Setting<InputStream> ENCRYPTION_KEY_SETTING =
|
||||||
SecureSetting.secureFile("xpack.watcher.encryption_key", null);
|
SecureSetting.secureFile("xpack.watcher.encryption_key", null);
|
||||||
|
|
||||||
|
public static final String EMAIL_NOTIFICATION_SSL_PREFIX = "xpack.notification.email.ssl.";
|
||||||
|
|
||||||
private WatcherField() {}
|
private WatcherField() {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,10 @@ thirdPartyAudit {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forbiddenPatterns {
|
||||||
|
exclude '**/*.p12'
|
||||||
|
}
|
||||||
|
|
||||||
// pulled in as external dependency to work on java 9
|
// pulled in as external dependency to work on java 9
|
||||||
rootProject.globalInfo.ready {
|
rootProject.globalInfo.ready {
|
||||||
if (project.runtimeJavaVersion <= JavaVersion.VERSION_1_8) {
|
if (project.runtimeJavaVersion <= JavaVersion.VERSION_1_8) {
|
||||||
|
|
|
@ -269,11 +269,12 @@ public class Watcher extends Plugin implements ActionPlugin, ScriptPlugin, Reloa
|
||||||
|
|
||||||
new WatcherIndexTemplateRegistry(environment.settings(), clusterService, threadPool, client, xContentRegistry);
|
new WatcherIndexTemplateRegistry(environment.settings(), clusterService, threadPool, client, xContentRegistry);
|
||||||
|
|
||||||
|
final SSLService sslService = getSslService();
|
||||||
// http client
|
// http client
|
||||||
httpClient = new HttpClient(settings, getSslService(), cryptoService, clusterService);
|
httpClient = new HttpClient(settings, sslService, cryptoService, clusterService);
|
||||||
|
|
||||||
// notification
|
// notification
|
||||||
EmailService emailService = new EmailService(settings, cryptoService, clusterService.getClusterSettings());
|
EmailService emailService = new EmailService(settings, cryptoService, sslService, clusterService.getClusterSettings());
|
||||||
JiraService jiraService = new JiraService(settings, httpClient, clusterService.getClusterSettings());
|
JiraService jiraService = new JiraService(settings, httpClient, clusterService.getClusterSettings());
|
||||||
SlackService slackService = new SlackService(settings, httpClient, clusterService.getClusterSettings());
|
SlackService slackService = new SlackService(settings, httpClient, clusterService.getClusterSettings());
|
||||||
PagerDutyService pagerDutyService = new PagerDutyService(settings, httpClient, clusterService.getClusterSettings());
|
PagerDutyService pagerDutyService = new PagerDutyService(settings, httpClient, clusterService.getClusterSettings());
|
||||||
|
|
|
@ -95,7 +95,7 @@ public abstract class NotificationService<Account> {
|
||||||
final Settings completeSettings = completeSettingsBuilder.build();
|
final Settings completeSettings = completeSettingsBuilder.build();
|
||||||
// obtain account names and create accounts
|
// obtain account names and create accounts
|
||||||
final Set<String> accountNames = getAccountNames(completeSettings);
|
final Set<String> accountNames = getAccountNames(completeSettings);
|
||||||
this.accounts = createAccounts(completeSettings, accountNames, this::createAccount);
|
this.accounts = createAccounts(completeSettings, accountNames, (name, accountSettings) -> createAccount(name, accountSettings));
|
||||||
this.defaultAccount = findDefaultAccountOrNull(completeSettings, this.accounts);
|
this.defaultAccount = findDefaultAccountOrNull(completeSettings, this.accounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.xpack.watcher.notification.email;
|
||||||
|
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.elasticsearch.SpecialPermission;
|
import org.elasticsearch.SpecialPermission;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.settings.SecureSetting;
|
import org.elasticsearch.common.settings.SecureSetting;
|
||||||
import org.elasticsearch.common.settings.SecureString;
|
import org.elasticsearch.common.settings.SecureString;
|
||||||
import org.elasticsearch.common.settings.Setting;
|
import org.elasticsearch.common.settings.Setting;
|
||||||
|
@ -22,6 +23,8 @@ import javax.mail.Session;
|
||||||
import javax.mail.Transport;
|
import javax.mail.Transport;
|
||||||
import javax.mail.internet.InternetAddress;
|
import javax.mail.internet.InternetAddress;
|
||||||
import javax.mail.internet.MimeMessage;
|
import javax.mail.internet.MimeMessage;
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
import java.security.PrivilegedActionException;
|
import java.security.PrivilegedActionException;
|
||||||
|
@ -184,7 +187,7 @@ public class Account {
|
||||||
final Smtp smtp;
|
final Smtp smtp;
|
||||||
final EmailDefaults defaults;
|
final EmailDefaults defaults;
|
||||||
|
|
||||||
Config(String name, Settings settings) {
|
Config(String name, Settings settings, @Nullable SSLSocketFactory sslSocketFactory) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
profile = Profile.resolve(settings.get("profile"), Profile.STANDARD);
|
profile = Profile.resolve(settings.get("profile"), Profile.STANDARD);
|
||||||
defaults = new EmailDefaults(name, settings.getAsSettings("email_defaults"));
|
defaults = new EmailDefaults(name, settings.getAsSettings("email_defaults"));
|
||||||
|
@ -193,6 +196,9 @@ public class Account {
|
||||||
String msg = "missing required email account setting for account [" + name + "]. 'smtp.host' must be configured";
|
String msg = "missing required email account setting for account [" + name + "]. 'smtp.host' must be configured";
|
||||||
throw new SettingsException(msg);
|
throw new SettingsException(msg);
|
||||||
}
|
}
|
||||||
|
if (sslSocketFactory != null) {
|
||||||
|
smtp.setSocketFactory(sslSocketFactory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Session createSession() {
|
public Session createSession() {
|
||||||
|
@ -220,7 +226,7 @@ public class Account {
|
||||||
/**
|
/**
|
||||||
* Finds a setting, and then a secure setting if the setting is null, or returns null if one does not exist. This differs
|
* 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.
|
* from other getSetting calls in that it allows for null whereas the other methods throw an exception.
|
||||||
*
|
* <p>
|
||||||
* Note: if your setting was not previously secure, than the string reference that is in the setting object is still
|
* 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.
|
* insecure. This is only constructing a new SecureString with the char[] of the insecure setting.
|
||||||
*/
|
*/
|
||||||
|
@ -274,6 +280,10 @@ public class Account {
|
||||||
settings.put(newKey, TimeValue.parseTimeValue(value, currentKey).millis());
|
settings.put(newKey, TimeValue.parseTimeValue(value, currentKey).millis());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSocketFactory(SocketFactory socketFactory) {
|
||||||
|
this.properties.put("mail.smtp.ssl.socketFactory", socketFactory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,15 +15,20 @@ import org.elasticsearch.common.settings.Setting;
|
||||||
import org.elasticsearch.common.settings.Setting.Property;
|
import org.elasticsearch.common.settings.Setting.Property;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
|
||||||
|
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
|
||||||
|
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||||
import org.elasticsearch.xpack.core.watcher.crypto.CryptoService;
|
import org.elasticsearch.xpack.core.watcher.crypto.CryptoService;
|
||||||
import org.elasticsearch.xpack.watcher.notification.NotificationService;
|
import org.elasticsearch.xpack.watcher.notification.NotificationService;
|
||||||
|
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xpack.core.watcher.WatcherField.EMAIL_NOTIFICATION_SSL_PREFIX;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A component to store email credentials and handle sending email notifications.
|
* A component to store email credentials and handle sending email notifications.
|
||||||
*/
|
*/
|
||||||
|
@ -101,13 +106,17 @@ public class EmailService extends NotificationService<Account> {
|
||||||
Setting.affixKeySetting("xpack.notification.email.account.", "smtp.wait_on_quit",
|
Setting.affixKeySetting("xpack.notification.email.account.", "smtp.wait_on_quit",
|
||||||
(key) -> Setting.boolSetting(key, true, Property.Dynamic, Property.NodeScope));
|
(key) -> Setting.boolSetting(key, true, Property.Dynamic, Property.NodeScope));
|
||||||
|
|
||||||
|
private static final SSLConfigurationSettings SSL_SETTINGS = SSLConfigurationSettings.withPrefix(EMAIL_NOTIFICATION_SSL_PREFIX);
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger(EmailService.class);
|
private static final Logger logger = LogManager.getLogger(EmailService.class);
|
||||||
|
|
||||||
private final CryptoService cryptoService;
|
private final CryptoService cryptoService;
|
||||||
|
private final SSLService sslService;
|
||||||
|
|
||||||
public EmailService(Settings settings, @Nullable CryptoService cryptoService, ClusterSettings clusterSettings) {
|
public EmailService(Settings settings, @Nullable CryptoService cryptoService, SSLService sslService, ClusterSettings clusterSettings) {
|
||||||
super("email", settings, clusterSettings, EmailService.getDynamicSettings(), EmailService.getSecureSettings());
|
super("email", settings, clusterSettings, EmailService.getDynamicSettings(), EmailService.getSecureSettings());
|
||||||
this.cryptoService = cryptoService;
|
this.cryptoService = cryptoService;
|
||||||
|
this.sslService = sslService;
|
||||||
// ensure logging of setting changes
|
// ensure logging of setting changes
|
||||||
clusterSettings.addSettingsUpdateConsumer(SETTING_DEFAULT_ACCOUNT, (s) -> {});
|
clusterSettings.addSettingsUpdateConsumer(SETTING_DEFAULT_ACCOUNT, (s) -> {});
|
||||||
clusterSettings.addAffixUpdateConsumer(SETTING_PROFILE, (s, o) -> {}, (s, o) -> {});
|
clusterSettings.addAffixUpdateConsumer(SETTING_PROFILE, (s, o) -> {}, (s, o) -> {});
|
||||||
|
@ -132,10 +141,19 @@ public class EmailService extends NotificationService<Account> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Account createAccount(String name, Settings accountSettings) {
|
protected Account createAccount(String name, Settings accountSettings) {
|
||||||
Account.Config config = new Account.Config(name, accountSettings);
|
Account.Config config = new Account.Config(name, accountSettings, getSmtpSslSocketFactory());
|
||||||
return new Account(config, cryptoService, logger);
|
return new Account(config, cryptoService, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private SSLSocketFactory getSmtpSslSocketFactory() {
|
||||||
|
final SSLConfiguration sslConfiguration = sslService.getSSLConfiguration(EMAIL_NOTIFICATION_SSL_PREFIX);
|
||||||
|
if (sslConfiguration == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return sslService.sslSocketFactory(sslConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
public EmailSent send(Email email, Authentication auth, Profile profile, String accountName) throws MessagingException {
|
public EmailSent send(Email email, Authentication auth, Profile profile, String accountName) throws MessagingException {
|
||||||
Account account = getAccount(accountName);
|
Account account = getAccount(accountName);
|
||||||
if (account == null) {
|
if (account == null) {
|
||||||
|
@ -189,6 +207,7 @@ public class EmailService extends NotificationService<Account> {
|
||||||
public static List<Setting<?>> getSettings() {
|
public static List<Setting<?>> getSettings() {
|
||||||
List<Setting<?>> allSettings = new ArrayList<Setting<?>>(EmailService.getDynamicSettings());
|
List<Setting<?>> allSettings = new ArrayList<Setting<?>>(EmailService.getDynamicSettings());
|
||||||
allSettings.addAll(EmailService.getSecureSettings());
|
allSettings.addAll(EmailService.getSecureSettings());
|
||||||
|
allSettings.addAll(SSL_SETTINGS.getAllSettings());
|
||||||
return allSettings;
|
return allSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.elasticsearch.common.settings.MockSecureSettings;
|
||||||
import org.elasticsearch.common.settings.Setting;
|
import org.elasticsearch.common.settings.Setting;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||||
import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext;
|
import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext;
|
||||||
import org.elasticsearch.xpack.core.watcher.watch.Payload;
|
import org.elasticsearch.xpack.core.watcher.watch.Payload;
|
||||||
import org.elasticsearch.xpack.watcher.common.text.TextTemplateEngine;
|
import org.elasticsearch.xpack.watcher.common.text.TextTemplateEngine;
|
||||||
|
@ -30,6 +31,7 @@ import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
public class EmailMessageIdTests extends ESTestCase {
|
public class EmailMessageIdTests extends ESTestCase {
|
||||||
|
|
||||||
|
@ -56,7 +58,7 @@ public class EmailMessageIdTests extends ESTestCase {
|
||||||
Set<Setting<?>> registeredSettings = new HashSet<>(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
|
Set<Setting<?>> registeredSettings = new HashSet<>(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
|
||||||
registeredSettings.addAll(EmailService.getSettings());
|
registeredSettings.addAll(EmailService.getSettings());
|
||||||
ClusterSettings clusterSettings = new ClusterSettings(settings, registeredSettings);
|
ClusterSettings clusterSettings = new ClusterSettings(settings, registeredSettings);
|
||||||
emailService = new EmailService(settings, null, clusterSettings);
|
emailService = new EmailService(settings, null, mock(SSLService.class), clusterSettings);
|
||||||
EmailTemplate emailTemplate = EmailTemplate.builder().from("from@example.org").to("to@example.org")
|
EmailTemplate emailTemplate = EmailTemplate.builder().from("from@example.org").to("to@example.org")
|
||||||
.subject("subject").textBody("body").build();
|
.subject("subject").textBody("body").build();
|
||||||
emailAction = new EmailAction(emailTemplate, null, null, null, null, null);
|
emailAction = new EmailAction(emailTemplate, null, null, null, null, null);
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.watcher.actions.email;
|
||||||
|
|
||||||
|
import org.apache.http.ssl.SSLContextBuilder;
|
||||||
|
import org.elasticsearch.common.settings.ClusterSettings;
|
||||||
|
import org.elasticsearch.common.settings.MockSecureSettings;
|
||||||
|
import org.elasticsearch.common.settings.Setting;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.env.TestEnvironment;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||||
|
import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext;
|
||||||
|
import org.elasticsearch.xpack.core.watcher.watch.Payload;
|
||||||
|
import org.elasticsearch.xpack.watcher.common.text.TextTemplateEngine;
|
||||||
|
import org.elasticsearch.xpack.watcher.notification.email.EmailService;
|
||||||
|
import org.elasticsearch.xpack.watcher.notification.email.EmailTemplate;
|
||||||
|
import org.elasticsearch.xpack.watcher.notification.email.HtmlSanitizer;
|
||||||
|
import org.elasticsearch.xpack.watcher.notification.email.support.EmailServer;
|
||||||
|
import org.elasticsearch.xpack.watcher.test.MockTextTemplateEngine;
|
||||||
|
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
|
import javax.mail.MessagingException;
|
||||||
|
import javax.mail.internet.MimeMessage;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
|
||||||
|
public class EmailSslTests extends ESTestCase {
|
||||||
|
|
||||||
|
private EmailServer server;
|
||||||
|
private TextTemplateEngine textTemplateEngine = new MockTextTemplateEngine();
|
||||||
|
private HtmlSanitizer htmlSanitizer = new HtmlSanitizer(Settings.EMPTY);
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void startSmtpServer() throws GeneralSecurityException, IOException {
|
||||||
|
final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
|
final char[] keystorePassword = "test-smtp".toCharArray();
|
||||||
|
try (InputStream is = getDataInputStream("test-smtp.p12")) {
|
||||||
|
keyStore.load(is, keystorePassword);
|
||||||
|
}
|
||||||
|
final SSLContext sslContext = new SSLContextBuilder().loadKeyMaterial(keyStore, keystorePassword).build();
|
||||||
|
server = EmailServer.localhost(logger, sslContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void stopSmtpServer() {
|
||||||
|
server.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFailureSendingMessageToSmtpServerWithUntrustedCertificateAuthority() throws Exception {
|
||||||
|
final Settings.Builder settings = Settings.builder();
|
||||||
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
|
final ExecutableEmailAction emailAction = buildEmailAction(settings, secureSettings);
|
||||||
|
final WatchExecutionContext ctx = WatcherTestUtils.createWatchExecutionContext();
|
||||||
|
final MessagingException exception = expectThrows(MessagingException.class,
|
||||||
|
() -> emailAction.execute("my_action_id", ctx, Payload.EMPTY));
|
||||||
|
final List<Throwable> allCauses = getAllCauses(exception);
|
||||||
|
assertThat(allCauses, Matchers.hasItem(Matchers.instanceOf(SSLException.class)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCanSendMessageToSmtpServerUsingTrustStore() throws Exception {
|
||||||
|
List<MimeMessage> messages = new ArrayList<>();
|
||||||
|
server.addListener(messages::add);
|
||||||
|
try {
|
||||||
|
final Settings.Builder settings = Settings.builder()
|
||||||
|
.put("xpack.notification.email.ssl.truststore.path", getDataPath("test-smtp.p12"));
|
||||||
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
|
secureSettings.setString("xpack.notification.email.ssl.truststore.secure_password", "test-smtp");
|
||||||
|
|
||||||
|
ExecutableEmailAction emailAction = buildEmailAction(settings, secureSettings);
|
||||||
|
|
||||||
|
WatchExecutionContext ctx = WatcherTestUtils.createWatchExecutionContext();
|
||||||
|
emailAction.execute("my_action_id", ctx, Payload.EMPTY);
|
||||||
|
|
||||||
|
assertThat(messages, hasSize(1));
|
||||||
|
} finally {
|
||||||
|
server.clearListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCanSendMessageToSmtpServerByDisablingVerification() throws Exception {
|
||||||
|
List<MimeMessage> messages = new ArrayList<>();
|
||||||
|
server.addListener(messages::add);
|
||||||
|
try {
|
||||||
|
final Settings.Builder settings = Settings.builder().put("xpack.notification.email.ssl.verification_mode", "none");
|
||||||
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
|
ExecutableEmailAction emailAction = buildEmailAction(settings, secureSettings);
|
||||||
|
|
||||||
|
WatchExecutionContext ctx = WatcherTestUtils.createWatchExecutionContext();
|
||||||
|
emailAction.execute("my_action_id", ctx, Payload.EMPTY);
|
||||||
|
|
||||||
|
assertThat(messages, hasSize(1));
|
||||||
|
} finally {
|
||||||
|
server.clearListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExecutableEmailAction buildEmailAction(Settings.Builder baseSettings, MockSecureSettings secureSettings) {
|
||||||
|
secureSettings.setString("xpack.notification.email.account.test.smtp.secure_password", EmailServer.PASSWORD);
|
||||||
|
Settings settings = baseSettings
|
||||||
|
.put("path.home", createTempDir())
|
||||||
|
.put("xpack.notification.email.account.test.smtp.auth", true)
|
||||||
|
.put("xpack.notification.email.account.test.smtp.user", EmailServer.USERNAME)
|
||||||
|
.put("xpack.notification.email.account.test.smtp.port", server.port())
|
||||||
|
.put("xpack.notification.email.account.test.smtp.host", "localhost")
|
||||||
|
.setSecureSettings(secureSettings)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Set<Setting<?>> registeredSettings = new HashSet<>(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
|
||||||
|
registeredSettings.addAll(EmailService.getSettings());
|
||||||
|
ClusterSettings clusterSettings = new ClusterSettings(settings, registeredSettings);
|
||||||
|
SSLService sslService = new SSLService(settings, TestEnvironment.newEnvironment(settings));
|
||||||
|
final EmailService emailService = new EmailService(settings, null, sslService, clusterSettings);
|
||||||
|
EmailTemplate emailTemplate = EmailTemplate.builder().from("from@example.org").to("to@example.org")
|
||||||
|
.subject("subject").textBody("body").build();
|
||||||
|
final EmailAction emailAction = new EmailAction(emailTemplate, null, null, null, null, null);
|
||||||
|
return new ExecutableEmailAction(emailAction, logger, emailService, textTemplateEngine, htmlSanitizer, Collections.emptyMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Throwable> getAllCauses(Exception exception) {
|
||||||
|
final List<Throwable> allCauses = new ArrayList<>();
|
||||||
|
Throwable cause = exception.getCause();
|
||||||
|
while (cause != null) {
|
||||||
|
allCauses.add(cause);
|
||||||
|
cause = cause.getCause();
|
||||||
|
}
|
||||||
|
return allCauses;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import org.elasticsearch.common.settings.Setting;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.settings.SettingsException;
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.xpack.watcher.notification.NotificationService;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
|
@ -141,7 +141,7 @@ public class AccountTests extends ESTestCase {
|
||||||
|
|
||||||
Settings settings = builder.build();
|
Settings settings = builder.build();
|
||||||
|
|
||||||
Account.Config config = new Account.Config(accountName, settings);
|
Account.Config config = new Account.Config(accountName, settings, null);
|
||||||
|
|
||||||
assertThat(config.profile, is(profile));
|
assertThat(config.profile, is(profile));
|
||||||
assertThat(config.defaults, equalTo(emailDefaults));
|
assertThat(config.defaults, equalTo(emailDefaults));
|
||||||
|
@ -165,7 +165,7 @@ public class AccountTests extends ESTestCase {
|
||||||
.put("smtp.port", server.port())
|
.put("smtp.port", server.port())
|
||||||
.put("smtp.user", EmailServer.USERNAME)
|
.put("smtp.user", EmailServer.USERNAME)
|
||||||
.setSecureSettings(secureSettings)
|
.setSecureSettings(secureSettings)
|
||||||
.build()), null, logger);
|
.build(), null), null, logger);
|
||||||
|
|
||||||
Email email = Email.builder()
|
Email email = Email.builder()
|
||||||
.id("_id")
|
.id("_id")
|
||||||
|
@ -202,7 +202,7 @@ public class AccountTests extends ESTestCase {
|
||||||
.put("smtp.port", server.port())
|
.put("smtp.port", server.port())
|
||||||
.put("smtp.user", EmailServer.USERNAME)
|
.put("smtp.user", EmailServer.USERNAME)
|
||||||
.setSecureSettings(secureSettings)
|
.setSecureSettings(secureSettings)
|
||||||
.build()), null, logger);
|
.build(), null), null, logger);
|
||||||
|
|
||||||
Email email = Email.builder()
|
Email email = Email.builder()
|
||||||
.id("_id")
|
.id("_id")
|
||||||
|
@ -240,7 +240,7 @@ public class AccountTests extends ESTestCase {
|
||||||
Account account = new Account(new Account.Config("default", Settings.builder()
|
Account account = new Account(new Account.Config("default", Settings.builder()
|
||||||
.put("smtp.host", "localhost")
|
.put("smtp.host", "localhost")
|
||||||
.put("smtp.port", server.port())
|
.put("smtp.port", server.port())
|
||||||
.build()), null, logger);
|
.build(), null), null, logger);
|
||||||
|
|
||||||
Email email = Email.builder()
|
Email email = Email.builder()
|
||||||
.id("_id")
|
.id("_id")
|
||||||
|
@ -264,7 +264,7 @@ public class AccountTests extends ESTestCase {
|
||||||
Account account = new Account(new Account.Config("default", Settings.builder()
|
Account account = new Account(new Account.Config("default", Settings.builder()
|
||||||
.put("smtp.host", "localhost")
|
.put("smtp.host", "localhost")
|
||||||
.put("smtp.port", server.port())
|
.put("smtp.port", server.port())
|
||||||
.build()), null, logger);
|
.build(), null), null, logger);
|
||||||
|
|
||||||
Properties mailProperties = account.getConfig().smtp.properties;
|
Properties mailProperties = account.getConfig().smtp.properties;
|
||||||
assertThat(mailProperties.get("mail.smtp.connectiontimeout"), is(String.valueOf(TimeValue.timeValueMinutes(2).millis())));
|
assertThat(mailProperties.get("mail.smtp.connectiontimeout"), is(String.valueOf(TimeValue.timeValueMinutes(2).millis())));
|
||||||
|
@ -279,7 +279,7 @@ public class AccountTests extends ESTestCase {
|
||||||
.put("smtp.connection_timeout", TimeValue.timeValueMinutes(4))
|
.put("smtp.connection_timeout", TimeValue.timeValueMinutes(4))
|
||||||
.put("smtp.write_timeout", TimeValue.timeValueMinutes(6))
|
.put("smtp.write_timeout", TimeValue.timeValueMinutes(6))
|
||||||
.put("smtp.timeout", TimeValue.timeValueMinutes(8))
|
.put("smtp.timeout", TimeValue.timeValueMinutes(8))
|
||||||
.build()), null, logger);
|
.build(), null), null, logger);
|
||||||
|
|
||||||
Properties mailProperties = account.getConfig().smtp.properties;
|
Properties mailProperties = account.getConfig().smtp.properties;
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ public class AccountTests extends ESTestCase {
|
||||||
.put("smtp.host", "localhost")
|
.put("smtp.host", "localhost")
|
||||||
.put("smtp.port", server.port())
|
.put("smtp.port", server.port())
|
||||||
.put("smtp.connection_timeout", 4000)
|
.put("smtp.connection_timeout", 4000)
|
||||||
.build()), null, logger);
|
.build(), null), null, logger);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.elasticsearch.common.settings.ClusterSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.settings.SettingsException;
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
@ -16,13 +17,14 @@ import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.isOneOf;
|
import static org.hamcrest.Matchers.isOneOf;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
public class AccountsTests extends ESTestCase {
|
public class AccountsTests extends ESTestCase {
|
||||||
public void testSingleAccount() throws Exception {
|
public void testSingleAccount() throws Exception {
|
||||||
Settings.Builder builder = Settings.builder()
|
Settings.Builder builder = Settings.builder()
|
||||||
.put("default_account", "account1");
|
.put("default_account", "account1");
|
||||||
addAccountSettings("account1", builder);
|
addAccountSettings("account1", builder);
|
||||||
EmailService service = new EmailService(builder.build(), null,
|
EmailService service = new EmailService(builder.build(), null, mock(SSLService.class),
|
||||||
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
||||||
Account account = service.getAccount("account1");
|
Account account = service.getAccount("account1");
|
||||||
assertThat(account, notNullValue());
|
assertThat(account, notNullValue());
|
||||||
|
@ -35,7 +37,7 @@ public class AccountsTests extends ESTestCase {
|
||||||
public void testSingleAccountNoExplicitDefault() throws Exception {
|
public void testSingleAccountNoExplicitDefault() throws Exception {
|
||||||
Settings.Builder builder = Settings.builder();
|
Settings.Builder builder = Settings.builder();
|
||||||
addAccountSettings("account1", builder);
|
addAccountSettings("account1", builder);
|
||||||
EmailService service = new EmailService(builder.build(), null,
|
EmailService service = new EmailService(builder.build(), null, mock(SSLService.class),
|
||||||
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
||||||
Account account = service.getAccount("account1");
|
Account account = service.getAccount("account1");
|
||||||
assertThat(account, notNullValue());
|
assertThat(account, notNullValue());
|
||||||
|
@ -51,7 +53,7 @@ public class AccountsTests extends ESTestCase {
|
||||||
addAccountSettings("account1", builder);
|
addAccountSettings("account1", builder);
|
||||||
addAccountSettings("account2", builder);
|
addAccountSettings("account2", builder);
|
||||||
|
|
||||||
EmailService service = new EmailService(builder.build(), null,
|
EmailService service = new EmailService(builder.build(), null, mock(SSLService.class),
|
||||||
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
||||||
Account account = service.getAccount("account1");
|
Account account = service.getAccount("account1");
|
||||||
assertThat(account, notNullValue());
|
assertThat(account, notNullValue());
|
||||||
|
@ -70,7 +72,7 @@ public class AccountsTests extends ESTestCase {
|
||||||
addAccountSettings("account1", builder);
|
addAccountSettings("account1", builder);
|
||||||
addAccountSettings("account2", builder);
|
addAccountSettings("account2", builder);
|
||||||
|
|
||||||
EmailService service = new EmailService(builder.build(), null,
|
EmailService service = new EmailService(builder.build(), null, mock(SSLService.class),
|
||||||
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
||||||
Account account = service.getAccount("account1");
|
Account account = service.getAccount("account1");
|
||||||
assertThat(account, notNullValue());
|
assertThat(account, notNullValue());
|
||||||
|
@ -88,13 +90,14 @@ public class AccountsTests extends ESTestCase {
|
||||||
addAccountSettings("account1", builder);
|
addAccountSettings("account1", builder);
|
||||||
addAccountSettings("account2", builder);
|
addAccountSettings("account2", builder);
|
||||||
ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings()));
|
ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings()));
|
||||||
SettingsException e = expectThrows(SettingsException.class, () -> new EmailService(builder.build(), null, clusterSettings));
|
SettingsException e = expectThrows(SettingsException.class,
|
||||||
|
() -> new EmailService(builder.build(), null, mock(SSLService.class), clusterSettings));
|
||||||
assertThat(e.getMessage(), is("could not find default account [unknown]"));
|
assertThat(e.getMessage(), is("could not find default account [unknown]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNoAccount() throws Exception {
|
public void testNoAccount() throws Exception {
|
||||||
Settings.Builder builder = Settings.builder();
|
Settings.Builder builder = Settings.builder();
|
||||||
EmailService service = new EmailService(builder.build(), null,
|
EmailService service = new EmailService(builder.build(), null, mock(SSLService.class),
|
||||||
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
||||||
expectThrows(IllegalArgumentException.class, () -> service.getAccount(null));
|
expectThrows(IllegalArgumentException.class, () -> service.getAccount(null));
|
||||||
}
|
}
|
||||||
|
@ -102,7 +105,8 @@ public class AccountsTests extends ESTestCase {
|
||||||
public void testNoAccountWithDefaultAccount() throws Exception {
|
public void testNoAccountWithDefaultAccount() throws Exception {
|
||||||
Settings settings = Settings.builder().put("xpack.notification.email.default_account", "unknown").build();
|
Settings settings = Settings.builder().put("xpack.notification.email.default_account", "unknown").build();
|
||||||
ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings()));
|
ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings()));
|
||||||
SettingsException e = expectThrows(SettingsException.class, () -> new EmailService(settings, null, clusterSettings));
|
SettingsException e = expectThrows(SettingsException.class,
|
||||||
|
() -> new EmailService(settings, null, mock(SSLService.class), clusterSettings));
|
||||||
assertThat(e.getMessage(), is("could not find default account [unknown]"));
|
assertThat(e.getMessage(), is("could not find default account [unknown]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.elasticsearch.xpack.watcher.notification.email;
|
||||||
import org.elasticsearch.common.settings.ClusterSettings;
|
import org.elasticsearch.common.settings.ClusterSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||||
import org.elasticsearch.xpack.core.watcher.common.secret.Secret;
|
import org.elasticsearch.xpack.core.watcher.common.secret.Secret;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ public class EmailServiceTests extends ESTestCase {
|
||||||
public void init() throws Exception {
|
public void init() throws Exception {
|
||||||
account = mock(Account.class);
|
account = mock(Account.class);
|
||||||
service = new EmailService(Settings.builder().put("xpack.notification.email.account.account1.foo", "bar").build(), null,
|
service = new EmailService(Settings.builder().put("xpack.notification.email.account.account1.foo", "bar").build(), null,
|
||||||
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings()))) {
|
mock(SSLService.class), new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings()))) {
|
||||||
@Override
|
@Override
|
||||||
protected Account createAccount(String name, Settings accountSettings) {
|
protected Account createAccount(String name, Settings accountSettings) {
|
||||||
return account;
|
return account;
|
||||||
|
@ -70,7 +71,7 @@ public class EmailServiceTests extends ESTestCase {
|
||||||
.put("xpack.notification.email.account.account5.smtp.wait_on_quit", true)
|
.put("xpack.notification.email.account.account5.smtp.wait_on_quit", true)
|
||||||
.put("xpack.notification.email.account.account5.smtp.ssl.trust", "host1,host2,host3")
|
.put("xpack.notification.email.account.account5.smtp.ssl.trust", "host1,host2,host3")
|
||||||
.build();
|
.build();
|
||||||
EmailService emailService = new EmailService(settings, null,
|
EmailService emailService = new EmailService(settings, null, mock(SSLService.class),
|
||||||
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
||||||
|
|
||||||
Account account1 = emailService.getAccount("account1");
|
Account account1 = emailService.getAccount("account1");
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.elasticsearch.xpack.watcher.notification.email;
|
||||||
import org.elasticsearch.common.settings.ClusterSettings;
|
import org.elasticsearch.common.settings.ClusterSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||||
|
|
||||||
import javax.mail.BodyPart;
|
import javax.mail.BodyPart;
|
||||||
import javax.mail.Part;
|
import javax.mail.Part;
|
||||||
|
@ -19,6 +20,7 @@ import java.util.HashSet;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
public class ProfileTests extends ESTestCase {
|
public class ProfileTests extends ESTestCase {
|
||||||
|
|
||||||
|
@ -40,7 +42,7 @@ public class ProfileTests extends ESTestCase {
|
||||||
.put("xpack.notification.email.account.foo.smtp.host", "_host")
|
.put("xpack.notification.email.account.foo.smtp.host", "_host")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
EmailService service = new EmailService(settings, null,
|
EmailService service = new EmailService(settings, null, mock(SSLService.class),
|
||||||
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
||||||
Session session = service.getAccount("foo").getConfig().createSession();
|
Session session = service.getAccount("foo").getConfig().createSession();
|
||||||
MimeMessage mimeMessage = Profile.STANDARD.toMimeMessage(email, session);
|
MimeMessage mimeMessage = Profile.STANDARD.toMimeMessage(email, session);
|
||||||
|
@ -62,4 +64,4 @@ public class ProfileTests extends ESTestCase {
|
||||||
|
|
||||||
assertThat("Expected to find an inline attachment in mime message, but didnt", foundInlineAttachment, is(true));
|
assertThat("Expected to find an inline attachment in mime message, but didnt", foundInlineAttachment, is(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package org.elasticsearch.xpack.watcher.notification.email.support;
|
package org.elasticsearch.xpack.watcher.notification.email.support;
|
||||||
|
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.subethamail.smtp.auth.EasyAuthenticationHandlerFactory;
|
import org.subethamail.smtp.auth.EasyAuthenticationHandlerFactory;
|
||||||
import org.subethamail.smtp.helper.SimpleMessageListener;
|
import org.subethamail.smtp.helper.SimpleMessageListener;
|
||||||
import org.subethamail.smtp.helper.SimpleMessageListenerAdapter;
|
import org.subethamail.smtp.helper.SimpleMessageListenerAdapter;
|
||||||
|
@ -14,8 +15,13 @@ import org.subethamail.smtp.server.SMTPServer;
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
import javax.mail.Session;
|
import javax.mail.Session;
|
||||||
import javax.mail.internet.MimeMessage;
|
import javax.mail.internet.MimeMessage;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Socket;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -37,8 +43,8 @@ public class EmailServer {
|
||||||
private final List<Listener> listeners = new CopyOnWriteArrayList<>();
|
private final List<Listener> listeners = new CopyOnWriteArrayList<>();
|
||||||
private final SMTPServer server;
|
private final SMTPServer server;
|
||||||
|
|
||||||
public EmailServer(String host, final Logger logger) {
|
public EmailServer(String host, @Nullable SSLContext sslContext, final Logger logger) {
|
||||||
server = new SMTPServer(new SimpleMessageListenerAdapter(new SimpleMessageListener() {
|
final SimpleMessageListenerAdapter listener = new SimpleMessageListenerAdapter(new SimpleMessageListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(String from, String recipient) {
|
public boolean accept(String from, String recipient) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -49,9 +55,9 @@ public class EmailServer {
|
||||||
try {
|
try {
|
||||||
Session session = Session.getInstance(new Properties());
|
Session session = Session.getInstance(new Properties());
|
||||||
MimeMessage msg = new MimeMessage(session, data);
|
MimeMessage msg = new MimeMessage(session, data);
|
||||||
for (Listener listener : listeners) {
|
for (Listener listener1 : listeners) {
|
||||||
try {
|
try {
|
||||||
listener.on(msg);
|
listener1.on(msg);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Unexpected failure", e);
|
logger.error("Unexpected failure", e);
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
|
@ -61,12 +67,33 @@ public class EmailServer {
|
||||||
throw new RuntimeException("could not create mime message", me);
|
throw new RuntimeException("could not create mime message", me);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}), new EasyAuthenticationHandlerFactory((user, passwd) -> {
|
});
|
||||||
|
final EasyAuthenticationHandlerFactory authentication = new EasyAuthenticationHandlerFactory((user, passwd) -> {
|
||||||
assertThat(user, is(USERNAME));
|
assertThat(user, is(USERNAME));
|
||||||
assertThat(passwd, is(PASSWORD));
|
assertThat(passwd, is(PASSWORD));
|
||||||
}));
|
});
|
||||||
|
server = new SMTPServer(listener, authentication) {
|
||||||
|
@Override
|
||||||
|
public SSLSocket createSSLSocket(Socket socket) throws IOException {
|
||||||
|
if (sslContext == null) {
|
||||||
|
return super.createSSLSocket(socket);
|
||||||
|
} else {
|
||||||
|
SSLSocketFactory factory = sslContext.getSocketFactory();
|
||||||
|
InetSocketAddress remoteAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
|
||||||
|
SSLSocket sslSocket = (SSLSocket) factory.createSocket(socket, remoteAddress.getHostString(), socket.getPort(), true);
|
||||||
|
sslSocket.setUseClientMode(false);
|
||||||
|
sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites());
|
||||||
|
return sslSocket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
server.setHostName(host);
|
server.setHostName(host);
|
||||||
server.setPort(0);
|
server.setPort(0);
|
||||||
|
if (sslContext != null) {
|
||||||
|
server.setEnableTLS(true);
|
||||||
|
server.setRequireTLS(true);
|
||||||
|
server.setHideTLS(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,8 +120,16 @@ public class EmailServer {
|
||||||
listeners.add(listener);
|
listeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearListeners() {
|
||||||
|
this.listeners.clear();
|
||||||
|
}
|
||||||
|
|
||||||
public static EmailServer localhost(final Logger logger) {
|
public static EmailServer localhost(final Logger logger) {
|
||||||
EmailServer server = new EmailServer("localhost", logger);
|
return localhost(logger, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EmailServer localhost(final Logger logger, @Nullable SSLContext sslContext) {
|
||||||
|
EmailServer server = new EmailServer("localhost", sslContext, logger);
|
||||||
server.start();
|
server.start();
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ import org.elasticsearch.test.transport.MockTransportService;
|
||||||
import org.elasticsearch.xpack.core.XPackClient;
|
import org.elasticsearch.xpack.core.XPackClient;
|
||||||
import org.elasticsearch.xpack.core.XPackSettings;
|
import org.elasticsearch.xpack.core.XPackSettings;
|
||||||
import org.elasticsearch.xpack.core.security.SecurityField;
|
import org.elasticsearch.xpack.core.security.SecurityField;
|
||||||
|
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||||
import org.elasticsearch.xpack.core.watcher.WatcherState;
|
import org.elasticsearch.xpack.core.watcher.WatcherState;
|
||||||
import org.elasticsearch.xpack.core.watcher.client.WatcherClient;
|
import org.elasticsearch.xpack.core.watcher.client.WatcherClient;
|
||||||
import org.elasticsearch.xpack.core.watcher.execution.ExecutionState;
|
import org.elasticsearch.xpack.core.watcher.execution.ExecutionState;
|
||||||
|
@ -96,6 +97,7 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
import static org.hamcrest.core.Is.is;
|
import static org.hamcrest.core.Is.is;
|
||||||
import static org.hamcrest.core.IsNot.not;
|
import static org.hamcrest.core.IsNot.not;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
@ClusterScope(scope = SUITE, numClientNodes = 0, transportClientRatio = 0, maxNumDataNodes = 3)
|
@ClusterScope(scope = SUITE, numClientNodes = 0, transportClientRatio = 0, maxNumDataNodes = 3)
|
||||||
public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase {
|
public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase {
|
||||||
|
@ -574,7 +576,8 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
|
||||||
public static class NoopEmailService extends EmailService {
|
public static class NoopEmailService extends EmailService {
|
||||||
|
|
||||||
public NoopEmailService() {
|
public NoopEmailService() {
|
||||||
super(Settings.EMPTY, null, new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
super(Settings.EMPTY, null, mock(SSLService.class),
|
||||||
|
new ClusterSettings(Settings.EMPTY, new HashSet<>(EmailService.getSettings())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue