diff --git a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/notice/impl/EmailAlertNotifyHandlerImpl.java b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/notice/impl/EmailAlertNotifyHandlerImpl.java index f2d8f7eb02..a0e9fac809 100644 --- a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/notice/impl/EmailAlertNotifyHandlerImpl.java +++ b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/notice/impl/EmailAlertNotifyHandlerImpl.java @@ -98,6 +98,7 @@ public class EmailAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl Properties props = sender.getJavaMailProperties(); props.put("mail.smtp.ssl.enable", emailNoticeSenderConfig.isEmailSsl()); props.put("mail.smtp.starttls.enable", emailNoticeSenderConfig.isEmailStarttls()); + applySslCertVerify(props, emailNoticeSenderConfig.isEmailSslCertVerify()); fromUsername = emailNoticeSenderConfig.getEmailUsername(); useDatabase = true; } @@ -111,6 +112,7 @@ public class EmailAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl Properties props = sender.getJavaMailProperties(); props.put("mail.smtp.ssl.enable", sslEnable); props.put("mail.smtp.starttls.enable", starttlsEnable); + applySslCertVerify(props, true); } } catch (Exception e) { log.error("Type not found {}", e.getMessage()); @@ -133,6 +135,17 @@ public class EmailAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl } } + // the sender is a singleton, so both branches must set the props to avoid stale state + private void applySslCertVerify(Properties props, boolean verify) { + if (verify) { + props.remove("mail.smtp.ssl.trust"); + props.remove("mail.smtp.ssl.checkserveridentity"); + } else { + props.put("mail.smtp.ssl.trust", "*"); + props.put("mail.smtp.ssl.checkserveridentity", "false"); + } + } + @Override public byte type() { return 1; diff --git a/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/notice/impl/EmailAlertNotifyHandlerImplTest.java b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/notice/impl/EmailAlertNotifyHandlerImplTest.java index 901b27fae5..31fe45fdad 100644 --- a/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/notice/impl/EmailAlertNotifyHandlerImplTest.java +++ b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/notice/impl/EmailAlertNotifyHandlerImplTest.java @@ -17,6 +17,8 @@ package org.apache.hertzbeat.alert.notice.impl; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; @@ -124,6 +126,40 @@ class EmailAlertNotifyHandlerImplTest { verify(mailSender).send(any(MimeMessage.class)); } + @Test + public void testSkipSslCertVerifyTrustsAllHosts() throws Exception { + Properties props = stubMailConfig(false); + emailAlertNotifyHandler.send(receiver, template, groupAlert); + assertEquals("*", props.get("mail.smtp.ssl.trust")); + assertEquals("false", props.get("mail.smtp.ssl.checkserveridentity")); + } + + @Test + public void testEnableSslCertVerifyClearsStaleTrustProps() throws Exception { + Properties props = stubMailConfig(true); + props.put("mail.smtp.ssl.trust", "*"); + props.put("mail.smtp.ssl.checkserveridentity", "false"); + emailAlertNotifyHandler.send(receiver, template, groupAlert); + assertNull(props.get("mail.smtp.ssl.trust")); + assertNull(props.get("mail.smtp.ssl.checkserveridentity")); + } + + private Properties stubMailConfig(boolean sslCertVerify) { + MailServerConfig config = new MailServerConfig(); + config.setEmailHost("smtp.example.com"); + config.setEmailPort(465); + config.setEmailUsername("sender@example.com"); + config.setEmailPassword("password"); + config.setEnable(true); + config.setEmailSslCertVerify(sslCertVerify); + when(generalConfigDao.findByType(any())) + .thenReturn(GeneralConfig.builder().content(JsonUtil.toJson(config)).build()); + Properties props = new Properties(); + when(mailSender.getJavaMailProperties()).thenReturn(props); + when(mailSender.createMimeMessage()).thenReturn(mimeMessage); + return props; + } + @Test public void testNotifyAlertFailure() { when(mailSender.createMimeMessage()).thenThrow(new RuntimeException("Test Error")); diff --git a/hertzbeat-common-core/src/main/java/org/apache/hertzbeat/common/entity/dto/MailServerConfig.java b/hertzbeat-common-core/src/main/java/org/apache/hertzbeat/common/entity/dto/MailServerConfig.java index 3c99b34ab6..b51b3ea06d 100644 --- a/hertzbeat-common-core/src/main/java/org/apache/hertzbeat/common/entity/dto/MailServerConfig.java +++ b/hertzbeat-common-core/src/main/java/org/apache/hertzbeat/common/entity/dto/MailServerConfig.java @@ -56,5 +56,7 @@ public class MailServerConfig { private boolean emailStarttls = false; + private boolean emailSslCertVerify = true; + private boolean enable = true; } diff --git a/web-app/src/app/pojo/EmailNoticeSender.ts b/web-app/src/app/pojo/EmailNoticeSender.ts index 9d4ffea819..1a8a1c6788 100644 --- a/web-app/src/app/pojo/EmailNoticeSender.ts +++ b/web-app/src/app/pojo/EmailNoticeSender.ts @@ -25,6 +25,7 @@ export class EmailNoticeSender { emailPassword!: string; emailSsl: boolean = true; emailStarttls: boolean = false; + emailSslCertVerify: boolean = true; enable!: boolean; creator!: string; modifier!: string; diff --git a/web-app/src/app/routes/setting/settings/message-server/message-server.component.html b/web-app/src/app/routes/setting/settings/message-server/message-server.component.html index a804f51547..57290b5203 100644 --- a/web-app/src/app/routes/setting/settings/message-server/message-server.component.html +++ b/web-app/src/app/routes/setting/settings/message-server/message-server.component.html @@ -134,6 +134,14 @@ + + {{ + 'alert.notice.sender.mail.ssl-cert-verify' | i18n + }} + + + + {{ 'common.enable' | i18n }} diff --git a/web-app/src/assets/i18n/en-US.json b/web-app/src/assets/i18n/en-US.json index 32ac9d0b7f..0b5c837cc5 100644 --- a/web-app/src/assets/i18n/en-US.json +++ b/web-app/src/assets/i18n/en-US.json @@ -147,6 +147,7 @@ "alert.notice.sender.mail.port": "Email Port", "alert.notice.sender.mail.ssl": "Enable SSL", "alert.notice.sender.mail.starttls": "Enable STARTTLS", + "alert.notice.sender.mail.ssl-cert-verify": "Verify SSL Certificate", "alert.notice.sender.mail.username": "Email Account", "alert.notice.sender.sms.tencent.appId": "Tencent Sms AppId", "alert.notice.sender.sms.tencent.secretId": "Tencent Sms SecretId", diff --git a/web-app/src/assets/i18n/ja-JP.json b/web-app/src/assets/i18n/ja-JP.json index dcdcaeef5d..8df517eec8 100644 --- a/web-app/src/assets/i18n/ja-JP.json +++ b/web-app/src/assets/i18n/ja-JP.json @@ -146,6 +146,7 @@ "alert.notice.sender.mail.port": "メールポート", "alert.notice.sender.mail.ssl": "SSLを有効化", "alert.notice.sender.mail.starttls": "STARTTLSを有効化", + "alert.notice.sender.mail.ssl-cert-verify": "SSL証明書を検証", "alert.notice.sender.mail.username": "メールアカウント", "alert.notice.sender.sms.tencent.appId": "Tencent Sms AppId", "alert.notice.sender.sms.tencent.secretId": "Tencent Sms SecretId", diff --git a/web-app/src/assets/i18n/ko-KR.json b/web-app/src/assets/i18n/ko-KR.json index 0dd23716b5..1a77de3774 100644 --- a/web-app/src/assets/i18n/ko-KR.json +++ b/web-app/src/assets/i18n/ko-KR.json @@ -147,6 +147,7 @@ "alert.notice.sender.mail.port": "이메일 포트", "alert.notice.sender.mail.ssl": "SSL 활성화", "alert.notice.sender.mail.starttls": "STARTTLS 활성화", + "alert.notice.sender.mail.ssl-cert-verify": "SSL 인증서 검증", "alert.notice.sender.mail.username": "이메일 계정", "alert.notice.sender.sms.tencent.appId": "Tencent SMS AppId", "alert.notice.sender.sms.tencent.secretId": "Tencent SMS SecretId", diff --git a/web-app/src/assets/i18n/pt-BR.json b/web-app/src/assets/i18n/pt-BR.json index e8761d9a90..bf2a3e6e36 100644 --- a/web-app/src/assets/i18n/pt-BR.json +++ b/web-app/src/assets/i18n/pt-BR.json @@ -233,6 +233,7 @@ "alert.notice.sender.mail.port": "Porta do Email", "alert.notice.sender.mail.ssl": "Habilitar SSL", "alert.notice.sender.mail.starttls": "Habilitar STARTTLS", + "alert.notice.sender.mail.ssl-cert-verify": "Verificar Certificado SSL", "alert.notice.sender.mail.enable": "Habilitar Configuração de Email", "alert.notice.sender.sms.type": "Tipo de SMS", "alert.notice.sender.sms.type.tencent": "SMS Tencent", diff --git a/web-app/src/assets/i18n/zh-CN.json b/web-app/src/assets/i18n/zh-CN.json index 5282863db7..9c1059dbf0 100644 --- a/web-app/src/assets/i18n/zh-CN.json +++ b/web-app/src/assets/i18n/zh-CN.json @@ -147,6 +147,7 @@ "alert.notice.sender.mail.port": "邮箱端口", "alert.notice.sender.mail.ssl": "是否启用SSL", "alert.notice.sender.mail.starttls": "是否启用STARTTLS", + "alert.notice.sender.mail.ssl-cert-verify": "是否校验SSL证书", "alert.notice.sender.mail.username": "邮箱账号", "alert.notice.sender.sms.tencent.appId": "腾讯短信AppId", "alert.notice.sender.sms.tencent.secretId": "腾讯短信SecretId", diff --git a/web-app/src/assets/i18n/zh-TW.json b/web-app/src/assets/i18n/zh-TW.json index 239c8375b5..8e4b95974a 100644 --- a/web-app/src/assets/i18n/zh-TW.json +++ b/web-app/src/assets/i18n/zh-TW.json @@ -146,6 +146,7 @@ "alert.notice.sender.mail.port": "郵件端口", "alert.notice.sender.mail.ssl": "是否啟用SSL", "alert.notice.sender.mail.starttls": "是否啟用STARTTLS", + "alert.notice.sender.mail.ssl-cert-verify": "是否校驗SSL證書", "alert.notice.sender.mail.username": "郵件帳號", "alert.notice.sender.sms.tencent.appId": "騰訊短訊AppId", "alert.notice.sender.sms.tencent.secretId": "騰訊短訊SecretId",