From 8073f6df7bc0e7defd44d00c8789105c5c55945a Mon Sep 17 00:00:00 2001
From: bonampak <14160522+bonampak@users.noreply.github.com>
Date: Fri, 24 Jan 2025 21:39:07 +0100
Subject: [PATCH 1/2] KNOX-3094: Update CM API swagger and okhttp dependencies
---
gateway-discovery-cm/pom.xml | 8 +--
.../discovery/cm/DiscoveryApiClient.java | 64 ++++++++-----------
.../auth/DoAsQueryParameterInterceptor.java | 45 +++++++++++++
.../cm/auth/SpnegoAuthInterceptor.java | 21 +++---
.../ClouderaManagerServiceDiscoveryTest.java | 2 +-
.../util/TruststoreSSLContextUtils.java | 25 ++++++++
pom.xml | 8 +--
7 files changed, 109 insertions(+), 64 deletions(-)
create mode 100644 gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/auth/DoAsQueryParameterInterceptor.java
diff --git a/gateway-discovery-cm/pom.xml b/gateway-discovery-cm/pom.xml
index 2cb5ddb691..d3e4cd66a9 100644
--- a/gateway-discovery-cm/pom.xml
+++ b/gateway-discovery-cm/pom.xml
@@ -66,15 +66,9 @@
com.cloudera.api.swagger
cloudera-manager-api-swagger
-
-
- io.swagger
- swagger-annotations
-
-
- com.squareup.okhttp
+ com.squareup.okhttp3
okhttp
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 5a74a9cc84..965d53cc18 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
@@ -26,14 +26,13 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
+import javax.net.ssl.X509TrustManager;
import javax.security.auth.Subject;
import com.cloudera.api.swagger.client.ApiClient;
-import com.cloudera.api.swagger.client.Pair;
-import com.cloudera.api.swagger.client.auth.Authentication;
-import com.cloudera.api.swagger.client.auth.HttpBasicAuth;
-import com.squareup.okhttp.ConnectionSpec;
-import com.squareup.okhttp.OkHttpClient;
+import okhttp3.ConnectionSpec;
+import okhttp3.Interceptor;
+import okhttp3.OkHttpClient;
import org.apache.knox.gateway.config.ConfigurationException;
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
@@ -41,6 +40,7 @@
import org.apache.knox.gateway.services.security.AliasServiceException;
import org.apache.knox.gateway.topology.discovery.ServiceDiscoveryConfig;
import org.apache.knox.gateway.topology.discovery.cm.auth.AuthUtils;
+import org.apache.knox.gateway.topology.discovery.cm.auth.DoAsQueryParameterInterceptor;
import org.apache.knox.gateway.topology.discovery.cm.auth.SpnegoAuthInterceptor;
import org.apache.knox.gateway.util.TruststoreSSLContextUtils;
@@ -126,55 +126,39 @@ private void configure(GatewayConfig gatewayConfig, AliasService aliasService, K
setUsername(username);
setPassword(password);
- if (isKerberos) {
+ if (isKerberos()) {
// If there is a Kerberos subject, then add the SPNEGO auth interceptor
Subject subject = AuthUtils.getKerberosSubject();
if (subject != null) {
- SpnegoAuthInterceptor spnegoInterceptor = new SpnegoAuthInterceptor(subject);
- getHttpClient().interceptors().add(spnegoInterceptor);
+ addInterceptor(new SpnegoAuthInterceptor(subject));
}
+ addInterceptor(new DoAsQueryParameterInterceptor(username));
}
configureTimeouts(gatewayConfig);
configureSsl(gatewayConfig, trustStore);
}
- private void configureTimeouts(GatewayConfig config) {
- OkHttpClient client = getHttpClient();
- client.setConnectTimeout(config.getServiceDiscoveryConnectTimeoutMillis(), TimeUnit.MILLISECONDS);
- client.setReadTimeout(config.getServiceDiscoveryReadTimeoutMillis(), TimeUnit.MILLISECONDS);
- client.setWriteTimeout(config.getServiceDiscoveryWriteTimeoutMillis(), TimeUnit.MILLISECONDS);
- log.discoveryClientTimeout(client.getConnectTimeout(), client.getReadTimeout(), client.getWriteTimeout());
+ private void addInterceptor(Interceptor interceptor) {
+ OkHttpClient newClient = getHttpClient().newBuilder().addInterceptor(interceptor).build();
+ setHttpClient(newClient);
}
- @Override
- public String buildUrl(String path, List queryParams) {
- // If kerberos is enabled, then for every request, we're going to include a doAs query param
- if (isKerberos()) {
- String user = getUsername();
- if (user != null) {
- queryParams.add(new Pair("doAs", user));
- }
- }
- return super.buildUrl(path, queryParams);
- }
-
- /**
- * @return The username set from the discovery configuration when this instance was initialized.
- */
- private String getUsername() {
- String username = null;
- Authentication basicAuth = getAuthentication("basic");
- if (basicAuth instanceof HttpBasicAuth) {
- username = ((HttpBasicAuth) basicAuth).getUsername();
- }
- return username;
+ private void configureTimeouts(GatewayConfig config) {
+ OkHttpClient.Builder builder = getHttpClient().newBuilder();
+ builder.connectTimeout(config.getServiceDiscoveryConnectTimeoutMillis(), TimeUnit.MILLISECONDS);
+ builder.readTimeout(config.getServiceDiscoveryReadTimeoutMillis(), TimeUnit.MILLISECONDS);
+ builder.writeTimeout(config.getServiceDiscoveryWriteTimeoutMillis(), TimeUnit.MILLISECONDS);
+ OkHttpClient client = builder.build();
+ setHttpClient(client);
+ log.discoveryClientTimeout(client.connectTimeoutMillis(), client.readTimeoutMillis(), client.writeTimeoutMillis());
}
private void configureSsl(GatewayConfig gatewayConfig, KeyStore trustStore) {
final SSLContext truststoreSSLContext = TruststoreSSLContextUtils.getTruststoreSSLContext(trustStore);
+ final X509TrustManager trustManager = TruststoreSSLContextUtils.getTrustManager(trustStore);
- if (truststoreSSLContext != null) {
+ if (truststoreSSLContext != null && trustManager != null) {
final ConnectionSpec.Builder connectionSpecBuilder = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS);
final List includedSslCiphers = gatewayConfig.getIncludedSSLCiphers();
if (includedSslCiphers == null || includedSslCiphers.isEmpty()) {
@@ -188,8 +172,10 @@ private void configureSsl(GatewayConfig gatewayConfig, KeyStore trustStore) {
} else {
connectionSpecBuilder.tlsVersions(includedSslProtocols.toArray(new String[0]));
}
- getHttpClient().setConnectionSpecs(Arrays.asList(connectionSpecBuilder.build()));
- getHttpClient().setSslSocketFactory(truststoreSSLContext.getSocketFactory());
+ OkHttpClient.Builder builder = getHttpClient().newBuilder();
+ builder.connectionSpecs(Arrays.asList(connectionSpecBuilder.build()));
+ builder.sslSocketFactory(truststoreSSLContext.getSocketFactory(), trustManager);
+ setHttpClient(builder.build());
} else {
log.failedToConfigureTruststore();
}
diff --git a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/auth/DoAsQueryParameterInterceptor.java b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/auth/DoAsQueryParameterInterceptor.java
new file mode 100644
index 0000000000..041f0b421e
--- /dev/null
+++ b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/auth/DoAsQueryParameterInterceptor.java
@@ -0,0 +1,45 @@
+/*
+ * 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.knox.gateway.topology.discovery.cm.auth;
+
+import okhttp3.HttpUrl;
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+
+import java.io.IOException;
+
+public class DoAsQueryParameterInterceptor implements Interceptor {
+
+ private final String userName;
+ private static final String DO_AS_PRINCIPAL_PARAM = "doAs";
+
+ public DoAsQueryParameterInterceptor(String userName) {
+ this.userName = userName;
+ }
+
+ @Override
+ public Response intercept(Interceptor.Chain chain) throws IOException {
+ HttpUrl url = chain.request().url().newBuilder()
+ .addQueryParameter(DO_AS_PRINCIPAL_PARAM, userName)
+ .build();
+ Request request = chain.request().newBuilder()
+ .url(url)
+ .build();
+ return chain.proceed(request);
+ }
+}
diff --git a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/auth/SpnegoAuthInterceptor.java b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/auth/SpnegoAuthInterceptor.java
index 0122239c69..4adf33c61c 100644
--- a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/auth/SpnegoAuthInterceptor.java
+++ b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/auth/SpnegoAuthInterceptor.java
@@ -16,10 +16,11 @@
*/
package org.apache.knox.gateway.topology.discovery.cm.auth;
-import com.squareup.okhttp.Authenticator;
-import com.squareup.okhttp.Interceptor;
-import com.squareup.okhttp.Request;
-import com.squareup.okhttp.Response;
+import okhttp3.Authenticator;
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.Route;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
@@ -32,7 +33,6 @@
import java.io.IOException;
import java.net.InetAddress;
-import java.net.Proxy;
import java.net.UnknownHostException;
import java.security.Principal;
import java.security.PrivilegedActionException;
@@ -102,7 +102,7 @@ private static boolean isNegotiate(String value) {
}
@Override
- public Request authenticate(Proxy proxy, Response response) throws IOException {
+ public Request authenticate(Route route, Response response) throws IOException {
// If already attempted or not challenged for Kerberos, then skip this attempt
if (response.request().headers(AUTHORIZATION).stream().anyMatch(SpnegoAuthInterceptor::isNegotiate) ||
response.headers(WWW_AUTHENTICATE).stream().noneMatch(SpnegoAuthInterceptor::isNegotiate)) {
@@ -112,13 +112,8 @@ public Request authenticate(Proxy proxy, Response response) throws IOException {
return authenticate(response.request());
}
- @Override
- public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
- return null; // Not needed
- }
-
private Request authenticate(Request request) {
- String principal = defineServicePrincipal(remoteServiceName, request.url().getHost(), useCanonicalHostname);
+ String principal = defineServicePrincipal(remoteServiceName, request.url().host(), useCanonicalHostname);
byte[] token = generateToken(principal);
String credential = format(Locale.getDefault(), "%s %s", NEGOTIATE, Base64.getEncoder().encodeToString(token));
@@ -245,4 +240,4 @@ public boolean needsRefresh() throws GSSException {
}
}
-}
\ No newline at end of file
+}
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 9d98643ba7..0007e75ad3 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
@@ -30,7 +30,7 @@
import com.cloudera.api.swagger.model.ApiService;
import com.cloudera.api.swagger.model.ApiServiceConfig;
import com.cloudera.api.swagger.model.ApiServiceList;
-import com.squareup.okhttp.Call;
+import okhttp3.Call;
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.services.security.AliasService;
import org.apache.knox.gateway.topology.discovery.ServiceDiscovery;
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/util/TruststoreSSLContextUtils.java b/gateway-spi/src/main/java/org/apache/knox/gateway/util/TruststoreSSLContextUtils.java
index 7fadf5ed2a..87b7dcfa46 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/util/TruststoreSSLContextUtils.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/util/TruststoreSSLContextUtils.java
@@ -20,8 +20,12 @@
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
@@ -48,4 +52,25 @@ public static SSLContext getTruststoreSSLContext(KeyStore truststore) {
return sslContext;
}
+ public static X509TrustManager getTrustManager(KeyStore truststore) {
+ try {
+ if (truststore != null) {
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(truststore);
+ TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
+ if (trustManagers != null) {
+ for (TrustManager tm : trustManagers) {
+ if (tm instanceof X509TrustManager) {
+ return (X509TrustManager) tm;
+ }
+ }
+ }
+ throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
+ }
+ } catch (KeyStoreException | NoSuchAlgorithmException | IllegalStateException e) {
+ LOGGER.failedToLoadTruststore(e.getMessage(), e);
+ }
+ return null;
+ }
+
}
diff --git a/pom.xml b/pom.xml
index 6b2c1a3458..e5d570c251 100644
--- a/pom.xml
+++ b/pom.xml
@@ -174,7 +174,7 @@
1.4
3.3.0
8.38
- 7.8.1
+ 7.13.1
${cloudera-manager.version}
1.9.4
1.4
@@ -242,6 +242,7 @@
2.9.0
2.4.9
4.13.2
+ 1.9.10
1.5
1.11
2.17.1
@@ -256,7 +257,7 @@
4.1.77.Final
9.37.3
v14.15.0
- 2.7.5
+ 4.12.0
3.4.5
4.5.6
42.4.4
@@ -1570,11 +1571,10 @@
- com.squareup.okhttp
+ com.squareup.okhttp3
okhttp
${okhttp.version}
-
com.google.code.gson
gson
From c0f5f720635c8cf7ea0a06e1b67901b4b91de3a7 Mon Sep 17 00:00:00 2001
From: bonampak <14160522+bonampak@users.noreply.github.com>
Date: Sat, 15 Feb 2025 22:38:48 +0100
Subject: [PATCH 2/2] KNOX-3094: Update gson-fire, gson and pin okio to 3.6.0.
Resolve dependency convergence for org.jetbrains:annotations.
---
pom.xml | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index e5d570c251..59008308ea 100644
--- a/pom.xml
+++ b/pom.xml
@@ -208,7 +208,8 @@
1.11.0
1.0.0
2.3.3
- 2.8.9
+ 2.10.1
+ 1.9.0
3.0.7
28.2-jre
3.2.4
@@ -263,6 +264,7 @@
42.4.4
8.0.28
3.3.0
+ 3.6.0
3.16.3
2.0.9
0.0.11.1
@@ -1575,6 +1577,32 @@
okhttp
${okhttp.version}
+
+ com.squareup.okhttp3
+ logging-interceptor
+ ${okhttp.version}
+
+
+ com.squareup.okio
+ okio
+ ${okio.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jdk8
+ ${kotlin-stdlib.version}
+
+
+ org.jetbrains
+ annotations
+
+
+
+
+ io.gsonfire
+ gson-fire
+ ${gsonfire.version}
+
com.google.code.gson
gson