10
10
******************************************************************************/
11
11
package com.redhat.devtools.intellij.kubernetes.model.client
12
12
13
+ import com.intellij.openapi.diagnostic.logger
13
14
import com.intellij.util.net.ssl.CertificateManager
15
+ import com.intellij.util.net.ssl.ConfirmingTrustManager
14
16
import com.redhat.devtools.intellij.kubernetes.model.util.isUnauthorized
15
17
import io.fabric8.kubernetes.client.Client
16
18
import io.fabric8.kubernetes.client.Config
17
19
import io.fabric8.kubernetes.client.KubernetesClient
18
20
import io.fabric8.kubernetes.client.KubernetesClientBuilder
19
21
import io.fabric8.kubernetes.client.KubernetesClientException
22
+ import io.fabric8.kubernetes.client.http.HttpClient
20
23
import io.fabric8.kubernetes.client.impl.AppsAPIGroupClient
21
24
import io.fabric8.kubernetes.client.impl.BatchAPIGroupClient
22
25
import io.fabric8.kubernetes.client.impl.NetworkAPIGroupClient
23
26
import io.fabric8.kubernetes.client.impl.StorageAPIGroupClient
27
+ import io.fabric8.kubernetes.client.internal.SSLUtils
24
28
import io.fabric8.openshift.client.NamespacedOpenShiftClient
25
29
import io.fabric8.openshift.client.OpenShiftClient
26
30
import java.util.concurrent.ConcurrentHashMap
31
+ import javax.net.ssl.X509ExtendedTrustManager
32
+ import javax.net.ssl.X509TrustManager
33
+ import nl.altindag.ssl.trustmanager.CompositeX509ExtendedTrustManager
34
+ import nl.altindag.ssl.util.TrustManagerUtils
35
+ import org.apache.commons.lang3.reflect.FieldUtils
27
36
28
37
open class OSClientAdapter (client : OpenShiftClient , private val kubeClient : KubernetesClient ) :
29
38
ClientAdapter <OpenShiftClient >(client) {
@@ -55,14 +64,16 @@ abstract class ClientAdapter<C: KubernetesClient>(private val fabric8Client: C)
55
64
companion object Factory {
56
65
fun create (namespace : String? = null, context : String? = null): ClientAdapter <out KubernetesClient > {
57
66
val config = Config .autoConfigure(context)
58
- setAcceptCertificates(config)
59
67
return create(namespace, config)
60
68
}
61
69
62
70
fun create (namespace : String? = null, config : Config ): ClientAdapter <out KubernetesClient > {
63
71
setNamespace(namespace, config)
64
72
val kubeClient = KubernetesClientBuilder ()
65
73
.withConfig(config)
74
+ .withHttpClientBuilderConsumer { builder ->
75
+ setSslContext(builder, config)
76
+ }
66
77
.build()
67
78
val osClient = kubeClient.adapt(NamespacedOpenShiftClient ::class .java)
68
79
val isOpenShift = isOpenShift(osClient)
@@ -73,10 +84,74 @@ abstract class ClientAdapter<C: KubernetesClient>(private val fabric8Client: C)
73
84
}
74
85
}
75
86
76
- private fun setAcceptCertificates (config : Config ) {
77
- val manager = CertificateManager .getInstance().state;
78
- config.isTrustCerts = manager.ACCEPT_AUTOMATICALLY
79
- config.isDisableHostnameVerification = manager.ACCEPT_AUTOMATICALLY
87
+ private fun setSslContext (builder : HttpClient .Builder , config : Config ) {
88
+ val clientTrustManagers = SSLUtils .trustManagers(config)
89
+ .filterIsInstance<X509ExtendedTrustManager >()
90
+ .toTypedArray()
91
+ val ideTrustManager = configureIdeTrustManager(clientTrustManagers)
92
+ builder.sslContext(SSLUtils .keyManagers(config), arrayOf(ideTrustManager))
93
+ }
94
+
95
+ private fun configureIdeTrustManager (clientTrustManagers : Array <X509ExtendedTrustManager >): ConfirmingTrustManager {
96
+ val ideTrustManager = CertificateManager .getInstance().trustManager
97
+ try {
98
+ // < IC-2022.2
99
+ if (! setCompositeManager(clientTrustManagers, ideTrustManager)) {
100
+ // >= IC-2022.2
101
+ addCompositeManager(clientTrustManagers, ideTrustManager)
102
+ }
103
+ } catch (e: RuntimeException ) {
104
+ logger<ClientAdapter <* >>().warn(" Could not configure IDEA trust manager." , e)
105
+ }
106
+ return ideTrustManager
107
+ }
108
+
109
+ private fun setCompositeManager (
110
+ clientTrustManagers : Array <X509ExtendedTrustManager >,
111
+ ideTrustManager : ConfirmingTrustManager
112
+ ): Boolean {
113
+ val systemManagerField = FieldUtils .getDeclaredField(
114
+ ideTrustManager::class .java, " mySystemManager" , true ) ? : return false
115
+ val systemManager = systemManagerField.get(ideTrustManager) as ? X509ExtendedTrustManager ? : return false
116
+ val compositeTrustManager = createCompositeTrustManager(systemManager, clientTrustManagers)
117
+ systemManagerField.set(ideTrustManager, compositeTrustManager)
118
+ return true
119
+ }
120
+
121
+ private fun addCompositeManager (
122
+ clientTrustManagers : Array <X509ExtendedTrustManager >,
123
+ ideTrustManager : ConfirmingTrustManager
124
+ ) {
125
+ val systemManagersField =
126
+ FieldUtils .getDeclaredField(ideTrustManager::class .java, " mySystemManagers" , true )
127
+ val managers =
128
+ systemManagersField.get(ideTrustManager) as ? MutableList <X509TrustManager > ? : return
129
+ val nonCompositeManagers = managers.filter { it !is CompositeX509ExtendedTrustManager }
130
+ val clientTrustManager = CompositeX509ExtendedTrustManager (clientTrustManagers.asList())
131
+ managers.clear()
132
+ managers.addAll(nonCompositeManagers)
133
+ managers.add(clientTrustManager)
134
+ }
135
+
136
+ private fun createCompositeTrustManager (
137
+ systemManager : X509ExtendedTrustManager ,
138
+ clientTrustManagers : Array <X509ExtendedTrustManager >
139
+ ): X509ExtendedTrustManager {
140
+ val compositeTrustManager = if (systemManager is CompositeX509ExtendedTrustManager
141
+ ) {
142
+ // already patched CertificateManager, re-create composite manager
143
+ TrustManagerUtils .trustManagerBuilder()
144
+ .withTrustManager(systemManager.innerTrustManagers[0 ])
145
+ .withTrustManagers(* clientTrustManagers)
146
+ .build()
147
+ } else {
148
+ // 1st time we patch CertificateManager, create composite manager
149
+ TrustManagerUtils .trustManagerBuilder()
150
+ .withTrustManager(systemManager)
151
+ .withTrustManagers(* clientTrustManagers)
152
+ .build()
153
+ }
154
+ return compositeTrustManager
80
155
}
81
156
82
157
private fun isOpenShift (osClient : NamespacedOpenShiftClient ): Boolean {
0 commit comments