From 89bb24e5904384b97916f4aab97d75ac2d4db94f Mon Sep 17 00:00:00 2001 From: actiontech-zihan Date: Thu, 17 Sep 2026 02:26:21 +0000 Subject: [PATCH] fix: allow public key retrieval for MySQL family datasources MySQL 8 defaults to caching_sha2_password. When the server side authentication cache misses, the driver has to fetch the server RSA public key to encrypt the password, but ODC builds the JDBC url with useSSL=false and without allowPublicKeyRetrieval, so Connector/J refuses the retrieval and the connection fails with "Public Key Retrieval is not allowed". Default allowPublicKeyRetrieval to true in the MySQL connect plugin so test connection, SQL console, data transfer and DLM all get it. Values supplied by the datasource still win, and TiDB / Doris inherit it. Also build the parameter map from a copy instead of mutating the caller's map: DataSourceInfoMapper passes Collections.emptyMap(), which made the previous in-place put throw UnsupportedOperationException, and a null map silently dropped the defaults. --- .../mysql/MySQLConnectionExtension.java | 12 ++- .../mysql/MySQLConnectionExtensionTest.java | 91 +++++++++++++++++++ 2 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 server/plugins/connect-plugin-mysql/src/test/java/com/oceanbase/odc/plugin/connect/mysql/MySQLConnectionExtensionTest.java diff --git a/server/plugins/connect-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/connect/mysql/MySQLConnectionExtension.java b/server/plugins/connect-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/connect/mysql/MySQLConnectionExtension.java index 7e295aa8d9..dfecbee178 100644 --- a/server/plugins/connect-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/connect/mysql/MySQLConnectionExtension.java +++ b/server/plugins/connect-plugin-mysql/src/main/java/com/oceanbase/odc/plugin/connect/mysql/MySQLConnectionExtension.java @@ -19,6 +19,7 @@ import java.sql.DriverManager; import java.sql.SQLException; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -94,10 +95,13 @@ public TestResult test(String jdbcUrl, Properties properties, int queryTimeout, @Override protected Map appendDefaultJdbcUrlParameters(Map jdbcUrlParams) { - if (Objects.nonNull(jdbcUrlParams) && !jdbcUrlParams.containsKey("tinyInt1isBit")) { - jdbcUrlParams.put("tinyInt1isBit", "false"); - } - return jdbcUrlParams; + Map parameters = + Objects.isNull(jdbcUrlParams) ? new HashMap<>() : new HashMap<>(jdbcUrlParams); + parameters.putIfAbsent("tinyInt1isBit", "false"); + // caching_sha2_password full authentication needs the server public key, which the driver + // refuses to retrieve over a non-SSL connection unless this is enabled + parameters.putIfAbsent("allowPublicKeyRetrieval", "true"); + return parameters; } } diff --git a/server/plugins/connect-plugin-mysql/src/test/java/com/oceanbase/odc/plugin/connect/mysql/MySQLConnectionExtensionTest.java b/server/plugins/connect-plugin-mysql/src/test/java/com/oceanbase/odc/plugin/connect/mysql/MySQLConnectionExtensionTest.java new file mode 100644 index 0000000000..eb477a2640 --- /dev/null +++ b/server/plugins/connect-plugin-mysql/src/test/java/com/oceanbase/odc/plugin/connect/mysql/MySQLConnectionExtensionTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * Licensed 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 com.oceanbase.odc.plugin.connect.mysql; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +import com.oceanbase.odc.plugin.connect.model.JdbcUrlProperty; + +/** + * {@link MySQLConnectionExtensionTest} + */ +public class MySQLConnectionExtensionTest { + + private static final String HOST = "127.0.0.1"; + private static final int PORT = 3306; + private static final String SCHEMA = "testdb"; + + private final MySQLConnectionExtension connectionExtension = new MySQLConnectionExtension(); + + private String generateJdbcUrl(Map jdbcParameters) { + return connectionExtension.generateJdbcUrl(new JdbcUrlProperty(HOST, PORT, SCHEMA, jdbcParameters)); + } + + @Test + public void generateJdbcUrl_noUserParameters_publicKeyRetrievalAllowed() { + String url = generateJdbcUrl(new HashMap<>()); + + Assert.assertTrue(url, url.contains("allowPublicKeyRetrieval=true")); + Assert.assertTrue(url, url.contains("tinyInt1isBit=false")); + } + + @Test + public void generateJdbcUrl_userDisabledPublicKeyRetrieval_userValueKept() { + Map jdbcParameters = new HashMap<>(); + jdbcParameters.put("allowPublicKeyRetrieval", "false"); + + String url = generateJdbcUrl(jdbcParameters); + + Assert.assertTrue(url, url.contains("allowPublicKeyRetrieval=false")); + Assert.assertFalse(url, url.contains("allowPublicKeyRetrieval=true")); + } + + @Test + public void generateJdbcUrl_nullParameters_publicKeyRetrievalAllowed() { + String url = generateJdbcUrl(null); + + Assert.assertTrue(url, url.contains("allowPublicKeyRetrieval=true")); + } + + @Test + public void generateJdbcUrl_immutableParameters_noExceptionThrown() { + String url = generateJdbcUrl(Collections.emptyMap()); + + Assert.assertTrue(url, url.contains("allowPublicKeyRetrieval=true")); + } + + @Test + public void generateJdbcUrl_callerParameters_notModified() { + Map jdbcParameters = new HashMap<>(); + + generateJdbcUrl(jdbcParameters); + + Assert.assertTrue(jdbcParameters.toString(), jdbcParameters.isEmpty()); + } + + @Test + public void generateJdbcUrl_mysql_withoutOceanBaseOnlyParameter() { + String url = generateJdbcUrl(new HashMap<>()); + + Assert.assertFalse(url, url.contains("enableFullLinkTrace")); + } +}