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 java.lang.reflect.Field
17
+ import javax.net.ssl.X509ExtendedTrustManager
18
+ import javax.net.ssl.X509TrustManager
19
+ import org.apache.commons.lang3.reflect.FieldUtils
20
+
21
+ class IDEATrustManager (private val trustManager : X509TrustManager = CertificateManager .getInstance().trustManager) {
22
+
23
+ fun configure (toAdd : Array <out X509ExtendedTrustManager >): X509TrustManager {
24
+ try {
25
+ if (hasSystemManagerField()) {
26
+ // < IC-2022.2
27
+ setCompositeManager(toAdd, trustManager)
28
+ } else {
29
+ // >= IC-2022.2
30
+ addCompositeManager(toAdd, trustManager)
31
+ }
32
+ } catch (e: RuntimeException ) {
33
+ logger<IDEATrustManager >().warn(" Could not configure IDEA trust manager." , e)
34
+ }
35
+ return trustManager
36
+ }
37
+
38
+ /* *
39
+ * Returns `true` if [ConfirmingTrustManager] has a private field `mySystemManager`.
40
+ * Returns `false` otherwise.
41
+ * IDEA < IC-2022.2 manages a single [X509TrustManager] in a private field called `mySystemManager`.
42
+ * IDEA >= IC-2022.2 manages a list of [X509TrustManager]s in a private list called `mySystemManagers`.
43
+ *
44
+ * @return true if com.intellij.util.net.ssl.ConfirmingTrustManager has a field mySystemManager. False otherwise.
45
+ */
46
+ private fun hasSystemManagerField (): Boolean {
47
+ return getSystemManagerField() != null
48
+ }
49
+
50
+ private fun getSystemManagerField (): Field ? {
51
+ return FieldUtils .getDeclaredField(
52
+ trustManager::class .java,
53
+ " mySystemManager" ,
54
+ true
55
+ )
56
+ }
57
+
58
+ /* *
59
+ * Sets a [CompositeX509ExtendedTrustManager] with the given [X509TrustManager]s
60
+ * to the given destination [X509TrustManager].
61
+ * If a [CompositeX509ExtendedTrustManager] already exists, his first entry is taken and set to a new
62
+ * [CompositeX509ExtendedTrustManager] that replaces the existing one.
63
+ *
64
+ * @param trustManagers the trust managers that should be set to the destination trust manager
65
+ * @param destination the destination trust manager that should receive the trust managers
66
+ * @return true if the operation worked
67
+ */
68
+ private fun setCompositeManager (
69
+ trustManagers : Array <out X509ExtendedTrustManager >,
70
+ destination : X509TrustManager
71
+ ): Boolean {
72
+ val systemManagerField = getSystemManagerField() ? : return false
73
+ val systemManager = systemManagerField.get(destination) as ? X509ExtendedTrustManager ? : return false
74
+ val compositeTrustManager = createCompositeTrustManager(systemManager, trustManagers)
75
+ systemManagerField.set(destination, compositeTrustManager)
76
+ return true
77
+ }
78
+
79
+ private fun createCompositeTrustManager (
80
+ systemManager : X509ExtendedTrustManager ,
81
+ clientTrustManagers : Array <out X509ExtendedTrustManager >
82
+ ): X509ExtendedTrustManager {
83
+ val trustManagers = if (systemManager is CompositeX509ExtendedTrustManager ) {
84
+ // already patched CertificateManager, take 1st entry in existing system manager
85
+ mutableListOf (systemManager.innerTrustManagers[0 ])
86
+ } else {
87
+ // unpatched CertificateManager, take system manager
88
+ mutableListOf (systemManager)
89
+ }
90
+ trustManagers.addAll(clientTrustManagers)
91
+ return CompositeX509ExtendedTrustManager (trustManagers)
92
+ }
93
+
94
+ /* *
95
+ * Adds a [CompositeX509ExtendedTrustManager] to the given destination [X509TrustManager].
96
+ * If a [CompositeX509ExtendedTrustManager] already exists, it is replaced by a new [CompositeX509ExtendedTrustManager].
97
+ *
98
+ * @param trustManagers the trust managers that should be added to destination trust manager
99
+ * @param destination the trust manager that should receive the given trust managers
100
+ */
101
+ private fun addCompositeManager (
102
+ trustManagers : Array <out X509ExtendedTrustManager >,
103
+ destination : X509TrustManager
104
+ ): Boolean {
105
+ val systemManagersField = FieldUtils .getDeclaredField(
106
+ destination::class .java,
107
+ " mySystemManagers" ,
108
+ true
109
+ ) ? : return false
110
+ val managers = systemManagersField.get(destination) as ? MutableList <X509TrustManager > ? : return false
111
+ val nonCompositeManagers = managers.filterNot { it is CompositeX509ExtendedTrustManager }
112
+ val clientTrustManager = CompositeX509ExtendedTrustManager (trustManagers.asList())
113
+ managers.clear()
114
+ managers.addAll(nonCompositeManagers)
115
+ managers.add(clientTrustManager)
116
+ return true
117
+ }
118
+ }
0 commit comments