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 : ConfirmingTrustManager = CertificateManager .getInstance().trustManager) {
21
+
22
+ fun configure (toAdd : Array <out X509ExtendedTrustManager >): X509TrustManager {
23
+ try {
24
+ if (hasSystemManagerField()) {
25
+ // < IC-2022.2
26
+ setCompositeManager(toAdd, trustManager)
27
+ } else {
28
+ // >= IC-2022.2
29
+ addCompositeManager(toAdd, 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
+ * @return true if com.intellij.util.net.ssl.ConfirmingTrustManager has a field mySystemManager. False otherwise.
44
+ */
45
+ private fun hasSystemManagerField (): Boolean {
46
+ return FieldUtils .getDeclaredField(
47
+ ConfirmingTrustManager ::class .java, " mySystemManager" , true ) != null
48
+ }
49
+
50
+ /* *
51
+ * Sets a [CompositeX509ExtendedTrustManager] with the given [X509TrustManager]s
52
+ * to the given destination [X509TrustManager].
53
+ * If a [CompositeX509ExtendedTrustManager] already exists, his first entry is taken and set to a new
54
+ * [CompositeX509ExtendedTrustManager] that replaces the existing one.
55
+ *
56
+ * @param trustManagers the trust managers that should be set to the destination trust manager
57
+ * @param destination the destination trust manager that should receive the trust managers
58
+ * @return true if the operation worked
59
+ */
60
+ private fun setCompositeManager (
61
+ trustManagers : Array <out X509ExtendedTrustManager >,
62
+ destination : ConfirmingTrustManager
63
+ ): Boolean {
64
+ val systemManagerField = FieldUtils .getDeclaredField(
65
+ ConfirmingTrustManager ::class .java,
66
+ " mySystemManager" ,
67
+ true
68
+ ) ? : return false
69
+ val systemManager = systemManagerField.get(destination) as ? X509ExtendedTrustManager ? : return false
70
+ val compositeTrustManager = createCompositeTrustManager(systemManager, trustManagers)
71
+ systemManagerField.set(destination, compositeTrustManager)
72
+ return true
73
+ }
74
+
75
+ private fun createCompositeTrustManager (
76
+ systemManager : X509ExtendedTrustManager ,
77
+ clientTrustManagers : Array <out X509ExtendedTrustManager >
78
+ ): X509ExtendedTrustManager {
79
+ val trustManagers = if (systemManager is CompositeX509ExtendedTrustManager ) {
80
+ // already patched CertificateManager, re-create composite manager
81
+ mutableListOf (systemManager.innerTrustManagers[0 ])
82
+ .plus(clientTrustManagers)
83
+ } else {
84
+ // 1st time we patch CertificateManager, create composite manager
85
+ mutableListOf (systemManager)
86
+ .plus(clientTrustManagers)
87
+ }
88
+ return CompositeX509ExtendedTrustManager (trustManagers)
89
+ }
90
+
91
+ /* *
92
+ * Adds a [CompositeX509ExtendedTrustManager] to the given destination [X509TrustManager].
93
+ * If a [CompositeX509ExtendedTrustManager] already exists, it is replaced by a new [CompositeX509ExtendedTrustManager].
94
+ *
95
+ * @param trustManagers the trust managers that should be added to destination trust manager
96
+ * @param destination the trust manager that should receive the given trust managers
97
+ */
98
+ private fun addCompositeManager (
99
+ trustManagers : Array <out X509ExtendedTrustManager >,
100
+ destination : ConfirmingTrustManager
101
+ ): Boolean {
102
+ val systemManagersField = FieldUtils .getDeclaredField(
103
+ destination::class .java,
104
+ " mySystemManagers" ,
105
+ true
106
+ ) ? : return false
107
+ val managers = systemManagersField.get(destination) as ? MutableList <X509TrustManager > ? : return false
108
+ val nonCompositeManagers = managers.filterNot { it is CompositeX509ExtendedTrustManager }
109
+ val clientTrustManager = CompositeX509ExtendedTrustManager (trustManagers.asList())
110
+ managers.clear()
111
+ managers.addAll(nonCompositeManagers)
112
+ managers.add(clientTrustManager)
113
+ return true
114
+ }
115
+ }
0 commit comments