This is an automated email from the ASF dual-hosted git repository.

liuhongyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git


The following commit(s) were added to refs/heads/master by this push:
     new 42f0a74edf [fix] adding trusted domain verification (#3866)
42f0a74edf is described below

commit 42f0a74edf9282457c321eecb4563db642b06747
Author: Duansg <[email protected]>
AuthorDate: Thu Nov 27 20:38:00 2025 +0800

    [fix] adding trusted domain verification (#3866)
    
    Co-authored-by: aias00 <[email protected]>
---
 .../impl/HuaweiCloudExternAlertService.java        | 61 ++++++++++++++++++++++
 .../service/HuaweiCloudExternAlertServiceTest.java | 37 ++++++++++++-
 2 files changed, 97 insertions(+), 1 deletion(-)

diff --git 
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/HuaweiCloudExternAlertService.java
 
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/HuaweiCloudExternAlertService.java
index 2c538aeb48..335426f5db 100644
--- 
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/HuaweiCloudExternAlertService.java
+++ 
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/HuaweiCloudExternAlertService.java
@@ -18,6 +18,7 @@
 package org.apache.hertzbeat.alert.service.impl;
 
 import com.fasterxml.jackson.databind.JsonNode;
+import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.hertzbeat.alert.dto.HuaweiCloudExternAlert;
@@ -43,6 +44,7 @@ import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.text.MessageFormat;
 import java.time.Instant;
+import java.util.Arrays;
 import java.util.Base64;
 import java.util.HashMap;
 import java.util.Map;
@@ -70,6 +72,8 @@ public class HuaweiCloudExternAlertService implements 
ExternAlertService {
 
     private static final String CHARSET_UTF8 = StandardCharsets.UTF_8.name();
 
+    private static final String SUBSCRIBE_URL_PREFIX = 
"https://console.huaweicloud.com/smn/subscription/confirm";;
+
     private final AlarmCommonReduce alarmCommonReduce;
 
     public HuaweiCloudExternAlertService(AlarmCommonReduce alarmCommonReduce) {
@@ -197,6 +201,9 @@ public class HuaweiCloudExternAlertService implements 
ExternAlertService {
         if (StringUtils.isBlank(subscribeUrl)) {
             return;
         }
+        if (!subscribeUrl.startsWith(SUBSCRIBE_URL_PREFIX)) {
+            throw new SecurityException("Untrusted domain: " + subscribeUrl);
+        }
         try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
             HttpGet httpGet = new HttpGet(subscribeUrl);
             try (CloseableHttpResponse response = httpClient.execute(httpGet)) 
{
@@ -303,6 +310,13 @@ public class HuaweiCloudExternAlertService implements 
ExternAlertService {
      */
     private X509Certificate getCertificate(String signCertUrl) throws 
Exception {
         URL url = new URL(signCertUrl);
+        if (!"https".equalsIgnoreCase(url.getProtocol())) {
+            throw new SecurityException("Only HTTPS is allowed");
+        }
+        boolean trusted = Arrays.stream(Region.values()).anyMatch(ep -> 
ep.getEndpoint().equals(url.getHost()));
+        if (!trusted) {
+            throw new SecurityException("Untrusted domain: " + url.getHost());
+        }
         try (InputStream in = url.openStream()) {
             CertificateFactory cf = 
CertificateFactory.getInstance(CERTIFICATE_TYPE);
             return (X509Certificate) cf.generateCertificate(in);
@@ -340,4 +354,51 @@ public class HuaweiCloudExternAlertService implements 
ExternAlertService {
         return "huaweicloud-ces";
     }
 
+
+    /**
+     * doc: <a 
href="https://console.huaweicloud.com/apiexplorer/#/endpoint/SMN";>SMN API</a>
+     */
+    @Getter
+    private enum Region {
+
+        AE_AD_1("ae-ad-1", "smn.ae-ad-1.myhuaweicloud.com"),
+        AF_SOUTH_1("af-south-1", "smn.af-south-1.myhuaweicloud.com"),
+        AP_SOUTHEAST_1("ap-southeast-1", 
"smn.ap-southeast-1.myhuaweicloud.com"),
+        AP_SOUTHEAST_2("ap-southeast-2", 
"smn.ap-southeast-2.myhuaweicloud.com"),
+        AP_SOUTHEAST_3("ap-southeast-3", 
"smn.ap-southeast-3.myhuaweicloud.com"),
+        AP_SOUTHEAST_4("ap-southeast-4", 
"smn.ap-southeast-4.myhuaweicloud.com"),
+        CN_EAST_2("cn-east-2", "smn.cn-east-2.myhuaweicloud.com"),
+        CN_EAST_3("cn-east-3", "smn.cn-east-3.myhuaweicloud.com"),
+        CN_EAST_4("cn-east-4", "smn.cn-east-4.myhuaweicloud.com"),
+        CN_EAST_5("cn-east-5", "smn.cn-east-5.myhuaweicloud.com"),
+        CN_NORTH_1("cn-north-1", "smn.cn-north-1.myhuaweicloud.com"),
+        CN_NORTH_11("cn-north-11", "smn.cn-north-11.myhuaweicloud.com"),
+        CN_NORTH_12("cn-north-12", "smn.cn-north-12.myhuaweicloud.com"),
+        CN_NORTH_2("cn-north-2", "smn.cn-north-2.myhuaweicloud.cn"),
+        CN_NORTH_4("cn-north-4", "smn.cn-north-4.myhuaweicloud.com"),
+        CN_NORTH_9("cn-north-9", "smn.cn-north-9.myhuaweicloud.com"),
+        CN_SOUTH_1("cn-south-1", "smn.cn-south-1.myhuaweicloud.com"),
+        CN_SOUTH_2("cn-south-2", "smn.cn-south-2.myhuaweicloud.com"),
+        CN_SOUTH_4("cn-south-4", "smn.cn-south-4.myhuaweicloud.com"),
+        CN_SOUTHWEST_2("cn-southwest-2", 
"smn.cn-southwest-2.myhuaweicloud.com"),
+        CN_SOUTHWEST_3("cn-southwest-3", 
"smn.cn-southwest-3.myhuaweicloud.com"),
+        EU_WEST_0("eu-west-0", "smn.eu-west-0.myhuaweicloud.com"),
+        LA_NORTH_2("la-north-2", "smn.la-north-2.myhuaweicloud.com"),
+        LA_SOUTH_2("la-south-2", "smn.la-south-2.myhuaweicloud.com"),
+        MY_KUALALUMPUR_1("my-kualalumpur-1", 
"smn.my-kualalumpur-1.myhuaweicloud.com"),
+        NA_MEXICO_1("na-mexico-1", "smn.na-mexico-1.myhuaweicloud.com"),
+        RU_MOSCOW_1("ru-moscow-1", "smn.ru-moscow-1.myhuaweicloud.com"),
+        SA_BRAZIL_1("sa-brazil-1", "smn.sa-brazil-1.myhuaweicloud.com"),
+        TR_WEST_1("tr-west-1", "smn.tr-west-1.myhuaweicloud.com"),
+        EU_WEST_101("eu-west-101", "smn.eu-west-101.myhuaweicloud.eu");
+
+        private final String id;
+
+        private final String endpoint;
+
+        Region(String id, String endpoint) {
+            this.id = id;
+            this.endpoint = endpoint;
+        }
+    }
 }
\ No newline at end of file
diff --git 
a/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/HuaweiCloudExternAlertServiceTest.java
 
b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/HuaweiCloudExternAlertServiceTest.java
index b29b948251..3859303c7e 100644
--- 
a/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/HuaweiCloudExternAlertServiceTest.java
+++ 
b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/HuaweiCloudExternAlertServiceTest.java
@@ -146,7 +146,42 @@ public class HuaweiCloudExternAlertServiceTest {
         verify(alarmCommonReduce, 
never()).reduceAndSendAlarm(any(SingleAlert.class));
     }
 
+    @Test
+    void testSubscriptionUrlFail() {
+        HuaweiCloudExternAlert externAlert = new HuaweiCloudExternAlert();
+        
externAlert.setSubscribeUrl("https://console.huaweicloud.com/smn/subscription/confirm?token=477a784601d744e4ab9ab83986502d31c4b938";
+                + 
"0ec0b64392b134e517c3aa17eb7b3a12dc9f3b4ab495e61c4dee654b435d7223ea934345bf8ae8901cef912b1d&topic_urn=urn:smn:cn-north-4"
+                + 
":477a784601d744e4ab9ab83986502d31:CES_notification_group_bngJ2aMpX&region=cn-north-4");
+        
externAlert.setSignature("ottf37C/2RdDgqimRQMIBU6i7XjUfPPMU760jJn71wwP3825YPoIT22uw2A9399rkm9Jrt1qUEFrDLuA5yHFLd5n/XoM4FghIgyFn7VIfgpuVM31a+co78s"
+                + 
"YBiZ1egOCE/AwFm2oygRhfIceUj9Kw9vmc06el9TXY6RtE5tAEF6qEmICtTh45KwtCO/WRs3DY72dQi5hm0w7/tktS4WFZ1iP4LHt5eCwFvnH0u29Y96cJNI0fLUQxI5MkhgjK"
+                + 
"77JkFK7UT6ZYJZhzgSp/B7OQGStOQx+3Duvx4T4CzccZQM3sca81Z0B0GFGWeVXuEHyCPLsayY/Iz+5Tco51elT8w==");
+        
externAlert.setTopicUrn("urn:smn:cn-north-4:477a784601d744e4ab9ab83986502d31:CES_notification_group_bngJ2aMpX");
+        externAlert.setMessageId("242fac183d3a4936b5ead6c725a32ed0");
+        externAlert.setType("SubscriptionConfirmation");
+        externAlert.setMessage("You are invited to subscribe to topic: 
urn:smn:cn-north-4:477a784601d744e4ab9ab83986502d31:"
+                + "CES_notification_group_bngJ2aMpX. To confirm this 
subscription, please visit the subscribe_url included in this message. The 
subscribe_url is valid only within 48 hours.");
+        
externAlert.setSigningCertUrl("https://xxxx.myhuaweicloud.com/smn/SMN_cn-north-4_b98100ca131b4116ab8ee7ccedbaae99.pem";);
+        externAlert.setTimestamp("2025-06-07T15:07:14Z");
+        externAlertService.addExternAlert(JsonUtil.toJson(externAlert));
+        verify(alarmCommonReduce, 
never()).reduceAndSendAlarm(any(SingleAlert.class));
+    }
 
-
+    @Test
+    void testCertUrlFailed() {
+        HuaweiCloudExternAlert externAlert = new HuaweiCloudExternAlert();
+        
externAlert.setSignature("TImrLoeb0tV1JZJSPyA0rpC9mNqH3MmhwQ4tgpuHHa+JztfGVZFvkU//OthKKhzpDAoYiXOYG9DbzXCLb"
+                + 
"vaGePIRITakoynYyYr9zZIpdx9jXhQNlgF8np1+t0JxNeoIq0DYWgH52tsodwqOm+OnmkcHwCRo/1rFv85KrKAaX2gy3sNwX"
+                + 
"w1hKnAwAw0mJlxHHSf/N3+7j6GoxCNV7fN9K4CpJiLMGNvUa7zVmG0U9mPvt/7Lac155kPPQ9lYyeL7vVI0e4sfRbuQruz3E"
+                + 
"0ZP40TKx0afoeR0/Bx/IoZzRP1La7pKlbEISvkcM7TqW/IOGQTkhVsQ32RFRxZWO2snw==");
+        externAlert.setSubject("DCS Redis “dcs-h4tv” ");
+        
externAlert.setTopicUrn("urn:smn:cn-north-4:477a784601d744e4ab9ab83986502d31:CES_notification_group_bngJ2aMpX");
+        externAlert.setMessageId("d3672d737bb742cf8c2aa3f0fd72d4d1");
+        externAlert.setType("Notification");
+        externAlert.setMessage("{}");
+        
externAlert.setSigningCertUrl("https://xxx.myhuaweicloud.com/failedUrl";);
+        externAlert.setTimestamp("2025-06-07T15:12:09Z");
+        externAlertService.addExternAlert(JsonUtil.toJson(externAlert));
+        verify(alarmCommonReduce, 
never()).reduceAndSendAlarm(any(SingleAlert.class));
+    }
 
 }
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to