This is an automated email from the ASF dual-hosted git repository.
yhcast0 pushed a commit to branch kylin5
in repository https://gitbox.apache.org/repos/asf/kylin.git
The following commit(s) were added to refs/heads/kylin5 by this push:
new 000e328bb2 KYLIN-5994 Fix JDBC source config remote code execution
(#2252)
000e328bb2 is described below
commit 000e328bb200b2b20c631b3d808860ac865768ca
Author: Yinghao Lin <[email protected]>
AuthorDate: Thu Feb 20 19:42:10 2025 +0800
KYLIN-5994 Fix JDBC source config remote code execution (#2252)
---
src/common-service/pom.xml | 4 +
.../apache/kylin/rest/service/ProjectService.java | 9 ++-
.../CommonJdbcSourceConnectionValidator.java | 87 +++++++++++++++++++++
.../CommonJdbcSourceConnectionValidatorTest.java | 65 ++++++++++++++++
.../org/apache/kylin/common/KylinConfigBase.java | 34 +++++++++
.../org/apache/kylin/common/util/JdbcUtils.java | 48 ------------
.../framework/SourceConnectorFactory.java | 10 +++
.../sdk/datasource/framework/utils/JdbcUtils.java | 89 ++++++++++++++++++++++
.../AbstractJdbcSourceConnectionValidator.java | 37 +++++++++
.../security/JdbcSourceConnectionValidator.java | 28 +++++++
.../security/JdbcSourceValidationSettings.java | 33 ++++++++
.../datasource/framework/utils/JdbcUtilsTest.java | 65 ++++++++++++++++
12 files changed, 460 insertions(+), 49 deletions(-)
diff --git a/src/common-service/pom.xml b/src/common-service/pom.xml
index 7e2906984f..90a65cf005 100644
--- a/src/common-service/pom.xml
+++ b/src/common-service/pom.xml
@@ -39,6 +39,10 @@
<groupId>org.apache.kylin</groupId>
<artifactId>kylin-tool</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.kylin</groupId>
+ <artifactId>kylin-datasource-sdk</artifactId>
+ </dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
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 17e2455965..2885c7fa5f 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
@@ -80,7 +80,6 @@ import
org.apache.kylin.common.persistence.transaction.UnitOfWork;
import org.apache.kylin.common.scheduler.EventBusFactory;
import org.apache.kylin.common.scheduler.SourceUsageUpdateNotifier;
import org.apache.kylin.common.util.EncryptUtil;
-import org.apache.kylin.common.util.JdbcUtils;
import org.apache.kylin.common.util.JsonUtil;
import org.apache.kylin.common.util.Pair;
import org.apache.kylin.common.util.SetThreadName;
@@ -135,6 +134,7 @@ import org.apache.kylin.rest.security.AclPermissionEnum;
import org.apache.kylin.rest.security.KerberosLoginManager;
import org.apache.kylin.rest.service.task.QueryHistoryMetaUpdateScheduler;
import org.apache.kylin.rest.util.AclEvaluate;
+import org.apache.kylin.sdk.datasource.framework.utils.JdbcUtils;
import org.apache.kylin.streaming.manager.StreamingJobManager;
import org.apache.kylin.tool.garbage.MetadataCleaner;
import org.slf4j.Logger;
@@ -446,6 +446,13 @@ 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)) {
+ throw new KylinException(INVALID_JDBC_SOURCE_CONFIG,
MsgPicker.getMsg().getJdbcConnectionInfoWrong());
+ }
+ }
encryptJdbcPassInOverrideKylinProps(overrideKylinProps);
projectManager.updateProject(project, copyForWrite ->
copyForWrite.getOverrideKylinProps()
.putAll(KylinConfig.trimKVFromMap(overrideKylinProps)));
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
new file mode 100644
index 0000000000..72c3cb122b
--- /dev/null
+++
b/src/common-service/src/main/java/org/apache/kylin/rest/source/CommonJdbcSourceConnectionValidator.java
@@ -0,0 +1,87 @@
+/*
+ * 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.rest.source;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+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;
+ }
+}
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
new file mode 100644
index 0000000000..2cc2942af5
--- /dev/null
+++
b/src/common-service/src/test/java/org/apache/kylin/rest/source/CommonJdbcSourceConnectionValidatorTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.rest.source;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.celeborn.shaded.com.google.common.collect.Sets;
+import org.apache.kylin.sdk.datasource.security.JdbcSourceValidationSettings;
+import org.junit.Test;
+
+public class CommonJdbcSourceConnectionValidatorTest {
+
+ @Test
+ public void testValidate() {
+ JdbcSourceValidationSettings settings =
JdbcSourceValidationSettings.builder()
+ .validUrlParamKeys(Sets.newHashSet("q1", "q2", "q3"))
+ .build();
+
+ {
+ CommonJdbcSourceConnectionValidator validator = new
CommonJdbcSourceConnectionValidator();
+
validator.settings(settings).url("jdbc:mysql://localhost:123/data_db?q1=v1&q2=v2&q3=v3");
+ assertTrue(validator.isValid());
+ }
+ {
+ CommonJdbcSourceConnectionValidator validator = new
CommonJdbcSourceConnectionValidator();
+
validator.settings(settings).url("jdbc:mysql://localhost:123/data_db?q1=v1&q2=v2&q4=v4");
+ assertFalse(validator.isValid());
+ }
+ }
+
+ @Test
+ public void testValidateFailed() {
+ JdbcSourceValidationSettings settings =
JdbcSourceValidationSettings.builder()
+ .validUrlParamKeys(Sets.newHashSet("q1", "q2", "q3"))
+ .build();
+
+ {
+ CommonJdbcSourceConnectionValidator validator = new
CommonJdbcSourceConnectionValidator();
+ validator.settings(settings).url("");
+ assertFalse(validator.isValid());
+ }
+ {
+ CommonJdbcSourceConnectionValidator validator = new
CommonJdbcSourceConnectionValidator();
+ validator.settings(settings).url("mysql://localhost:123/data_db");
+ assertFalse(validator.isValid());
+ }
+ }
+}
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 88e75107ee..601fc7fb14 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
@@ -4466,4 +4466,38 @@ public abstract class KylinConfigBase implements
Serializable {
return
TimeUtil.timeStringAs(getOptional("kylin.query.v3.delta-log-cache-expire-threshold",
"43200s"),
TimeUnit.SECONDS);
}
+
+ public boolean isSourceJdbcWhiteListEnabled() {
+ return
Boolean.parseBoolean(getOptional("kylin.source.jdbc.white-list.enabled",
FALSE));
+ }
+
+ public Set<String> getSourceJdbcWhiteListSchemes() {
+ String config =
StringUtils.deleteWhitespace(getOptional("kylin.source.jdbc.white-list.schemes",
""));
+ if (StringUtils.isBlank(config)) {
+ return Collections.emptySet();
+ }
+ return Sets.newHashSet(config.split(","));
+ }
+
+ public String getSourceJdbcWhiteListValidatorClassByScheme(String scheme) {
+ Set<String> whiteListSchemes = getSourceJdbcWhiteListSchemes();
+ if (!whiteListSchemes.contains(scheme)) {
+ return null;
+ }
+ return getOptional(String.format(Locale.ROOT,
"kylin.source.jdbc.white-list.%s.validator-class", scheme),
+
"org.apache.kylin.rest.source.CommonJdbcSourceConnectionValidator");
+ }
+
+ public Set<String> getSourceJdbcWhiteListUrlParamKeysByScheme(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.url-param-keys", scheme),
""));
+ if (StringUtils.isBlank(config)) {
+ return Collections.emptySet();
+ }
+ return Sets.newHashSet(config.split(","));
+ }
}
diff --git
a/src/core-common/src/main/java/org/apache/kylin/common/util/JdbcUtils.java
b/src/core-common/src/main/java/org/apache/kylin/common/util/JdbcUtils.java
deleted file mode 100644
index bba675dd17..0000000000
--- a/src/core-common/src/main/java/org/apache/kylin/common/util/JdbcUtils.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.common.util;
-
-import java.sql.Connection;
-import java.util.Properties;
-
-import org.apache.commons.dbcp2.BasicDataSourceFactory;
-
-import lombok.SneakyThrows;
-import lombok.val;
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-
-public class JdbcUtils {
- @SneakyThrows
- public static boolean checkConnectionParameter(String driver, String url,
String username, String password) {
- Properties connProp = new Properties();
- connProp.put("driverClassName", driver);
- connProp.put("url", url);
- connProp.put("username", username);
- connProp.put("password", password);
- try (val dataSource =
BasicDataSourceFactory.createDataSource(connProp);
- Connection conn = dataSource.getConnection()) {
- return true;
- } catch (Exception e) {
- log.debug("jdbc connect check failed", e);
- return 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 364fd5e70a..9be07b6913 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
@@ -17,14 +17,19 @@
*/
package org.apache.kylin.sdk.datasource.framework;
+import static
org.apache.kylin.common.exception.ServerErrorCode.INVALID_JDBC_SOURCE_CONFIG;
+
import java.util.HashMap;
import java.util.Map;
import org.apache.kylin.common.KylinConfig;
import org.apache.kylin.common.KylinConfigExt;
+import org.apache.kylin.common.exception.KylinException;
+import org.apache.kylin.common.msg.MsgPicker;
import org.apache.kylin.sdk.datasource.adaptor.AdaptorConfig;
import org.apache.kylin.sdk.datasource.adaptor.DefaultAdaptor;
import org.apache.kylin.sdk.datasource.adaptor.MysqlAdaptor;
+import org.apache.kylin.sdk.datasource.framework.utils.JdbcUtils;
public class SourceConnectorFactory {
private SourceConnectorFactory() {
@@ -37,6 +42,11 @@ public class SourceConnectorFactory {
String jdbcPass = config.getJdbcPass();
String adaptorClazz = config.getJdbcAdaptorClass();
+ if (KylinConfig.getInstanceFromEnv().isSourceJdbcWhiteListEnabled()
+ && !JdbcUtils.validateUrlByWhiteList(jdbcUrl)) {
+ throw new KylinException(INVALID_JDBC_SOURCE_CONFIG,
MsgPicker.getMsg().getJdbcConnectionInfoWrong());
+ }
+
Map<String, String> options = new HashMap<>();
if (config instanceof KylinConfigExt) {
options = ((KylinConfigExt) config).getExtendedOverrides();
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
new file mode 100644
index 0000000000..28f616a2b1
--- /dev/null
+++
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/framework/utils/JdbcUtils.java
@@ -0,0 +1,89 @@
+/*
+ * 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.framework.utils;
+
+import java.sql.Connection;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.dbcp2.BasicDataSourceFactory;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.util.ClassUtil;
+import org.apache.kylin.sdk.datasource.security.JdbcSourceConnectionValidator;
+import org.apache.kylin.sdk.datasource.security.JdbcSourceValidationSettings;
+
+import lombok.SneakyThrows;
+import lombok.val;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class JdbcUtils {
+
+ public static final Pattern JDBC_SCHEMA_PATTERN =
Pattern.compile("(?<=jdbc:)[\\w\\-]+(?=:)");
+
+ @SneakyThrows
+ public static boolean checkConnectionParameter(String driver, String url,
String username, String password) {
+ Properties connProp = new Properties();
+ connProp.put("driverClassName", driver);
+ connProp.put("url", url);
+ connProp.put("username", username);
+ connProp.put("password", password);
+
+ if (KylinConfig.getInstanceFromEnv().isSourceJdbcWhiteListEnabled() &&
!validateUrlByWhiteList(url)) {
+ log.warn("jdbc url white list check failed");
+ return false;
+ }
+
+ try (val dataSource =
BasicDataSourceFactory.createDataSource(connProp);
+ Connection conn = dataSource.getConnection()) {
+ return true;
+ } catch (Exception e) {
+ log.warn("jdbc connect check failed", e);
+ return false;
+ }
+ }
+
+ public static boolean validateUrlByWhiteList(String url) {
+ try {
+ KylinConfig config = KylinConfig.getInstanceFromEnv();
+ String scheme = null;
+
+ Matcher m = JDBC_SCHEMA_PATTERN.matcher(url);
+ if (m.find()) {
+ scheme = m.group();
+ }
+ if (StringUtils.isBlank(scheme) ||
!config.getSourceJdbcWhiteListSchemes().contains(scheme)) {
+ return false;
+ }
+
+ JdbcSourceValidationSettings settings =
JdbcSourceValidationSettings.builder()
+
.validUrlParamKeys(config.getSourceJdbcWhiteListUrlParamKeysByScheme(scheme)).build();
+
+ JdbcSourceConnectionValidator validator =
(JdbcSourceConnectionValidator) ClassUtil
+
.newInstance(config.getSourceJdbcWhiteListValidatorClassByScheme(scheme));
+
+ return validator.settings(settings).url(url).isValid();
+ } catch (Exception e) {
+ log.error("Error on validate url", e);
+ return false;
+ }
+ }
+}
diff --git
a/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/AbstractJdbcSourceConnectionValidator.java
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/AbstractJdbcSourceConnectionValidator.java
new file mode 100644
index 0000000000..e76872c222
--- /dev/null
+++
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/AbstractJdbcSourceConnectionValidator.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+public abstract class AbstractJdbcSourceConnectionValidator implements
JdbcSourceConnectionValidator {
+
+ protected JdbcSourceValidationSettings settings;
+ protected String url;
+
+ @Override
+ public JdbcSourceConnectionValidator settings(JdbcSourceValidationSettings
settings) {
+ this.settings = settings;
+ return this;
+ }
+
+ @Override
+ public JdbcSourceConnectionValidator url(String url) {
+ this.url = url;
+ return this;
+ }
+}
diff --git
a/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/JdbcSourceConnectionValidator.java
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/JdbcSourceConnectionValidator.java
new file mode 100644
index 0000000000..9880c4097a
--- /dev/null
+++
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/JdbcSourceConnectionValidator.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+public interface JdbcSourceConnectionValidator {
+
+ JdbcSourceConnectionValidator settings(JdbcSourceValidationSettings
settings);
+
+ JdbcSourceConnectionValidator url(String url);
+
+ boolean isValid();
+}
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
new file mode 100644
index 0000000000..da2065ae0c
--- /dev/null
+++
b/src/datasource-sdk/src/main/java/org/apache/kylin/sdk/datasource/security/JdbcSourceValidationSettings.java
@@ -0,0 +1,33 @@
+/*
+ * 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.Set;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+@AllArgsConstructor
+public final class JdbcSourceValidationSettings {
+
+ private Set<String> validUrlParamKeys;
+}
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
new file mode 100644
index 0000000000..a53d5297c1
--- /dev/null
+++
b/src/datasource-sdk/src/test/java/org/apache/kylin/sdk/datasource/framework/utils/JdbcUtilsTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.framework.utils;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.kylin.common.util.NLocalFileMetadataTestCase;
+import
org.apache.kylin.sdk.datasource.security.AbstractJdbcSourceConnectionValidator;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JdbcUtilsTest extends NLocalFileMetadataTestCase {
+
+ @Before
+ public void setUp() throws Exception {
+ createTestMetadata();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ cleanupTestMetadata();
+ }
+
+ @Test
+ public void testValidateUrlByWhiteList_schemeCheck() {
+ overwriteSystemProp("kylin.source.jdbc.white-list.schemes", "mysql,
postgresql");
+
overwriteSystemProp("kylin.source.jdbc.white-list.mysql.validator-class",
+
"org.apache.kylin.sdk.datasource.framework.utils.JdbcUtilsTest$MockJdbcSourceConnectionValidator");
+
overwriteSystemProp("kylin.source.jdbc.white-list.postgresql.validator-class",
+
"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"));
+
+ // invalid cases
+
assertFalse(JdbcUtils.validateUrlByWhiteList("xxx://localhost:3306/db"));
+
assertFalse(JdbcUtils.validateUrlByWhiteList("jdbc:mongodb://localhost:1234/db"));
+ }
+
+ public static class MockJdbcSourceConnectionValidator extends
AbstractJdbcSourceConnectionValidator {
+ @Override
+ public boolean isValid() {
+ return true;
+ }
+ }
+}