This is an automated email from the ASF dual-hosted git repository.
casionone pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/linkis.git
The following commit(s) were added to refs/heads/master by this push:
new 1da0c6790c #AI COMMIT# [SECURITY][DS] Block JDBC URL-option injection
via instance/database field (#5450)
1da0c6790c is described below
commit 1da0c6790c4784c2e3f467ba1ac4cfdd5035af50
Author: aiceflower <[email protected]>
AuthorDate: Fri Jun 26 16:59:52 2026 +0800
#AI COMMIT# [SECURITY][DS] Block JDBC URL-option injection via
instance/database field (#5450)
The DB2 SqlConnection classes interpolate the user-supplied instance
value directly into the JDBC URL via String.format("jdbc:db2://%s:%s/%s",
...).
A value containing URL option separators (e.g. "SAMPLE:traceLevel=1;")
becomes "jdbc:db2://host:port/SAMPLE:traceLevel=1;", letting the database
segment toggle DB2 driver options (traceLevel/traceFile/traceDirectory/
traceFileAppend) that bypass the Properties denylist. Same class of issue
affects SQL Server (';' separator), Oracle (service-name slot), and the
mysql:// family.
Adds four layers of defense:
1. SecurityUtils.checkDatabaseIsSafe(JdbcDriverType, database) rejects
URL-option separators per driver family:
DB2 -> : ; ? # &
SQLSERVER -> ; ? # &
ORACLE -> ? # &
PG/MySQL/CK/DM/etc -> ? # & /
2. Expand JDBC_DB2_BLOCKED_PARAMS with traceLevel/traceFile/
traceDirectory/traceFileAppend so Properties-based injection of the
same logging options is also blocked (defense in depth).
3. Backfill value_regex for the `instance` field of every JDBC data
source in linkis_dml.sql. RegExpParameterValidateStrategy skips
validation when value_regex is NULL, so the previous schema offered
no first-line defense. New regex: ^[A-Za-z0-9_.-]+$
4. Same regex backfilled via UPDATE in the 1.9.0 upgrade script for
existing installs.
5. 6 new unit tests covering the DB2 database segment, the SQL Server
and MySQL variants, benign-database sanity, and the expanded DB2
denylist. All 24 tests in SecurityUtilsTest pass.
Co-authored-by: Claude Opus 4.7 <[email protected]>
---
.../apache/linkis/common/utils/SecurityUtils.java | 66 ++++++++-
.../linkis/common/utils/SecurityUtilsTest.java | 154 +++++++++++++++++++++
linkis-dist/package/db/linkis_dml.sql | 26 ++--
.../db/upgrade/1.9.0_schema/mysql/linkis_dml.sql | 8 ++
4 files changed, 239 insertions(+), 15 deletions(-)
diff --git
a/linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/SecurityUtils.java
b/linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/SecurityUtils.java
index e8848aad28..3dca6c1f30 100644
---
a/linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/SecurityUtils.java
+++
b/linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/SecurityUtils.java
@@ -118,7 +118,10 @@ public abstract class SecurityUtils {
private static final CommonVars<String> JDBC_DB2_BLOCKED_PARAMS =
CommonVars$.MODULE$.apply(
"linkis.jdbc.db2.blocked.params",
- "clientRerouteServerListJNDIName,enableSeamlessFailover,JNDIName");
+ // traceLevel / traceFile / traceDirectory / traceFileAppend let the
driver write trace
+ // output to arbitrary paths; blocked alongside the JNDI-related
options.
+ "clientRerouteServerListJNDIName,enableSeamlessFailover,JNDIName,"
+ + "traceLevel,traceFile,traceDirectory,traceFileAppend");
private static final CommonVars<String> JDBC_ORACLE_BLOCKED_PARAMS =
CommonVars$.MODULE$.apply(
@@ -503,7 +506,9 @@ public abstract class SecurityUtils {
// 2. Host sanity check: reject hosts that smuggle extra URL segments
// (e.g. "host:port/evil?socketFactory=...").
checkHostIsSafe(host);
- // 3. Param denylist check (also handles URL-encoded bypass).
+ // 3. Database sanity check (reject URL option separators in the database
segment).
+ checkDatabaseIsSafe(driverType, database);
+ // 4. Param denylist check (also handles URL-encoded bypass).
checkDriverParams(driverType, extraParams);
}
@@ -621,6 +626,63 @@ public abstract class SecurityUtils {
}
}
+ /**
+ * Reject database names that contain URL option separators. The
metadata-query / datasource
+ * manager SqlConnection classes interpolate the user-supplied
database/instance segment directly
+ * into the JDBC URL via String.format, so a value containing a separator
character would be
+ * parsed as an extra URL option. Block the characters that any supported
driver family treats as
+ * a delimiter after the database segment.
+ */
+ private static void checkDatabaseIsSafe(JdbcDriverType driverType, String
database) {
+ if (StringUtils.isBlank(database)) {
+ return;
+ }
+ String trimmed = database.trim();
+ String forbidden;
+ switch (driverType) {
+ case DB2:
+ // DB2 URL option syntax is "jdbc:db2://h:p/db:opt1=v1;opt2=v2;".
+ forbidden = ":;?#&";
+ break;
+ case ORACLE:
+ // Oracle thin URL is "jdbc:oracle:thin:@//h:p/service" — ':' and '/'
are structural, but
+ // '?' / '&' would only appear if the caller is abusing the
service-name slot to inject
+ // query-style params. '#' is the fragment anchor and a known
smuggling trick.
+ forbidden = "?#&";
+ break;
+ case SQLSERVER:
+ // SQL Server URL is "jdbc:sqlserver://h:p;databaseName=db;prop=v;" —
';' is the property
+ // separator, so block it along with the usual query/fragment anchors.
+ forbidden = ";?#&";
+ break;
+ case POSTGRESQL:
+ case GREENPLUM:
+ case KINGBASE:
+ case CLICKHOUSE:
+ case DM:
+ case MYSQL:
+ case STARROCKS:
+ default:
+ // For the mysql:// family the database is followed by '?' for query
params; for the others
+ // a '/' selects a path segment. Block all of the URL-meaningful
characters.
+ forbidden = "?#&/";
+ break;
+ }
+ for (int i = 0; i < forbidden.length(); i++) {
+ char c = forbidden.charAt(i);
+ if (trimmed.indexOf(c) >= 0) {
+ throw new LinkisSecurityException(
+ 35000,
+ "Database name contains forbidden character '"
+ + c
+ + "' for driver "
+ + driverType
+ + ": "
+ + trimmed);
+ }
+ }
+ }
+
private static CommonVars<String> getDriverBlockedConfig(JdbcDriverType
driverType) {
switch (driverType) {
case POSTGRESQL:
diff --git
a/linkis-commons/linkis-common/src/test/java/org/apache/linkis/common/utils/SecurityUtilsTest.java
b/linkis-commons/linkis-common/src/test/java/org/apache/linkis/common/utils/SecurityUtilsTest.java
index 860bc8b154..06cc6d8fb9 100644
---
a/linkis-commons/linkis-common/src/test/java/org/apache/linkis/common/utils/SecurityUtilsTest.java
+++
b/linkis-commons/linkis-common/src/test/java/org/apache/linkis/common/utils/SecurityUtilsTest.java
@@ -533,4 +533,158 @@ public class SecurityUtilsTest {
Assertions.assertEquals("linkis", props.getProperty("applicationName"));
Assertions.assertEquals("u", props.getProperty("user"));
}
+
+ // ----------------------- Database name sanitization tests
-----------------------
+
+ @Test
+ public void testGenericCheck_Db2DatabaseInjection() {
+ // DB2 URL option syntax uses ':' and ';' as delimiters, so a database
name containing them
+ // would be parsed as extra options. checkDatabaseIsSafe must reject them.
+ Map<String, Object> params = new HashMap<>();
+ params.put("k1", "v1");
+ Assertions.assertThrows(
+ LinkisSecurityException.class,
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.DB2, "localhost", 50000, "u", "p",
"SAMPLE:traceLevel=1;", params));
+ // Same with a traceFile payload.
+ Assertions.assertThrows(
+ LinkisSecurityException.class,
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.DB2,
+ "localhost",
+ 50000,
+ "u",
+ "p",
+ "SAMPLE:traceFile=/tmp/evil;",
+ params));
+ // Single-character URL separators must also be rejected individually.
+ Assertions.assertThrows(
+ LinkisSecurityException.class,
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.DB2, "localhost", 50000, "u", "p", "db;",
params));
+ Assertions.assertThrows(
+ LinkisSecurityException.class,
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.DB2, "localhost", 50000, "u", "p", "db:opt=v",
params));
+ Assertions.assertThrows(
+ LinkisSecurityException.class,
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.DB2, "localhost", 50000, "u", "p", "db?q=1",
params));
+ Assertions.assertThrows(
+ LinkisSecurityException.class,
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.DB2, "localhost", 50000, "u", "p", "db#frag",
params));
+ Assertions.assertThrows(
+ LinkisSecurityException.class,
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.DB2, "localhost", 50000, "u", "p", "db&k=v",
params));
+ }
+
+ @Test
+ public void testGenericCheck_SqlserverDatabaseInjection() {
+ // SQL Server property separator is ';', reject it in the database name.
+ Map<String, Object> params = new HashMap<>();
+ params.put("k1", "v1");
+ Assertions.assertThrows(
+ LinkisSecurityException.class,
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.SQLSERVER,
+ "localhost",
+ 1433,
+ "u",
+ "p",
+ "db;trustServerCertificate=true",
+ params));
+ Assertions.assertThrows(
+ LinkisSecurityException.class,
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.SQLSERVER, "localhost", 1433, "u", "p",
"db?q=1", params));
+ }
+
+ @Test
+ public void testGenericCheck_MysqlAndPostgresDatabaseInjection() {
+ // The mysql:// family uses '?' / '&' for query params and '#' as the
fragment anchor.
+ Map<String, Object> params = new HashMap<>();
+ params.put("k1", "v1");
+ Assertions.assertThrows(
+ LinkisSecurityException.class,
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.MYSQL,
+ "localhost",
+ 3306,
+ "u",
+ "p",
+ "db?autoDeserialize=true",
+ params));
+ Assertions.assertThrows(
+ LinkisSecurityException.class,
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.POSTGRESQL,
+ "localhost",
+ 5432,
+ "u",
+ "p",
+ "db?socketFactory=evil",
+ params));
+ // '/' is blocked for the mysql:// family because it selects a different
path segment.
+ Assertions.assertThrows(
+ LinkisSecurityException.class,
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.POSTGRESQL, "localhost", 5432, "u", "p",
"db/other", params));
+ }
+
+ @Test
+ public void testGenericCheck_BenignDatabaseNamesPass() {
+ // Sanity: legitimate database names for each driver family must still
pass.
+ Map<String, Object> params = new HashMap<>();
+ Assertions.assertDoesNotThrow(
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.DB2, "localhost", 50000, "u", "p", "SAMPLE",
params));
+ Assertions.assertDoesNotThrow(
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.ORACLE, "localhost", 1521, "u", "p", "ORCL",
params));
+ Assertions.assertDoesNotThrow(
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.POSTGRESQL, "localhost", 5432, "u", "p",
"postgres", params));
+ Assertions.assertDoesNotThrow(
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.MYSQL, "localhost", 3306, "u", "p", "db_name",
params));
+ Assertions.assertDoesNotThrow(
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.SQLSERVER, "localhost", 1433, "u", "p",
"master", params));
+ // Blank database names are allowed (some drivers use a default).
+ Assertions.assertDoesNotThrow(
+ () ->
+ SecurityUtils.checkJdbcConnParams(
+ JdbcDriverType.DB2, "localhost", 50000, "u", "p", " ",
params));
+ }
+
+ @Test
+ public void testGenericCheck_Db2TraceParamsInDenylist() {
+ // The DB2 denylist must reject these even when they arrive via Properties
rather than the URL.
+ assertDriverRejectsParam(JdbcDriverType.DB2, "traceLevel", "1");
+ assertDriverRejectsParam(JdbcDriverType.DB2, "traceFile", "/tmp/evil.log");
+ assertDriverRejectsParam(JdbcDriverType.DB2, "traceDirectory", "/tmp");
+ assertDriverRejectsParam(JdbcDriverType.DB2, "traceFileAppend", "true");
+ // JNDI-related params must remain in the denylist.
+ assertDriverRejectsParam(
+ JdbcDriverType.DB2, "clientRerouteServerListJNDIName",
"ldap://evil/exp");
+ }
}
diff --git a/linkis-dist/package/db/linkis_dml.sql
b/linkis-dist/package/db/linkis_dml.sql
index 6dd4ab0c86..eb4cb68037 100644
--- a/linkis-dist/package/db/linkis_dml.sql
+++ b/linkis-dist/package/db/linkis_dml.sql
@@ -679,7 +679,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'sid', 'SID', 'SID', NULL, 'TEXT', NULL, 0,
'SID', 'SID', NULL, NULL, NULL, NULL, now(), now()),
(@data_source_type_id, 'serviceName', 'service_name', 'service_name',
NULL, 'TEXT', NULL, 0, 'service_name', 'service_name', NULL, NULL, NULL, NULL,
now(), now()),
(@data_source_type_id, 'server', 'server', 'server', NULL, 'TEXT',
NULL, 0, 'server', 'server', NULL, NULL, NULL, NULL, now(), now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 0, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 0, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'dm';
INSERT INTO `linkis_ps_dm_datasource_type_key`
@@ -691,7 +691,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format):
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL,
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'password', '密码(Password)', 'Password', NULL,
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL, now(),
now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'kingbase';
INSERT INTO `linkis_ps_dm_datasource_type_key`
@@ -703,7 +703,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format):
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL,
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'password', '密码(Password)', 'Password', NULL,
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL, now(),
now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
-- https://jdbc.postgresql.org/documentation/use/
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'postgresql';
@@ -716,7 +716,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format):
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL,
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'password', '密码(Password)', 'Password', NULL,
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL, now(),
now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
--
https://learn.microsoft.com/zh-cn/sql/connect/jdbc/building-the-connection-url?redirectedfrom=MSDN&view=sql-server-ver16
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'sqlserver';
@@ -729,7 +729,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format):
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL,
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'password', '密码(Password)', 'Password', NULL,
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL, now(),
now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
--
https://www.ibm.com/docs/en/db2/11.5?topic=cdsudidsdjs-url-format-data-server-driver-jdbc-sqlj-type-4-connectivity
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'db2';
@@ -742,7 +742,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format):
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL,
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'password', '密码(Password)', 'Password', NULL,
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL, now(),
now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
--
https://greenplum.docs.pivotal.io/6-1/datadirect/datadirect_jdbc.html#topic_ylk_pbx_2bb
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'greenplum';
@@ -755,7 +755,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format):
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL,
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'password', '密码(Password)', 'Password', NULL,
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL, now(),
now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'doris';
INSERT INTO `linkis_ps_dm_datasource_type_key`
@@ -767,7 +767,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format):
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL,
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'password', '密码(Password)', 'Password', NULL,
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL, now(),
now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
-- https://github.com/ClickHouse/clickhouse-jdbc/tree/master/clickhouse-jdbc
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'clickhouse';
@@ -780,7 +780,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format):
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL,
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'password', '密码(Password)', 'Password', NULL,
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL, now(),
now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'hive';
@@ -800,7 +800,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format):
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL,
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'password', '密码(Password)', 'Password', NULL,
'PASSWORD', NULL, 0, '密码(Password)', 'Password', '', NULL, NULL, NULL, now(),
now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'starrocks';
INSERT INTO `linkis_ps_dm_datasource_type_key`
@@ -812,7 +812,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format):
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL,
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'password', '密码(Password)', 'Password', NULL,
'PASSWORD', NULL, 0, '密码(Password)', 'Password', '', NULL, NULL, NULL, now(),
now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'gaussdb';
INSERT INTO `linkis_ps_dm_datasource_type_key`
@@ -824,7 +824,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format):
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL,
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'password', '密码(Password)', 'Password', NULL,
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL, now(),
now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'oceanbase';
INSERT INTO `linkis_ps_dm_datasource_type_key`
@@ -836,7 +836,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address',
NULL, 'TEXT', NULL
(@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format):
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL,
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL,
NULL, now(), now()),
(@data_source_type_id, 'password', '密码(Password)', 'Password', NULL,
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL, now(),
now()),
- (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL, now(),
now());
+ (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL,
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL,
NULL, NULL, now(), now());
select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where
`name` = 'doris';
UPDATE linkis_ps_dm_datasource_type_key SET `require` = 0 WHERE `key`
="password" and `data_source_type_id` = @data_source_type_id;
diff --git a/linkis-dist/package/db/upgrade/1.9.0_schema/mysql/linkis_dml.sql
b/linkis-dist/package/db/upgrade/1.9.0_schema/mysql/linkis_dml.sql
index e5625ca195..2c95812990 100644
--- a/linkis-dist/package/db/upgrade/1.9.0_schema/mysql/linkis_dml.sql
+++ b/linkis-dist/package/db/upgrade/1.9.0_schema/mysql/linkis_dml.sql
@@ -285,3 +285,11 @@ UPDATE `linkis_ps_configuration_config_key` SET
default_value = '60' WHERE `key`
-- 更新错误码正则表达式
UPDATE linkis_ps_error_code SET error_regex = "The ecm of labels" WHERE
error_code = "01001";
+-- Backfill value_regex for JDBC data-source `instance` fields.
+-- Restrict the instance field to identifier characters so
RegExpParameterValidateStrategy
+-- rejects values containing URL option separators before they reach the
connection layer.
+UPDATE `linkis_ps_dm_datasource_type_key`
+SET `value_regex` = '^[A-Za-z0-9_.-]+$'
+WHERE `key` = 'instance'
+ AND `value_regex` IS NULL;
+
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]