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

liyang-kylin pushed a commit to branch kylin5
in repository https://gitbox.apache.org/repos/asf/kylin.git

commit 771c13b52cc58ff8234fa84a0c66e36577a77593
Author: Li Yang <[email protected]>
AuthorDate: Fri Oct 2 22:04:07 2026 +0800

    KYLIN-6111 harden JDBC source validation
---
 .../apache/kylin/rest/service/ProjectService.java  | 12 ++-
 .../CommonJdbcSourceConnectionValidator.java       | 67 +---------------
 .../CommonJdbcSourceConnectionValidatorTest.java   | 16 ++++
 .../org/apache/kylin/common/KylinConfigBase.java   | 64 ++++++++++++++-
 .../framework/SourceConnectorFactory.java          |  2 +-
 .../sdk/datasource/framework/utils/JdbcUtils.java  | 13 ++-
 .../DefaultJdbcSourceConnectionValidator.java      | 93 ++++++++++++++++++++++
 .../security/JdbcSourceValidationSettings.java     |  7 +-
 .../datasource/framework/utils/JdbcUtilsTest.java  | 35 +++++++-
 9 files changed, 227 insertions(+), 82 deletions(-)

diff --git 
a/src/common-service/src/main/java/org/apache/kylin/rest/service/ProjectService.java
 
b/src/common-service/src/main/java/org/apache/kylin/rest/service/ProjectService.java
index 4f96e6ad7d..ec5ad37e15 100644
--- 
a/src/common-service/src/main/java/org/apache/kylin/rest/service/ProjectService.java
+++ 
b/src/common-service/src/main/java/org/apache/kylin/rest/service/ProjectService.java
@@ -450,10 +450,14 @@ public class ProjectService extends BasicService {
                 throw new KylinException(INVALID_PARAMETER,
                         
MsgPicker.getMsg().getIllegalNegative(KYLIN_JOB_MAX_CONCURRENT_JOBS));
         }
-        if 
(overrideKylinProps.containsKey(KYLIN_SOURCE_JDBC_CONNECTION_URL_KEY)) {
-            String url = 
overrideKylinProps.get(KYLIN_SOURCE_JDBC_CONNECTION_URL_KEY);
-            if (KylinConfig.getInstanceFromEnv().isSourceJdbcWhiteListEnabled()
-                    && !JdbcUtils.validateUrlByWhiteList(url)) {
+        if 
(overrideKylinProps.containsKey(KYLIN_SOURCE_JDBC_CONNECTION_URL_KEY)
+                || 
overrideKylinProps.containsKey(KYLIN_SOURCE_JDBC_DRIVER_KEY)) {
+            String url = 
overrideKylinProps.getOrDefault(KYLIN_SOURCE_JDBC_CONNECTION_URL_KEY,
+                    projectInstance.getConfig().getJdbcConnectionUrl());
+            String driver = 
overrideKylinProps.getOrDefault(KYLIN_SOURCE_JDBC_DRIVER_KEY,
+                    projectInstance.getConfig().getJdbcDriver());
+            if (StringUtils.isNotBlank(url) && 
KylinConfig.getInstanceFromEnv().isSourceJdbcWhiteListEnabled()
+                    && !JdbcUtils.validateUrlByWhiteList(url, driver)) {
                 throw new KylinException(INVALID_JDBC_SOURCE_CONFIG, 
MsgPicker.getMsg().getJdbcConnectionInfoWrong());
             }
         }
diff --git 
a/src/common-service/src/main/java/org/apache/kylin/rest/source/CommonJdbcSourceConnectionValidator.java
 
b/src/common-service/src/main/java/org/apache/kylin/rest/source/CommonJdbcSourceConnectionValidator.java
index 72c3cb122b..1b6463bbf0 100644
--- 
a/src/common-service/src/main/java/org/apache/kylin/rest/source/CommonJdbcSourceConnectionValidator.java
+++ 
b/src/common-service/src/main/java/org/apache/kylin/rest/source/CommonJdbcSourceConnectionValidator.java
@@ -18,70 +18,7 @@
 
 package org.apache.kylin.rest.source;
 
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import 
org.apache.kylin.sdk.datasource.security.DefaultJdbcSourceConnectionValidator;
 
-import org.apache.commons.lang3.StringUtils;
-import 
org.apache.kylin.sdk.datasource.security.AbstractJdbcSourceConnectionValidator;
-import org.springframework.web.util.UriComponents;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import lombok.NoArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-
-@NoArgsConstructor
-@Slf4j
-public class CommonJdbcSourceConnectionValidator extends 
AbstractJdbcSourceConnectionValidator {
-
-    private static final String JDBC_COLON = "jdbc:";
-
-    private boolean parsed = false;
-    private String scheme;
-    private String host;
-    private int port;
-    private String path;
-    private Map<String, List<String>> queryParams;
-
-    @Override
-    public boolean isValid() {
-        if (!parsed) {
-            try {
-                parseUrl();
-            } catch (Exception e) {
-                log.error("Error on parseUrl", e);
-                return false;
-            }
-        }
-        // Only query param keys need to be validated currently
-        return validateQueryParamKeys();
-    }
-
-    private boolean validateQueryParamKeys() {
-        Set<String> validUrlParamKeys = settings.getValidUrlParamKeys();
-        Set<String> userInputKeys = queryParams.keySet();
-        return validUrlParamKeys.containsAll(userInputKeys);
-    }
-
-    private void parseUrl() {
-        if (parsed) {
-            return;
-        }
-        if (StringUtils.isBlank(url)) {
-            throw new IllegalStateException("url cannot be empty");
-        }
-        if (!url.startsWith(JDBC_COLON)) {
-            throw new IllegalStateException("url must start with " + 
JDBC_COLON);
-        }
-
-        String noPrefixUrl = url.substring(JDBC_COLON.length());
-        UriComponents uri = 
UriComponentsBuilder.fromUriString(noPrefixUrl).build();
-        scheme = uri.getScheme();
-        host = uri.getHost();
-        port = uri.getPort();
-        path = uri.getPath();
-        queryParams = uri.getQueryParams();
-
-        parsed = true;
-    }
+public class CommonJdbcSourceConnectionValidator extends 
DefaultJdbcSourceConnectionValidator {
 }
diff --git 
a/src/common-service/src/test/java/org/apache/kylin/rest/source/CommonJdbcSourceConnectionValidatorTest.java
 
b/src/common-service/src/test/java/org/apache/kylin/rest/source/CommonJdbcSourceConnectionValidatorTest.java
index 2cc2942af5..56bab6d79f 100644
--- 
a/src/common-service/src/test/java/org/apache/kylin/rest/source/CommonJdbcSourceConnectionValidatorTest.java
+++ 
b/src/common-service/src/test/java/org/apache/kylin/rest/source/CommonJdbcSourceConnectionValidatorTest.java
@@ -31,6 +31,7 @@ public class CommonJdbcSourceConnectionValidatorTest {
     public void testValidate() {
         JdbcSourceValidationSettings settings = 
JdbcSourceValidationSettings.builder()
                 .validUrlParamKeys(Sets.newHashSet("q1", "q2", "q3"))
+                .validSemicolonParamKeys(Sets.newHashSet("DB_CLOSE_DELAY", 
"MODE"))
                 .build();
 
         {
@@ -43,6 +44,21 @@ public class CommonJdbcSourceConnectionValidatorTest {
             
validator.settings(settings).url("jdbc:mysql://localhost:123/data_db?q1=v1&q2=v2&q4=v4");
             assertFalse(validator.isValid());
         }
+        {
+            CommonJdbcSourceConnectionValidator validator = new 
CommonJdbcSourceConnectionValidator();
+            
validator.settings(settings).url("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1;MODE=MYSQL");
+            assertTrue(validator.isValid());
+        }
+        {
+            CommonJdbcSourceConnectionValidator validator = new 
CommonJdbcSourceConnectionValidator();
+            validator.settings(settings).url("jdbc:h2:mem:db;INIT=RUNSCRIPT 
FROM 'evil.sql'");
+            assertFalse(validator.isValid());
+        }
+        {
+            CommonJdbcSourceConnectionValidator validator = new 
CommonJdbcSourceConnectionValidator();
+            
validator.settings(settings).url("jdbc:mysql://localhost:123/data_db;allowLoadLocalInfile=true");
+            assertFalse(validator.isValid());
+        }
     }
 
     @Test
diff --git 
a/src/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java 
b/src/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
index 060aa42c5f..8097e6fc27 100644
--- a/src/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
+++ b/src/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
@@ -4530,15 +4530,16 @@ public abstract class KylinConfigBase implements 
Serializable {
     }
 
     public boolean isSourceJdbcWhiteListEnabled() {
-        return 
Boolean.parseBoolean(getOptional("kylin.source.jdbc.white-list.enabled", 
FALSE));
+        return 
Boolean.parseBoolean(getOptional("kylin.source.jdbc.white-list.enabled", TRUE));
     }
 
     public Set<String> getSourceJdbcWhiteListSchemes() {
-        String config = 
StringUtils.deleteWhitespace(getOptional("kylin.source.jdbc.white-list.schemes",
 ""));
+        String config = 
StringUtils.deleteWhitespace(getOptional("kylin.source.jdbc.white-list.schemes",
+                "h2,mysql,postgresql,sqlserver,snowflake"));
         if (StringUtils.isBlank(config)) {
             return Collections.emptySet();
         }
-        return Sets.newHashSet(config.split(","));
+        return Arrays.stream(config.split(",")).map(value -> 
value.toLowerCase(Locale.ROOT)).collect(Collectors.toSet());
     }
 
     public String getSourceJdbcWhiteListValidatorClassByScheme(String scheme) {
@@ -4547,7 +4548,7 @@ public abstract class KylinConfigBase implements 
Serializable {
             return null;
         }
         return getOptional(String.format(Locale.ROOT, 
"kylin.source.jdbc.white-list.%s.validator-class", scheme),
-                
"org.apache.kylin.rest.source.CommonJdbcSourceConnectionValidator");
+                
"org.apache.kylin.sdk.datasource.security.DefaultJdbcSourceConnectionValidator");
     }
 
     public Set<String> getSourceJdbcWhiteListUrlParamKeysByScheme(String 
scheme) {
@@ -4563,6 +4564,61 @@ public abstract class KylinConfigBase implements 
Serializable {
         return Sets.newHashSet(config.split(","));
     }
 
+    public Set<String> getSourceJdbcWhiteListDriversByScheme(String scheme) {
+        Set<String> whiteListSchemes = getSourceJdbcWhiteListSchemes();
+        if (!whiteListSchemes.contains(scheme)) {
+            return Collections.emptySet();
+        }
+        String config = 
StringUtils.deleteWhitespace(getOptional(String.format(Locale.ROOT,
+                "kylin.source.jdbc.white-list.%s.drivers", scheme), 
getDefaultSourceJdbcDrivers(scheme)));
+        if (StringUtils.isBlank(config)) {
+            return Collections.emptySet();
+        }
+        return Sets.newHashSet(config.split(","));
+    }
+
+    public Set<String> getSourceJdbcWhiteListSemicolonParamKeysByScheme(String 
scheme) {
+        Set<String> whiteListSchemes = getSourceJdbcWhiteListSchemes();
+        if (!whiteListSchemes.contains(scheme)) {
+            return Collections.emptySet();
+        }
+        String defaultValue;
+        switch (scheme) {
+        case "h2":
+            defaultValue = 
"DB_CLOSE_DELAY,MODE,DATABASE_TO_UPPER,DEFAULT_LOCK_TIMEOUT,SCHEMA";
+            break;
+        case "sqlserver":
+            defaultValue = 
"databaseName,encrypt,trustServerCertificate,applicationName,loginTimeout,socketTimeout";
+            break;
+        default:
+            defaultValue = "";
+            break;
+        }
+        String config = 
StringUtils.deleteWhitespace(getOptional(String.format(Locale.ROOT,
+                "kylin.source.jdbc.white-list.%s.semicolon-param-keys", 
scheme), defaultValue));
+        if (StringUtils.isBlank(config)) {
+            return Collections.emptySet();
+        }
+        return Sets.newHashSet(config.split(","));
+    }
+
+    private String getDefaultSourceJdbcDrivers(String scheme) {
+        switch (scheme) {
+        case "h2":
+            return "org.h2.Driver";
+        case "mysql":
+            return "com.mysql.jdbc.Driver,com.mysql.cj.jdbc.Driver";
+        case "postgresql":
+            return "org.postgresql.Driver";
+        case "sqlserver":
+            return "com.microsoft.sqlserver.jdbc.SQLServerDriver";
+        case "snowflake":
+            return "net.snowflake.client.jdbc.SnowflakeDriver";
+        default:
+            return "";
+        }
+    }
+
     public boolean isForcedToPushDown() {
         return Boolean.parseBoolean(getOptional("kylin.query.pushdown-force", 
FALSE));
     }
diff --git 
a/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/framework/SourceConnectorFactory.java
 
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/framework/SourceConnectorFactory.java
index 9be07b6913..48c08fd330 100644
--- 
a/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/framework/SourceConnectorFactory.java
+++ 
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/framework/SourceConnectorFactory.java
@@ -43,7 +43,7 @@ public class SourceConnectorFactory {
         String adaptorClazz = config.getJdbcAdaptorClass();
 
         if (KylinConfig.getInstanceFromEnv().isSourceJdbcWhiteListEnabled()
-                && !JdbcUtils.validateUrlByWhiteList(jdbcUrl)) {
+                && !JdbcUtils.validateUrlByWhiteList(jdbcUrl, jdbcDriver)) {
             throw new KylinException(INVALID_JDBC_SOURCE_CONFIG, 
MsgPicker.getMsg().getJdbcConnectionInfoWrong());
         }
 
diff --git 
a/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/framework/utils/JdbcUtils.java
 
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/framework/utils/JdbcUtils.java
index 28f616a2b1..68e8a8eb7a 100644
--- 
a/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/framework/utils/JdbcUtils.java
+++ 
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/framework/utils/JdbcUtils.java
@@ -19,6 +19,7 @@
 package org.apache.kylin.sdk.datasource.framework.utils;
 
 import java.sql.Connection;
+import java.util.Locale;
 import java.util.Properties;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -47,7 +48,8 @@ public class JdbcUtils {
         connProp.put("username", username);
         connProp.put("password", password);
 
-        if (KylinConfig.getInstanceFromEnv().isSourceJdbcWhiteListEnabled() && 
!validateUrlByWhiteList(url)) {
+        if (KylinConfig.getInstanceFromEnv().isSourceJdbcWhiteListEnabled()
+                && !validateUrlByWhiteList(url, driver)) {
             log.warn("jdbc url white list check failed");
             return false;
         }
@@ -61,7 +63,7 @@ public class JdbcUtils {
         }
     }
 
-    public static boolean validateUrlByWhiteList(String url) {
+    public static boolean validateUrlByWhiteList(String url, String driver) {
         try {
             KylinConfig config = KylinConfig.getInstanceFromEnv();
             String scheme = null;
@@ -70,12 +72,17 @@ public class JdbcUtils {
             if (m.find()) {
                 scheme = m.group();
             }
+            scheme = scheme == null ? null : scheme.toLowerCase(Locale.ROOT);
             if (StringUtils.isBlank(scheme) || 
!config.getSourceJdbcWhiteListSchemes().contains(scheme)) {
                 return false;
             }
+            if 
(!config.getSourceJdbcWhiteListDriversByScheme(scheme).contains(driver)) {
+                return false;
+            }
 
             JdbcSourceValidationSettings settings = 
JdbcSourceValidationSettings.builder()
-                    
.validUrlParamKeys(config.getSourceJdbcWhiteListUrlParamKeysByScheme(scheme)).build();
+                    
.validUrlParamKeys(config.getSourceJdbcWhiteListUrlParamKeysByScheme(scheme))
+                    
.validSemicolonParamKeys(config.getSourceJdbcWhiteListSemicolonParamKeysByScheme(scheme)).build();
 
             JdbcSourceConnectionValidator validator = 
(JdbcSourceConnectionValidator) ClassUtil
                     
.newInstance(config.getSourceJdbcWhiteListValidatorClassByScheme(scheme));
diff --git 
a/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/DefaultJdbcSourceConnectionValidator.java
 
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/DefaultJdbcSourceConnectionValidator.java
new file mode 100644
index 0000000000..ca0f1819db
--- /dev/null
+++ 
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/DefaultJdbcSourceConnectionValidator.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.kylin.sdk.datasource.security;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+
+public class DefaultJdbcSourceConnectionValidator extends 
AbstractJdbcSourceConnectionValidator {
+
+    private static final String JDBC_PREFIX = "jdbc:";
+
+    @Override
+    public boolean isValid() {
+        if (StringUtils.isBlank(url) || !url.startsWith(JDBC_PREFIX)) {
+            return false;
+        }
+
+        try {
+            String schemeSpecificUrl = url.substring(JDBC_PREFIX.length());
+            int schemeEnd = schemeSpecificUrl.indexOf(':');
+            if (schemeEnd <= 0 || 
StringUtils.isBlank(schemeSpecificUrl.substring(0, schemeEnd))) {
+                return false;
+            }
+
+            int queryIndex = url.indexOf('?');
+            String urlWithoutQuery = queryIndex < 0 ? url : url.substring(0, 
queryIndex);
+            String query = queryIndex < 0 ? "" : url.substring(queryIndex + 1);
+            if (queryIndex >= 0 && StringUtils.isBlank(query)) {
+                return false;
+            }
+            if (query.contains(";") || url.indexOf('#') >= 0) {
+                return false;
+            }
+
+            Set<String> queryKeys = parseKeys(query, '&');
+            Set<String> semicolonKeys = parseSemicolonKeys(urlWithoutQuery);
+            return settings.getValidUrlParamKeys().containsAll(queryKeys)
+                    && 
settings.getValidSemicolonParamKeys().containsAll(semicolonKeys);
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+    }
+
+    private Set<String> parseSemicolonKeys(String urlWithoutQuery) {
+        int semicolonIndex = urlWithoutQuery.indexOf(';');
+        if (semicolonIndex < 0) {
+            return Collections.emptySet();
+        }
+        String semicolonContent = urlWithoutQuery.substring(semicolonIndex + 
1);
+        if (StringUtils.isBlank(semicolonContent)) {
+            throw new IllegalArgumentException("empty semicolon parameters");
+        }
+        return parseKeys(semicolonContent, ';');
+    }
+
+    private Set<String> parseKeys(String content, char separator) {
+        if (StringUtils.isBlank(content)) {
+            return Collections.emptySet();
+        }
+
+        Set<String> keys = new LinkedHashSet<>();
+        for (String segment : content.split(String.valueOf(separator), -1)) {
+            if (StringUtils.isBlank(segment)) {
+                throw new IllegalArgumentException("empty parameter");
+            }
+            int equalsIndex = segment.indexOf('=');
+            String key = equalsIndex < 0 ? segment : segment.substring(0, 
equalsIndex);
+            key = key.trim();
+            if (StringUtils.isBlank(key) || !keys.add(key)) {
+                throw new IllegalArgumentException("invalid parameter");
+            }
+        }
+        return keys;
+    }
+}
diff --git 
a/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/JdbcSourceValidationSettings.java
 
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/JdbcSourceValidationSettings.java
index da2065ae0c..3eaad3a6d5 100644
--- 
a/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/JdbcSourceValidationSettings.java
+++ 
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/JdbcSourceValidationSettings.java
@@ -18,6 +18,7 @@
 
 package org.apache.kylin.sdk.datasource.security;
 
+import java.util.Collections;
 import java.util.Set;
 
 import lombok.AllArgsConstructor;
@@ -29,5 +30,9 @@ import lombok.Getter;
 @AllArgsConstructor
 public final class JdbcSourceValidationSettings {
 
-    private Set<String> validUrlParamKeys;
+    @Builder.Default
+    private Set<String> validUrlParamKeys = Collections.emptySet();
+
+    @Builder.Default
+    private Set<String> validSemicolonParamKeys = Collections.emptySet();
 }
diff --git 
a/src/datasource-sdk/src/test/java/org/apache/kylin/sdk/datasource/framework/utils/JdbcUtilsTest.java
 
b/src/datasource-sdk/src/test/java/org/apache/kylin/sdk/datasource/framework/utils/JdbcUtilsTest.java
index a53d5297c1..989d775a10 100644
--- 
a/src/datasource-sdk/src/test/java/org/apache/kylin/sdk/datasource/framework/utils/JdbcUtilsTest.java
+++ 
b/src/datasource-sdk/src/test/java/org/apache/kylin/sdk/datasource/framework/utils/JdbcUtilsTest.java
@@ -21,6 +21,7 @@ package org.apache.kylin.sdk.datasource.framework.utils;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import org.apache.kylin.common.KylinConfig;
 import org.apache.kylin.common.util.NLocalFileMetadataTestCase;
 import 
org.apache.kylin.sdk.datasource.security.AbstractJdbcSourceConnectionValidator;
 import org.junit.After;
@@ -48,12 +49,38 @@ public class JdbcUtilsTest extends 
NLocalFileMetadataTestCase {
                 
"org.apache.kylin.sdk.datasource.framework.utils.JdbcUtilsTest$MockJdbcSourceConnectionValidator");
 
         // valid cases
-        
assertTrue(JdbcUtils.validateUrlByWhiteList("jdbc:mysql://localhost:3306/db"));
-        
assertTrue(JdbcUtils.validateUrlByWhiteList("jdbc:postgresql://localhost:5433/db"));
+        
assertTrue(JdbcUtils.validateUrlByWhiteList("jdbc:mysql://localhost:3306/db", 
"com.mysql.cj.jdbc.Driver"));
+        
assertTrue(JdbcUtils.validateUrlByWhiteList("jdbc:postgresql://localhost:5433/db",
 "org.postgresql.Driver"));
 
         // invalid cases
-        
assertFalse(JdbcUtils.validateUrlByWhiteList("xxx://localhost:3306/db"));
-        
assertFalse(JdbcUtils.validateUrlByWhiteList("jdbc:mongodb://localhost:1234/db"));
+        
assertFalse(JdbcUtils.validateUrlByWhiteList("xxx://localhost:3306/db", 
"com.mysql.cj.jdbc.Driver"));
+        
assertFalse(JdbcUtils.validateUrlByWhiteList("jdbc:mongodb://localhost:1234/db",
 "org.mongodb.Driver"));
+    }
+
+    @Test
+    public void testValidateUrlByWhiteList_driverCheck() {
+        
overwriteSystemProp("kylin.source.jdbc.white-list.mysql.validator-class",
+                
"org.apache.kylin.sdk.datasource.framework.utils.JdbcUtilsTest$MockJdbcSourceConnectionValidator");
+        
assertTrue(JdbcUtils.validateUrlByWhiteList("jdbc:mysql://localhost:3306/db", 
"com.mysql.jdbc.Driver"));
+        
assertFalse(JdbcUtils.validateUrlByWhiteList("jdbc:mysql://localhost:3306/db", 
"org.h2.Driver"));
+        
assertFalse(JdbcUtils.validateUrlByWhiteList("jdbc:mysql://localhost:3306/db", 
"com.mysql.jdbc.driver"));
+    }
+
+    @Test
+    public void testValidateUrlByWhiteList_enabledByDefault() {
+        
assertTrue(KylinConfig.getInstanceFromEnv().isSourceJdbcWhiteListEnabled());
+    }
+
+    @Test
+    public void testValidateUrlByWhiteList_semicolonSettings() {
+        
assertTrue(JdbcUtils.validateUrlByWhiteList("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1;MODE=MYSQL",
 "org.h2.Driver"));
+        
assertTrue(JdbcUtils.validateUrlByWhiteList("jdbc:sqlserver://localhost;databaseName=kylin",
+                "com.microsoft.sqlserver.jdbc.SQLServerDriver"));
+        
assertFalse(JdbcUtils.validateUrlByWhiteList("jdbc:h2:mem:db;INIT=RUNSCRIPT 
FROM 'evil.sql'",
+                "org.h2.Driver"));
+        assertFalse(JdbcUtils.validateUrlByWhiteList("jdbc:h2:mem:db;", 
"org.h2.Driver"));
+        assertFalse(JdbcUtils.validateUrlByWhiteList(
+                "jdbc:mysql://localhost:3306/db;allowLoadLocalInfile=true", 
"com.mysql.cj.jdbc.Driver"));
     }
 
     public static class MockJdbcSourceConnectionValidator extends 
AbstractJdbcSourceConnectionValidator {

Reply via email to