diff --git a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/ObjectStoreConfigServiceImpl.java b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/ObjectStoreConfigServiceImpl.java index 9682935d8ad..94a49824e1a 100644 --- a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/ObjectStoreConfigServiceImpl.java +++ b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/ObjectStoreConfigServiceImpl.java @@ -20,8 +20,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.obs.services.ObsClient; -import java.lang.reflect.Type; -import javax.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.apache.hertzbeat.common.constants.GeneralConfigTypeEnum; import org.apache.hertzbeat.manager.dao.GeneralConfigDao; @@ -35,6 +33,10 @@ import org.springframework.stereotype.Service; import org.springframework.util.Assert; +import javax.annotation.Resource; +import java.lang.reflect.Type; +import java.net.URL; + /** * File storage configuration service */ @@ -44,18 +46,16 @@ public class ObjectStoreConfigServiceImpl extends AbstractGeneralConfigServiceImpl> implements InitializingBean { + private static final String BEAN_NAME = "ObjectStoreService"; @Resource private DefaultListableBeanFactory beanFactory; - @Resource private ApplicationContext ctx; - private static final String BEAN_NAME = "ObjectStoreService"; - /** *

Constructor, passing in GeneralConfigDao, ObjectMapper and type.

* - * @param generalConfigDao configDao object + * @param generalConfigDao configDao object * @param objectMapper JSON tool object */ public ObjectStoreConfigServiceImpl(GeneralConfigDao generalConfigDao, ObjectMapper objectMapper) { @@ -100,6 +100,9 @@ private void initObs(ObjectStoreDTO config) { Assert.hasText(obsConfig.getEndpoint(), "cannot find obs endpoint"); Assert.hasText(obsConfig.getBucketName(), "cannot find obs bucket name"); + // Add domain name verification for Huawei Cloud OBS endpoint + validateObsEndpoint(obsConfig.getEndpoint()); + var obsClient = new ObsClient(obsConfig.getAccessKey(), obsConfig.getSecretKey(), obsConfig.getEndpoint()); beanFactory.destroySingleton(BEAN_NAME); @@ -108,6 +111,25 @@ private void initObs(ObjectStoreDTO config) { log.info("obs store service init success."); } + /** + * Verify Huawei Cloud OBS endpoint domain name + * Only myhuaweicloud.com domain name is allowed + * Refer: https://console-intl.huaweicloud.com/apiexplorer/#/endpoint + */ + public void validateObsEndpoint(String endpoint) { + try { + URL url = new URL(endpoint); + String host = url.getHost(); + + // Verify whether it is a Huawei Cloud domain name + if (!host.endsWith("myhuaweicloud.com")) { + throw new IllegalArgumentException("Invalid OBS endpoint domain. Only myhuaweicloud.com is allowed"); + } + } catch (Exception e) { + throw new IllegalArgumentException("Invalid OBS endpoint: " + e.getMessage()); + } + } + @Override public void afterPropertiesSet() throws Exception { // init file storage diff --git a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/ObjectStoreConfigServiceTest.java b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/ObjectStoreConfigServiceTest.java index 5371e981cb2..083c2181880 100644 --- a/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/ObjectStoreConfigServiceTest.java +++ b/hertzbeat-manager/src/test/java/org/apache/hertzbeat/manager/service/ObjectStoreConfigServiceTest.java @@ -17,10 +17,6 @@ package org.apache.hertzbeat.manager.service; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.hertzbeat.common.constants.GeneralConfigTypeEnum; import org.apache.hertzbeat.manager.pojo.dto.ObjectStoreConfigChangeEvent; @@ -37,6 +33,13 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.util.ReflectionTestUtils; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + /** * test case for {@link ObjectStoreConfigServiceImpl} */ @@ -84,7 +87,7 @@ void testHandlerObsConfig() { ObjectStoreDTO.ObsConfig obsConfig = new ObjectStoreDTO.ObsConfig(); obsConfig.setAccessKey("access-key"); obsConfig.setSecretKey("secret-key"); - obsConfig.setEndpoint("endpoint"); + obsConfig.setEndpoint("http://xxx.myhuaweicloud.com"); obsConfig.setBucketName("bucket-name"); config.setConfig(obsConfig); @@ -93,4 +96,39 @@ void testHandlerObsConfig() { verify(ctx).publishEvent(any(ObjectStoreConfigChangeEvent.class)); } + @Test + void testValidateObsEndpoint() { + // Test valid endpoint URL - should pass validation + assertDoesNotThrow(() -> + objectStoreConfigService.validateObsEndpoint("https://obs.myhuaweicloud.com")); + + // Test various invalid scenarios + // 1. Using http protocol (insecure) + assertDoesNotThrow(() -> + objectStoreConfigService.validateObsEndpoint("http://obs.myhuaweicloud.com")); + + // 2. Using invalid domain names + assertThrows(IllegalArgumentException.class, () -> + objectStoreConfigService.validateObsEndpoint("https://obs.someotherdomain.com")); + assertThrows(IllegalArgumentException.class, () -> + objectStoreConfigService.validateObsEndpoint("https://obs.myhuaweicloud.com.abc.com")); + + // 3. Using internal network addresses + assertThrows(IllegalArgumentException.class, () -> + objectStoreConfigService.validateObsEndpoint("https://127.0.0.1")); + assertThrows(IllegalArgumentException.class, () -> + objectStoreConfigService.validateObsEndpoint("https://192.168.1.1")); + assertThrows(IllegalArgumentException.class, () -> + objectStoreConfigService.validateObsEndpoint("https://10.0.0.1")); + + // 4. Test invalid URL format + assertThrows(IllegalArgumentException.class, () -> + objectStoreConfigService.validateObsEndpoint("not-a-url")); + + // 5. Test null and empty values + assertThrows(IllegalArgumentException.class, () -> + objectStoreConfigService.validateObsEndpoint(null)); + assertThrows(IllegalArgumentException.class, () -> + objectStoreConfigService.validateObsEndpoint("")); + } }