From b5bde333b2407820cb5200b741ca7d3f97a8ec32 Mon Sep 17 00:00:00 2001 From: likeelli Date: Tue, 16 Jun 2026 11:04:27 +0800 Subject: [PATCH 1/3] fix: upgrade Java to 1.8 and okhttp from 3.12.13 to 4.12.0 to fix CVEs - Bump maven-compiler-plugin source/target from 1.7 to 1.8 - Bump okhttp and logging-interceptor from 3.12.13 to 4.12.0 - Add jaxb-api 2.3.0 (required by okhttp 4.x on Java 8) - Update RequestBody.create() call order to (body, mediaType) per okhttp 4.x API - Remove deprecated single-arg setSSLSocketFactory() in HttpConnection (removed in okhttp 4.x) - In AbstractClient.trySetSSLSocketFactory(), fall back to JVM default X509TrustManager when only SSLSocketFactory is set, preserving backward compatibility for existing callers CVE fixed: CVE-2021-0341 (CVSS 7.5 High): TLS hostname verification bypass in okhttp < 4.9.1 CVE-2023-3635 (CVSS 5.3 Medium): GzipSource resource leak in okhttp < 4.10.0 --- pom.xml | 13 +++++++--- .../common/AbstractClient.java | 25 ++++++++++++++++--- .../common/http/HttpConnection.java | 11 +++----- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/pom.xml b/pom.xml index d7924adb9d..4147bdcb86 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ com.squareup.okhttp3 okhttp - 3.12.13 + 4.12.0 com.google.code.gson @@ -27,13 +27,18 @@ com.squareup.okhttp3 logging-interceptor - 3.12.13 + 4.12.0 org.apache.commons commons-configuration2 2.12.0 + + javax.xml.bind + jaxb-api + 2.3.0 + junit junit @@ -63,8 +68,8 @@ maven-compiler-plugin 2.3.2 - 1.7 - 1.7 + 1.8 + 1.8 UTF-8 diff --git a/src/main/java/com/tencentcloudapi/common/AbstractClient.java b/src/main/java/com/tencentcloudapi/common/AbstractClient.java index 6efabaceb0..6531e70ee9 100644 --- a/src/main/java/com/tencentcloudapi/common/AbstractClient.java +++ b/src/main/java/com/tencentcloudapi/common/AbstractClient.java @@ -32,6 +32,8 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -43,6 +45,7 @@ import java.net.Proxy; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.security.KeyStore; import java.security.SecureRandom; import java.sql.Date; import java.text.SimpleDateFormat; @@ -420,11 +423,25 @@ private void trySetSSLSocketFactory(HttpConnection conn) { SSLSocketFactory sslSocketFactory = this.profile.getHttpProfile().getSslSocketFactory(); X509TrustManager trustManager = this.profile.getHttpProfile().getX509TrustManager(); if (sslSocketFactory != null) { - if (trustManager != null) { - this.httpConnection.setSSLSocketFactory(sslSocketFactory, trustManager); - } else { - this.httpConnection.setSSLSocketFactory(sslSocketFactory); + if (trustManager == null) { + // okhttp 4.x requires an explicit X509TrustManager alongside SSLSocketFactory. + // Fall back to the JVM default TrustManager so existing callers that only set + // SSLSocketFactory continue to work without requiring API changes. + try { + TrustManagerFactory tmf = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); + tmf.init((KeyStore) null); + for (TrustManager tm : tmf.getTrustManagers()) { + if (tm instanceof X509TrustManager) { + trustManager = (X509TrustManager) tm; + break; + } + } + } catch (Exception e) { + throw new RuntimeException("Failed to obtain default X509TrustManager for okhttp", e); + } } + this.httpConnection.setSSLSocketFactory(sslSocketFactory, trustManager); } } diff --git a/src/main/java/com/tencentcloudapi/common/http/HttpConnection.java b/src/main/java/com/tencentcloudapi/common/http/HttpConnection.java index f837274e79..81bb6a68b4 100644 --- a/src/main/java/com/tencentcloudapi/common/http/HttpConnection.java +++ b/src/main/java/com/tencentcloudapi/common/http/HttpConnection.java @@ -56,11 +56,6 @@ public void setProxyAuthenticator(Authenticator authenticator) { this.client = this.client.newBuilder().proxyAuthenticator(authenticator).build(); } - @Deprecated - public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) { - this.client = this.client.newBuilder().sslSocketFactory(sslSocketFactory).build(); - } - public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) { this.client = this.client.newBuilder().sslSocketFactory(sslSocketFactory, trustManager).build(); } @@ -99,7 +94,7 @@ public Response postRequest(String url, String body) throws TencentCloudSDKExcep MediaType contentType = MediaType.parse("application/x-www-form-urlencoded"); Request request = null; try { - request = new Request.Builder().url(url).post(RequestBody.create(contentType, body)).build(); + request = new Request.Builder().url(url).post(RequestBody.create(body, contentType)).build(); } catch (IllegalArgumentException e) { throw new TencentCloudSDKException(e.getClass().getName() + "-" + e.getMessage()); } @@ -115,7 +110,7 @@ public Response postRequest(String url, String body, Headers headers) request = new Request.Builder() .url(url) - .post(RequestBody.create(contentType, body)) + .post(RequestBody.create(body, contentType)) .headers(headers) .build(); } catch (IllegalArgumentException e) { @@ -133,7 +128,7 @@ public Response postRequest(String url, byte[] body, Headers headers) request = new Request.Builder() .url(url) - .post(RequestBody.create(contentType, body)) + .post(RequestBody.create(body, contentType)) .headers(headers) .build(); } catch (IllegalArgumentException e) { From 23a53bd7e5f733638942bd7e85bf2c579598c525 Mon Sep 17 00:00:00 2001 From: likeelli Date: Tue, 16 Jun 2026 11:38:24 +0800 Subject: [PATCH 2/3] test: add Okhttp4UpgradeTest for okhttp 4.x upgrade validation 8 test cases covering: TC1 - POST TC3-HMAC-SHA256 (default path) TC2 - GET HmacSHA256 (legacy signature) TC3 - GET TC3-HMAC-SHA256 TC4 - POST HmacSHA1 (legacy signature) TC5 - Custom SSLSocketFactory + X509TrustManager (okhttp4 two-arg API) TC6 - SSLSocketFactory only, no TrustManager (backward compat fallback) TC7 - Custom HostnameVerifier TC8 - Explicit HTTPS protocol --- .../okhttp4/Okhttp4UpgradeTest.java | 264 ++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 src/test/java/com/tencentcloudapi/integration/okhttp4/Okhttp4UpgradeTest.java diff --git a/src/test/java/com/tencentcloudapi/integration/okhttp4/Okhttp4UpgradeTest.java b/src/test/java/com/tencentcloudapi/integration/okhttp4/Okhttp4UpgradeTest.java new file mode 100644 index 0000000000..5ed65c05c0 --- /dev/null +++ b/src/test/java/com/tencentcloudapi/integration/okhttp4/Okhttp4UpgradeTest.java @@ -0,0 +1,264 @@ +package com.tencentcloudapi.integration.okhttp4; + +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.cvm.v20170312.CvmClient; +import com.tencentcloudapi.cvm.v20170312.models.DescribeInstancesRequest; +import com.tencentcloudapi.cvm.v20170312.models.DescribeInstancesResponse; +import com.tencentcloudapi.cvm.v20170312.models.DescribeZonesRequest; +import com.tencentcloudapi.cvm.v20170312.models.DescribeZonesResponse; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; +import java.security.KeyStore; + +/** + * okhttp 4.x 升级验证测试 + * + * 覆盖场景: + * TC1 - 默认配置 POST TC3-HMAC-SHA256(最常用路径) + * TC2 - GET + HmacSHA256(旧签名方式) + * TC3 - GET + TC3-HMAC-SHA256 + * TC4 - POST + HmacSHA1(旧签名方式) + * TC5 - 自定义 SSLSocketFactory + X509TrustManager(okhttp4 新 API) + * TC6 - 只设置 SSLSocketFactory 不设 TrustManager(向后兼容兜底逻辑) + * TC7 - 自定义 HostnameVerifier + * TC8 - HTTPS 协议显式指定 + * + * 运行方式(在外部仓根目录): + * mvn test -pl . -Dtest=Okhttp4UpgradeTest \ + * -DTENCENTCLOUD_SECRET_ID=your_id \ + * -DTENCENTCLOUD_SECRET_KEY=your_key + * + * 或通过环境变量: + * export TENCENTCLOUD_SECRET_ID=your_id + * export TENCENTCLOUD_SECRET_KEY=your_key + * mvn test -Dtest=Okhttp4UpgradeTest + */ +public class Okhttp4UpgradeTest { + + private static final String REGION = "ap-guangzhou"; + + private String secretId; + private String secretKey; + + @Before + public void setUp() { + secretId = getEnvOrProp("TENCENTCLOUD_SECRET_ID"); + secretKey = getEnvOrProp("TENCENTCLOUD_SECRET_KEY"); + if (secretId == null || secretId.isEmpty() || secretKey == null || secretKey.isEmpty()) { + throw new IllegalStateException( + "请设置环境变量 TENCENTCLOUD_SECRET_ID 和 TENCENTCLOUD_SECRET_KEY"); + } + } + + // ------------------------------------------------------------------------- + // TC1: 默认配置 POST TC3-HMAC-SHA256 + // ------------------------------------------------------------------------- + @Test + public void TC1_DefaultPostTC3() throws TencentCloudSDKException { + System.out.println("[TC1] POST TC3-HMAC-SHA256 (default)"); + + CvmClient client = new CvmClient(credential(), REGION); + DescribeZonesResponse resp = client.DescribeZones(new DescribeZonesRequest()); + + Assert.assertNotNull("Response should not be null", resp); + Assert.assertTrue("TotalCount >= 0", resp.getTotalCount() >= 0); + System.out.println("[TC1] PASS — TotalCount=" + resp.getTotalCount()); + } + + // ------------------------------------------------------------------------- + // TC2: GET + HmacSHA256(验证 RequestBody.create 参数顺序调整不影响 GET) + // ------------------------------------------------------------------------- + @Test + public void TC2_GetHmacSHA256() throws TencentCloudSDKException { + System.out.println("[TC2] GET HmacSHA256"); + + HttpProfile hp = new HttpProfile(); + hp.setReqMethod("GET"); + ClientProfile cp = new ClientProfile(); + cp.setSignMethod("HmacSHA256"); + cp.setHttpProfile(hp); + + CvmClient client = new CvmClient(credential(), REGION, cp); + DescribeInstancesResponse resp = client.DescribeInstances(new DescribeInstancesRequest()); + + Assert.assertNotNull(resp); + Assert.assertTrue(resp.getTotalCount() >= 0); + System.out.println("[TC2] PASS — TotalCount=" + resp.getTotalCount()); + } + + // ------------------------------------------------------------------------- + // TC3: GET + TC3-HMAC-SHA256 + // ------------------------------------------------------------------------- + @Test + public void TC3_GetTC3() throws TencentCloudSDKException { + System.out.println("[TC3] GET TC3-HMAC-SHA256"); + + HttpProfile hp = new HttpProfile(); + hp.setReqMethod("GET"); + ClientProfile cp = new ClientProfile(); + cp.setSignMethod("TC3-HMAC-SHA256"); + cp.setHttpProfile(hp); + + CvmClient client = new CvmClient(credential(), REGION, cp); + DescribeInstancesResponse resp = client.DescribeInstances(new DescribeInstancesRequest()); + + Assert.assertNotNull(resp); + Assert.assertTrue(resp.getTotalCount() >= 0); + System.out.println("[TC3] PASS — TotalCount=" + resp.getTotalCount()); + } + + // ------------------------------------------------------------------------- + // TC4: POST + HmacSHA1 + // ------------------------------------------------------------------------- + @Test + public void TC4_PostHmacSHA1() throws TencentCloudSDKException { + System.out.println("[TC4] POST HmacSHA1"); + + HttpProfile hp = new HttpProfile(); + hp.setReqMethod("POST"); + ClientProfile cp = new ClientProfile(); + cp.setSignMethod("HmacSHA1"); + cp.setHttpProfile(hp); + + CvmClient client = new CvmClient(credential(), REGION, cp); + DescribeInstancesResponse resp = client.DescribeInstances(new DescribeInstancesRequest()); + + Assert.assertNotNull(resp); + Assert.assertTrue(resp.getTotalCount() >= 0); + System.out.println("[TC4] PASS — TotalCount=" + resp.getTotalCount()); + } + + // ------------------------------------------------------------------------- + // TC5: 自定义 SSLSocketFactory + X509TrustManager(okhttp4 标准用法) + // 验证:setSSLSocketFactory(factory, trustManager) 双参数路径正常 + // ------------------------------------------------------------------------- + @Test + public void TC5_CustomSSLWithTrustManager() throws Exception { + System.out.println("[TC5] Custom SSLSocketFactory + X509TrustManager"); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); + tmf.init((KeyStore) null); + X509TrustManager tm = findX509TrustManager(tmf.getTrustManagers()); + Assert.assertNotNull("Should find X509TrustManager", tm); + + SSLContext sslCtx = SSLContext.getInstance("TLS"); + sslCtx.init(null, new TrustManager[]{tm}, null); + + HttpProfile hp = new HttpProfile(); + hp.setSslSocketFactory(sslCtx.getSocketFactory()); + hp.setX509TrustManager(tm); + ClientProfile cp = new ClientProfile(); + cp.setHttpProfile(hp); + + CvmClient client = new CvmClient(credential(), REGION, cp); + DescribeZonesResponse resp = client.DescribeZones(new DescribeZonesRequest()); + + Assert.assertNotNull(resp); + Assert.assertTrue(resp.getTotalCount() >= 0); + System.out.println("[TC5] PASS — TotalCount=" + resp.getTotalCount()); + } + + // ------------------------------------------------------------------------- + // TC6: 只设置 SSLSocketFactory,不设 X509TrustManager + // 验证:AbstractClient.trySetSSLSocketFactory() 兜底逻辑(从 JVM 默认取 TrustManager) + // 这是本次升级的核心向后兼容路径 + // ------------------------------------------------------------------------- + @Test + public void TC6_SSLSocketFactoryWithoutTrustManager() throws Exception { + System.out.println("[TC6] SSLSocketFactory only (backward compat fallback)"); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); + tmf.init((KeyStore) null); + X509TrustManager tm = findX509TrustManager(tmf.getTrustManagers()); + + SSLContext sslCtx = SSLContext.getInstance("TLS"); + sslCtx.init(null, new TrustManager[]{tm}, null); + + HttpProfile hp = new HttpProfile(); + hp.setSslSocketFactory(sslCtx.getSocketFactory()); + // 故意不调用 hp.setX509TrustManager(),触发兜底逻辑 + ClientProfile cp = new ClientProfile(); + cp.setHttpProfile(hp); + + CvmClient client = new CvmClient(credential(), REGION, cp); + DescribeZonesResponse resp = client.DescribeZones(new DescribeZonesRequest()); + + Assert.assertNotNull(resp); + Assert.assertTrue(resp.getTotalCount() >= 0); + System.out.println("[TC6] PASS — fallback TrustManager worked, TotalCount=" + resp.getTotalCount()); + } + + // ------------------------------------------------------------------------- + // TC7: 自定义 HostnameVerifier + // ------------------------------------------------------------------------- + @Test + public void TC7_CustomHostnameVerifier() throws TencentCloudSDKException { + System.out.println("[TC7] Custom HostnameVerifier"); + + HttpProfile hp = new HttpProfile(); + hp.setHostnameVerifier((hostname, session) -> { + System.out.println("[TC7] verifying hostname: " + hostname); + return true; + }); + ClientProfile cp = new ClientProfile(); + cp.setHttpProfile(hp); + + CvmClient client = new CvmClient(credential(), REGION, cp); + DescribeZonesResponse resp = client.DescribeZones(new DescribeZonesRequest()); + + Assert.assertNotNull(resp); + Assert.assertTrue(resp.getTotalCount() >= 0); + System.out.println("[TC7] PASS — TotalCount=" + resp.getTotalCount()); + } + + // ------------------------------------------------------------------------- + // TC8: 显式指定 HTTPS 协议 + // ------------------------------------------------------------------------- + @Test + public void TC8_ExplicitHttps() throws TencentCloudSDKException { + System.out.println("[TC8] Explicit HTTPS protocol"); + + HttpProfile hp = new HttpProfile(); + hp.setProtocol("https://"); + ClientProfile cp = new ClientProfile(); + cp.setHttpProfile(hp); + + CvmClient client = new CvmClient(credential(), REGION, cp); + DescribeZonesResponse resp = client.DescribeZones(new DescribeZonesRequest()); + + Assert.assertNotNull(resp); + Assert.assertTrue(resp.getTotalCount() >= 0); + System.out.println("[TC8] PASS — TotalCount=" + resp.getTotalCount()); + } + + // ------------------------------------------------------------------------- + // 工具方法 + // ------------------------------------------------------------------------- + private Credential credential() { + return new Credential(secretId, secretKey); + } + + private static String getEnvOrProp(String key) { + String val = System.getenv(key); + if (val != null && !val.isEmpty()) return val; + return System.getProperty(key); + } + + private static X509TrustManager findX509TrustManager(TrustManager[] managers) { + for (TrustManager tm : managers) { + if (tm instanceof X509TrustManager) return (X509TrustManager) tm; + } + return null; + } +} From d3239a89eb2a5c51c36b2b2406581d3863505d10 Mon Sep 17 00:00:00 2001 From: likeelli Date: Tue, 16 Jun 2026 16:35:08 +0800 Subject: [PATCH 3/3] =?UTF-8?q?--story=3D134453973=20=E3=80=90=E5=AE=89?= =?UTF-8?q?=E5=85=A8=E3=80=91Java=20SDK=20okhttp=20=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E6=BC=8F=E6=B4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commonclient/OkhttpUpgradeTest.java | 161 +++++++++++ .../okhttp4/Okhttp4UpgradeTest.java | 264 ------------------ 2 files changed, 161 insertions(+), 264 deletions(-) create mode 100644 src/test/java/com/tencentcloudapi/integration/commonclient/OkhttpUpgradeTest.java delete mode 100644 src/test/java/com/tencentcloudapi/integration/okhttp4/Okhttp4UpgradeTest.java diff --git a/src/test/java/com/tencentcloudapi/integration/commonclient/OkhttpUpgradeTest.java b/src/test/java/com/tencentcloudapi/integration/commonclient/OkhttpUpgradeTest.java new file mode 100644 index 0000000000..c310a8850e --- /dev/null +++ b/src/test/java/com/tencentcloudapi/integration/commonclient/OkhttpUpgradeTest.java @@ -0,0 +1,161 @@ +package com.tencentcloudapi.integration.commonclient; + +import com.tencentcloudapi.common.CommonClient; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import okhttp3.OkHttp; +import org.junit.Assert; +import org.junit.Test; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; + +/** + * 验证 okhttp 升级到 4.x 后核心功能正常 + * 运行前请设置环境变量: + * TENCENTCLOUD_SECRET_ID + * TENCENTCLOUD_SECRET_KEY + */ +public class OkhttpUpgradeTest { + + private Credential getCredential() { + return new Credential( + System.getenv("TENCENTCLOUD_SECRET_ID"), + System.getenv("TENCENTCLOUD_SECRET_KEY")); + } + + /** + * 验证 okhttp 版本已升级到 4.x + */ + @Test + public void testOkhttpVersion() { + String version = OkHttp.VERSION; + System.out.println("OkHttp version: " + version); + Assert.assertTrue("期望 okhttp 版本为 4.x,实际为: " + version, + version.startsWith("4.")); + } + + /** + * 基础 API 调用:DescribeInstances(验证 RequestBody.create 参数顺序修改后正常) + */ + @Test + public void testBasicApiCall() { + Credential cred = getCredential(); + CommonClient client = new CommonClient("cvm", "2017-03-12", cred, "ap-guangzhou"); + try { + String resp = client.call("DescribeInstances", + "{\"Filters\":[{\"Name\":\"zone\",\"Values\":[\"ap-guangzhou-1\"]}]}"); + System.out.println("DescribeInstances 响应: " + resp.substring(0, Math.min(200, resp.length()))); + Assert.assertTrue("响应中应包含 RequestId", resp.contains("RequestId")); + } catch (TencentCloudSDKException e) { + Assert.fail("API 调用失败: " + e.getMessage()); + } + } + + /** + * 验证 HTTPS 正常(默认 SSLSocketFactory,okhttp 4.x 默认连接) + */ + @Test + public void testHttpsCall() { + Credential cred = getCredential(); + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setProtocol("https://"); + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + + CommonClient client = new CommonClient("cvm", "2017-03-12", cred, "ap-guangzhou", clientProfile); + try { + String resp = client.call("DescribeInstances", "{}"); + System.out.println("HTTPS 调用响应: " + resp.substring(0, Math.min(200, resp.length()))); + Assert.assertTrue("HTTPS 调用应包含 RequestId", resp.contains("RequestId")); + } catch (TencentCloudSDKException e) { + Assert.fail("HTTPS 调用失败: " + e.getMessage()); + } + } + + /** + * 验证仅设置 SSLSocketFactory(不传 TrustManager)时 okhttp 4.x 兼容性 + * AbstractClient 改动:自动获取默认 X509TrustManager,避免报错 + */ + @Test + public void testSSLSocketFactoryOnlyCompat() throws NoSuchAlgorithmException, KeyManagementException { + Credential cred = getCredential(); + + // 只创建 SSLSocketFactory,不显式传 TrustManager(模拟旧调用方式) + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, null, null); // 使用 JVM 默认 TrustManager + SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setSslSocketFactory(sslSocketFactory); + // 注意:不调用 setX509TrustManager,测试 AbstractClient 的自动兜底逻辑 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + + CommonClient client = new CommonClient("cvm", "2017-03-12", cred, "ap-guangzhou", clientProfile); + try { + String resp = client.call("DescribeInstances", "{}"); + System.out.println("SSLSocketFactory-only 调用响应: " + resp.substring(0, Math.min(200, resp.length()))); + Assert.assertTrue("应包含 RequestId", resp.contains("RequestId")); + } catch (TencentCloudSDKException e) { + Assert.fail("SSLSocketFactory only 调用失败(兼容性回归): " + e.getMessage()); + } + } + + /** + * 验证自定义 SSLSocketFactory + TrustManager(信任所有证书)调用正常 + */ + @Test + public void testCustomSSLSocketFactory() throws Exception { + Credential cred = getCredential(); + + TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] chain, String authType) {} + public void checkServerTrusted(X509Certificate[] chain, String authType) {} + public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } + } + }; + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); + SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setSslSocketFactory(sslSocketFactory); + httpProfile.setX509TrustManager((X509TrustManager) trustAllCerts[0]); + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + + CommonClient client = new CommonClient("cvm", "2017-03-12", cred, "ap-guangzhou", clientProfile); + try { + String resp = client.call("DescribeInstances", "{}"); + System.out.println("自定义 SSL 调用响应: " + resp.substring(0, Math.min(200, resp.length()))); + Assert.assertTrue("应包含 RequestId", resp.contains("RequestId")); + } catch (TencentCloudSDKException e) { + Assert.fail("自定义 SSL 调用失败: " + e.getMessage()); + } + } + + /** + * 验证 POST JSON 请求(覆盖 RequestBody.create(body, contentType) 调用路径) + */ + @Test + public void testPostJsonRequest() { + Credential cred = getCredential(); + CommonClient client = new CommonClient("sts", "2018-08-13", cred, "ap-guangzhou"); + try { + String resp = client.call("GetCallerIdentity", "{}"); + System.out.println("GetCallerIdentity 响应: " + resp.substring(0, Math.min(200, resp.length()))); + Assert.assertTrue("应包含 RequestId", resp.contains("RequestId")); + } catch (TencentCloudSDKException e) { + Assert.fail("POST JSON 请求失败: " + e.getMessage()); + } + } +} diff --git a/src/test/java/com/tencentcloudapi/integration/okhttp4/Okhttp4UpgradeTest.java b/src/test/java/com/tencentcloudapi/integration/okhttp4/Okhttp4UpgradeTest.java deleted file mode 100644 index 5ed65c05c0..0000000000 --- a/src/test/java/com/tencentcloudapi/integration/okhttp4/Okhttp4UpgradeTest.java +++ /dev/null @@ -1,264 +0,0 @@ -package com.tencentcloudapi.integration.okhttp4; - -import com.tencentcloudapi.common.Credential; -import com.tencentcloudapi.common.exception.TencentCloudSDKException; -import com.tencentcloudapi.common.profile.ClientProfile; -import com.tencentcloudapi.common.profile.HttpProfile; -import com.tencentcloudapi.cvm.v20170312.CvmClient; -import com.tencentcloudapi.cvm.v20170312.models.DescribeInstancesRequest; -import com.tencentcloudapi.cvm.v20170312.models.DescribeInstancesResponse; -import com.tencentcloudapi.cvm.v20170312.models.DescribeZonesRequest; -import com.tencentcloudapi.cvm.v20170312.models.DescribeZonesResponse; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; -import java.security.KeyStore; - -/** - * okhttp 4.x 升级验证测试 - * - * 覆盖场景: - * TC1 - 默认配置 POST TC3-HMAC-SHA256(最常用路径) - * TC2 - GET + HmacSHA256(旧签名方式) - * TC3 - GET + TC3-HMAC-SHA256 - * TC4 - POST + HmacSHA1(旧签名方式) - * TC5 - 自定义 SSLSocketFactory + X509TrustManager(okhttp4 新 API) - * TC6 - 只设置 SSLSocketFactory 不设 TrustManager(向后兼容兜底逻辑) - * TC7 - 自定义 HostnameVerifier - * TC8 - HTTPS 协议显式指定 - * - * 运行方式(在外部仓根目录): - * mvn test -pl . -Dtest=Okhttp4UpgradeTest \ - * -DTENCENTCLOUD_SECRET_ID=your_id \ - * -DTENCENTCLOUD_SECRET_KEY=your_key - * - * 或通过环境变量: - * export TENCENTCLOUD_SECRET_ID=your_id - * export TENCENTCLOUD_SECRET_KEY=your_key - * mvn test -Dtest=Okhttp4UpgradeTest - */ -public class Okhttp4UpgradeTest { - - private static final String REGION = "ap-guangzhou"; - - private String secretId; - private String secretKey; - - @Before - public void setUp() { - secretId = getEnvOrProp("TENCENTCLOUD_SECRET_ID"); - secretKey = getEnvOrProp("TENCENTCLOUD_SECRET_KEY"); - if (secretId == null || secretId.isEmpty() || secretKey == null || secretKey.isEmpty()) { - throw new IllegalStateException( - "请设置环境变量 TENCENTCLOUD_SECRET_ID 和 TENCENTCLOUD_SECRET_KEY"); - } - } - - // ------------------------------------------------------------------------- - // TC1: 默认配置 POST TC3-HMAC-SHA256 - // ------------------------------------------------------------------------- - @Test - public void TC1_DefaultPostTC3() throws TencentCloudSDKException { - System.out.println("[TC1] POST TC3-HMAC-SHA256 (default)"); - - CvmClient client = new CvmClient(credential(), REGION); - DescribeZonesResponse resp = client.DescribeZones(new DescribeZonesRequest()); - - Assert.assertNotNull("Response should not be null", resp); - Assert.assertTrue("TotalCount >= 0", resp.getTotalCount() >= 0); - System.out.println("[TC1] PASS — TotalCount=" + resp.getTotalCount()); - } - - // ------------------------------------------------------------------------- - // TC2: GET + HmacSHA256(验证 RequestBody.create 参数顺序调整不影响 GET) - // ------------------------------------------------------------------------- - @Test - public void TC2_GetHmacSHA256() throws TencentCloudSDKException { - System.out.println("[TC2] GET HmacSHA256"); - - HttpProfile hp = new HttpProfile(); - hp.setReqMethod("GET"); - ClientProfile cp = new ClientProfile(); - cp.setSignMethod("HmacSHA256"); - cp.setHttpProfile(hp); - - CvmClient client = new CvmClient(credential(), REGION, cp); - DescribeInstancesResponse resp = client.DescribeInstances(new DescribeInstancesRequest()); - - Assert.assertNotNull(resp); - Assert.assertTrue(resp.getTotalCount() >= 0); - System.out.println("[TC2] PASS — TotalCount=" + resp.getTotalCount()); - } - - // ------------------------------------------------------------------------- - // TC3: GET + TC3-HMAC-SHA256 - // ------------------------------------------------------------------------- - @Test - public void TC3_GetTC3() throws TencentCloudSDKException { - System.out.println("[TC3] GET TC3-HMAC-SHA256"); - - HttpProfile hp = new HttpProfile(); - hp.setReqMethod("GET"); - ClientProfile cp = new ClientProfile(); - cp.setSignMethod("TC3-HMAC-SHA256"); - cp.setHttpProfile(hp); - - CvmClient client = new CvmClient(credential(), REGION, cp); - DescribeInstancesResponse resp = client.DescribeInstances(new DescribeInstancesRequest()); - - Assert.assertNotNull(resp); - Assert.assertTrue(resp.getTotalCount() >= 0); - System.out.println("[TC3] PASS — TotalCount=" + resp.getTotalCount()); - } - - // ------------------------------------------------------------------------- - // TC4: POST + HmacSHA1 - // ------------------------------------------------------------------------- - @Test - public void TC4_PostHmacSHA1() throws TencentCloudSDKException { - System.out.println("[TC4] POST HmacSHA1"); - - HttpProfile hp = new HttpProfile(); - hp.setReqMethod("POST"); - ClientProfile cp = new ClientProfile(); - cp.setSignMethod("HmacSHA1"); - cp.setHttpProfile(hp); - - CvmClient client = new CvmClient(credential(), REGION, cp); - DescribeInstancesResponse resp = client.DescribeInstances(new DescribeInstancesRequest()); - - Assert.assertNotNull(resp); - Assert.assertTrue(resp.getTotalCount() >= 0); - System.out.println("[TC4] PASS — TotalCount=" + resp.getTotalCount()); - } - - // ------------------------------------------------------------------------- - // TC5: 自定义 SSLSocketFactory + X509TrustManager(okhttp4 标准用法) - // 验证:setSSLSocketFactory(factory, trustManager) 双参数路径正常 - // ------------------------------------------------------------------------- - @Test - public void TC5_CustomSSLWithTrustManager() throws Exception { - System.out.println("[TC5] Custom SSLSocketFactory + X509TrustManager"); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - tmf.init((KeyStore) null); - X509TrustManager tm = findX509TrustManager(tmf.getTrustManagers()); - Assert.assertNotNull("Should find X509TrustManager", tm); - - SSLContext sslCtx = SSLContext.getInstance("TLS"); - sslCtx.init(null, new TrustManager[]{tm}, null); - - HttpProfile hp = new HttpProfile(); - hp.setSslSocketFactory(sslCtx.getSocketFactory()); - hp.setX509TrustManager(tm); - ClientProfile cp = new ClientProfile(); - cp.setHttpProfile(hp); - - CvmClient client = new CvmClient(credential(), REGION, cp); - DescribeZonesResponse resp = client.DescribeZones(new DescribeZonesRequest()); - - Assert.assertNotNull(resp); - Assert.assertTrue(resp.getTotalCount() >= 0); - System.out.println("[TC5] PASS — TotalCount=" + resp.getTotalCount()); - } - - // ------------------------------------------------------------------------- - // TC6: 只设置 SSLSocketFactory,不设 X509TrustManager - // 验证:AbstractClient.trySetSSLSocketFactory() 兜底逻辑(从 JVM 默认取 TrustManager) - // 这是本次升级的核心向后兼容路径 - // ------------------------------------------------------------------------- - @Test - public void TC6_SSLSocketFactoryWithoutTrustManager() throws Exception { - System.out.println("[TC6] SSLSocketFactory only (backward compat fallback)"); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - tmf.init((KeyStore) null); - X509TrustManager tm = findX509TrustManager(tmf.getTrustManagers()); - - SSLContext sslCtx = SSLContext.getInstance("TLS"); - sslCtx.init(null, new TrustManager[]{tm}, null); - - HttpProfile hp = new HttpProfile(); - hp.setSslSocketFactory(sslCtx.getSocketFactory()); - // 故意不调用 hp.setX509TrustManager(),触发兜底逻辑 - ClientProfile cp = new ClientProfile(); - cp.setHttpProfile(hp); - - CvmClient client = new CvmClient(credential(), REGION, cp); - DescribeZonesResponse resp = client.DescribeZones(new DescribeZonesRequest()); - - Assert.assertNotNull(resp); - Assert.assertTrue(resp.getTotalCount() >= 0); - System.out.println("[TC6] PASS — fallback TrustManager worked, TotalCount=" + resp.getTotalCount()); - } - - // ------------------------------------------------------------------------- - // TC7: 自定义 HostnameVerifier - // ------------------------------------------------------------------------- - @Test - public void TC7_CustomHostnameVerifier() throws TencentCloudSDKException { - System.out.println("[TC7] Custom HostnameVerifier"); - - HttpProfile hp = new HttpProfile(); - hp.setHostnameVerifier((hostname, session) -> { - System.out.println("[TC7] verifying hostname: " + hostname); - return true; - }); - ClientProfile cp = new ClientProfile(); - cp.setHttpProfile(hp); - - CvmClient client = new CvmClient(credential(), REGION, cp); - DescribeZonesResponse resp = client.DescribeZones(new DescribeZonesRequest()); - - Assert.assertNotNull(resp); - Assert.assertTrue(resp.getTotalCount() >= 0); - System.out.println("[TC7] PASS — TotalCount=" + resp.getTotalCount()); - } - - // ------------------------------------------------------------------------- - // TC8: 显式指定 HTTPS 协议 - // ------------------------------------------------------------------------- - @Test - public void TC8_ExplicitHttps() throws TencentCloudSDKException { - System.out.println("[TC8] Explicit HTTPS protocol"); - - HttpProfile hp = new HttpProfile(); - hp.setProtocol("https://"); - ClientProfile cp = new ClientProfile(); - cp.setHttpProfile(hp); - - CvmClient client = new CvmClient(credential(), REGION, cp); - DescribeZonesResponse resp = client.DescribeZones(new DescribeZonesRequest()); - - Assert.assertNotNull(resp); - Assert.assertTrue(resp.getTotalCount() >= 0); - System.out.println("[TC8] PASS — TotalCount=" + resp.getTotalCount()); - } - - // ------------------------------------------------------------------------- - // 工具方法 - // ------------------------------------------------------------------------- - private Credential credential() { - return new Credential(secretId, secretKey); - } - - private static String getEnvOrProp(String key) { - String val = System.getenv(key); - if (val != null && !val.isEmpty()) return val; - return System.getProperty(key); - } - - private static X509TrustManager findX509TrustManager(TrustManager[] managers) { - for (TrustManager tm : managers) { - if (tm instanceof X509TrustManager) return (X509TrustManager) tm; - } - return null; - } -}