You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by li...@apache.org on 2026/10/06 10:41:29 UTC
(kylin) 09/20: KYLIN-6111 harden JDBC source validation
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 <li...@apache.org>
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 {