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;
+        }
+    }
+}

Reply via email to