1
+ /* ******************************************************************************
2
+ * Copyright (c) 2023 Red Hat, Inc.
3
+ * Distributed under license by Red Hat, Inc. All rights reserved.
4
+ * This program is made available under the terms of the
5
+ * Eclipse Public License v2.0 which accompanies this distribution,
6
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
7
+ *
8
+ * Contributors:
9
+ * Red Hat, Inc. - initial API and implementation
10
+ ******************************************************************************/
11
+ package com.redhat.devtools.intellij.kubernetes.model.client.ssl
12
+
13
+ import com.intellij.openapi.diagnostic.logger
14
+ import com.intellij.util.net.ssl.CertificateManager
15
+ import com.intellij.util.net.ssl.ConfirmingTrustManager
16
+ import javax.net.ssl.X509ExtendedTrustManager
17
+ import javax.net.ssl.X509TrustManager
18
+ import org.apache.commons.lang3.reflect.FieldUtils
19
+
20
+ class IDEATrustManager (private val trustManager : X509TrustManager = CertificateManager .getInstance().trustManager) {
21
+
22
+ fun configure (toIntegrate : Array <out X509ExtendedTrustManager >): X509TrustManager {
23
+ try {
24
+ if (hasSystemManagerField()) {
25
+ // < IC-2022.2
26
+ setCompositeManager(toIntegrate, trustManager)
27
+ } else {
28
+ // >= IC-2022.2
29
+ addCompositeManager(toIntegrate, trustManager)
30
+ }
31
+ } catch (e: RuntimeException ) {
32
+ logger<IDEATrustManager >().warn(" Could not configure IDEA trust manager." , e)
33
+ }
34
+ return trustManager
35
+ }
36
+
37
+ /* *
38
+ * Returns `true` if [ConfirmingTrustManager] has a private field `mySystemManager`.
39
+ * Returns `false` otherwise.
40
+ * IDEA < IC-2022.2 manages a single [X509TrustManager] in a private field called `mySystemManager`.
41
+ * IDEA >= IC-2022.2 manages a list of [X509TrustManager]s in a private list called `mySystemManagers`.
42
+ */
43
+ private fun hasSystemManagerField (): Boolean {
44
+ return FieldUtils .getDeclaredField(
45
+ ConfirmingTrustManager ::class .java, " mySystemManager" , true ) != null
46
+ }
47
+
48
+ /* *
49
+ * Sets a [CompositeX509ExtendedTrustManager] with the given [X509TrustManager]s
50
+ * to the given destination [X509TrustManager].
51
+ * If a [CompositeX509ExtendedTrustManager] already exists, his first entry is taken and set to a new
52
+ * [CompositeX509ExtendedTrustManager] that replaces the existing one.
53
+ *
54
+ * @param trustManagers the trust managers that should be set to the destination trust manager
55
+ * @param destination the destination trust manager that should receive the trust managers
56
+ * @return true if the operation worked
57
+ */
58
+ private fun setCompositeManager (
59
+ trustManagers : Array <out X509ExtendedTrustManager >,
60
+ destination : X509TrustManager
61
+ ): Boolean {
62
+ val systemManagerField = FieldUtils .getDeclaredField(
63
+ ConfirmingTrustManager ::class .java,
64
+ " mySystemManager" ,
65
+ true
66
+ ) ? : return false
67
+ val systemManager = systemManagerField.get(destination) as ? X509ExtendedTrustManager ? : return false
68
+ val compositeTrustManager = createCompositeTrustManager(systemManager, trustManagers)
69
+ systemManagerField.set(destination, compositeTrustManager)
70
+ return true
71
+ }
72
+
73
+ private fun createCompositeTrustManager (
74
+ systemManager : X509ExtendedTrustManager ,
75
+ clientTrustManagers : Array <out X509ExtendedTrustManager >
76
+ ): X509ExtendedTrustManager {
77
+ val trustManagers = if (systemManager is CompositeX509ExtendedTrustManager ) {
78
+ // already patched CertificateManager, re-create composite manager
79
+ mutableListOf (systemManager.innerTrustManagers[0 ])
80
+ .plus(clientTrustManagers)
81
+ } else {
82
+ // 1st time we patch CertificateManager, create composite manager
83
+ mutableListOf (systemManager)
84
+ .plus(clientTrustManagers)
85
+ }
86
+ return CompositeX509ExtendedTrustManager (trustManagers)
87
+ }
88
+
89
+ /* *
90
+ * Adds a [CompositeX509ExtendedTrustManager] to the given destination [X509TrustManager].
91
+ * If a [CompositeX509ExtendedTrustManager] already exists, it is replaced by a new [CompositeX509ExtendedTrustManager].
92
+ *
93
+ * @param trustManagers the trust managers that should be added to destination trust manager
94
+ * @param destination the trust manager that should receive the given trust managers
95
+ */
96
+ private fun addCompositeManager (
97
+ trustManagers : Array <out X509ExtendedTrustManager >,
98
+ destination : X509TrustManager
99
+ ): Boolean {
100
+ val systemManagersField = FieldUtils .getDeclaredField(
101
+ destination::class .java,
102
+ " mySystemManagers" ,
103
+ true
104
+ ) ? : return false
105
+ val managers = systemManagersField.get(destination) as ? MutableList <X509TrustManager > ? : return false
106
+ val nonCompositeManagers = managers.filterNot { it is CompositeX509ExtendedTrustManager }
107
+ val clientTrustManager = CompositeX509ExtendedTrustManager (trustManagers.asList())
108
+ managers.clear()
109
+ managers.addAll(nonCompositeManagers)
110
+ managers.add(clientTrustManager)
111
+ return true
112
+ }
113
+ }
0 commit comments