This is an automated email from the ASF dual-hosted git repository.

smolnar82 pushed a commit to branch knox_idf
in repository https://gitbox.apache.org/repos/asf/knox.git

commit 01c04c2da79e330ccfae3437bdc171d3e36a63ba
Author: Sandor Molnar <[email protected]>
AuthorDate: Fri Jun 19 17:46:10 2026 +0200

    KNOX-3356: Allow Cloudera Manager service discovery over cleartext HTTP 
(#1272)
    
    (cherry picked from commit c3f55243fba023261ae91b80b5534aaa460ed114)
---
 .../ClouderaManagerServiceDiscoveryMessages.java   |  3 +++
 .../topology/discovery/cm/DiscoveryApiClient.java  | 14 ++++++++++
 .../cm/ClouderaManagerServiceDiscoveryTest.java    | 30 +++++++++++++++++++++-
 3 files changed, 46 insertions(+), 1 deletion(-)

diff --git 
a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryMessages.java
 
b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryMessages.java
index d025fdf05..30155c4d9 100644
--- 
a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryMessages.java
+++ 
b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryMessages.java
@@ -280,6 +280,9 @@ public interface ClouderaManagerServiceDiscoveryMessages {
   @Message(level = MessageLevel.ERROR, text = "Failed to configure truststore")
   void failedToConfigureTruststore();
 
+  @Message(level = MessageLevel.DEBUG, text = "Skipping SSL configuration for 
cleartext CM discovery address {0}")
+  void skippingSslConfigurationForCleartextAddress(String address);
+
   @Message(level = MessageLevel.DEBUG, text = "Looking up cluster services 
from service discovery repository...")
   void lookupClusterServicesFromRepository();
 
diff --git 
a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/DiscoveryApiClient.java
 
b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/DiscoveryApiClient.java
index f74203b61..27e240ca5 100644
--- 
a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/DiscoveryApiClient.java
+++ 
b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/DiscoveryApiClient.java
@@ -20,6 +20,7 @@ import java.security.KeyStore;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Locale;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import javax.net.ssl.SSLContext;
@@ -155,6 +156,11 @@ public class DiscoveryApiClient extends ApiClient {
     return (address.endsWith("/") ? address + apiPath : address + "/" + 
apiPath);
   }
 
+  private boolean isSecure() {
+    final String basePath = getBasePath();
+    return basePath != null && 
basePath.toLowerCase(Locale.ROOT).startsWith("https:");
+  }
+
   private void configureInterceptors(List<Interceptor> interceptors) {
     final OkHttpClient.Builder builder = getHttpClient().newBuilder();
     interceptors.forEach(builder::addInterceptor);
@@ -172,6 +178,14 @@ public class DiscoveryApiClient extends ApiClient {
   }
 
   private void configureSsl(GatewayConfig gatewayConfig, KeyStore trustStore) {
+    // The CM discovery endpoint may be plain HTTP (e.g. CM TLS not enabled). 
In that case the
+    // TLS-only ConnectionSpec below would make OkHttp reject the connection 
with
+    // "CLEARTEXT communication not enabled for client". Only configure TLS 
for HTTPS addresses.
+    if (!isSecure()) {
+      log.skippingSslConfigurationForCleartextAddress(getBasePath());
+      return;
+    }
+
     final SSLContext truststoreSSLContext = 
TruststoreSSLContextUtils.getTruststoreSSLContext(trustStore);
     final X509TrustManager trustManager = 
TruststoreSSLContextUtils.getTrustManager(trustStore);
 
diff --git 
a/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryTest.java
 
b/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryTest.java
index adaaaf35a..9437913ad 100644
--- 
a/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryTest.java
+++ 
b/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryTest.java
@@ -91,6 +91,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 public class ClouderaManagerServiceDiscoveryTest {
 
   private static final String DISCOVERY_URL = "http://localhost:1234";;
+  private static final String DISCOVERY_URL_TLS = "https://localhost:1234";;
   private static final String DISCOVERY_USER = "discoveryUser";
   private static final String CLUSTER_NAME = "Cluster 1";
   private static final String DISCOVERY_PASSWORD_ALIAS = "discovery.alias";
@@ -164,7 +165,7 @@ public class ClouderaManagerServiceDiscoveryTest {
     
EasyMock.expect(gwConf.getClouderaManagerClientSSLProtocols()).andReturn(Set.of(cmClientTlsVersion)).anyTimes();
     EasyMock.replay(gwConf);
 
-    ServiceDiscoveryConfig sdConfig = createMockDiscoveryConfig(DISCOVERY_URL, 
DISCOVERY_USER, CLUSTER_NAME);
+    ServiceDiscoveryConfig sdConfig = 
createMockDiscoveryConfig(DISCOVERY_URL_TLS, DISCOVERY_USER, CLUSTER_NAME);
 
     AliasService aliasService = EasyMock.createNiceMock(AliasService.class);
     EasyMock.replay(aliasService);
@@ -195,6 +196,33 @@ public class ClouderaManagerServiceDiscoveryTest {
     assertTrue(containsTlsVersion(connectionSpecs.get(0).tlsVersions(), 
cmClientTlsVersion));
   }
 
+  /**
+   * KNOX-3353: when the CM discovery address is plain HTTP (CM TLS not 
enabled), the client must
+   * not be locked to a TLS-only ConnectionSpec, otherwise OkHttp rejects the 
request with
+   * "CLEARTEXT communication not enabled for client". The default specs 
(which include CLEARTEXT)
+   * should be left in place.
+   */
+  @Test
+  public void testApiClientAllowsCleartextForHttpDiscoveryAddress() {
+    GatewayConfig gwConf = EasyMock.createNiceMock(GatewayConfig.class);
+    
EasyMock.expect(gwConf.getClouderaManagerServiceDiscoveryApiVersion()).andReturn(GatewayConfig.DEFAULT_CLOUDERA_MANAGER_SERVICE_DISCOVERY_API_VERSION).anyTimes();
+    EasyMock.replay(gwConf);
+
+    ServiceDiscoveryConfig sdConfig = createMockDiscoveryConfig(DISCOVERY_URL, 
DISCOVERY_USER, CLUSTER_NAME);
+
+    AliasService aliasService = EasyMock.createNiceMock(AliasService.class);
+    EasyMock.replay(aliasService);
+
+    KeyStore trustStore = EasyMock.createNiceMock(KeyStore.class);
+    EasyMock.replay(trustStore);
+
+    ApiClient apiClient = new TestDiscoveryApiClient(gwConf, sdConfig, 
aliasService, trustStore);
+
+    final List<ConnectionSpec> connectionSpecs = 
apiClient.getHttpClient().connectionSpecs();
+    assertTrue("HTTP discovery address should keep a CLEARTEXT-capable 
connection spec.",
+        connectionSpecs.stream().anyMatch(spec -> 
spec.equals(ConnectionSpec.CLEARTEXT)));
+  }
+
   private boolean containsCipherSuite(List<CipherSuite> cipherSuites, String 
cipherSuiteNameToCheck) {
     return cipherSuites.stream().anyMatch(cipherSuite -> 
cipherSuite.javaName().equals(cipherSuiteNameToCheck));
   }

Reply via email to