1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.atlassian.theplugin.util;
18
19 import com.atlassian.theplugin.commons.configuration.GeneralConfigurationBean;
20 import com.atlassian.theplugin.commons.remoteapi.rest.AbstractHttpSession;
21 import com.atlassian.theplugin.idea.ui.CertMessageDialog;
22
23 import javax.net.ssl.TrustManager;
24 import javax.net.ssl.TrustManagerFactory;
25 import javax.net.ssl.X509TrustManager;
26 import java.awt.*;
27 import java.lang.reflect.InvocationTargetException;
28 import java.security.KeyStore;
29 import java.security.KeyStoreException;
30 import java.security.NoSuchAlgorithmException;
31 import java.security.cert.CertificateException;
32 import java.security.cert.CertificateExpiredException;
33 import java.security.cert.CertificateNotYetValidException;
34 import java.security.cert.X509Certificate;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.HashSet;
38
39 public final class PluginTrustManager implements X509TrustManager {
40 private static final Collection<String> ALREADY_REJECTED_CERTS = new HashSet<String>();
41 private static Collection<String> temporarilyAcceptedCerts =
42 Collections.synchronizedCollection(new HashSet<String>());
43
44 private final GeneralConfigurationBean configuration;
45 private X509TrustManager standardTrustManager;
46
47 private static ThreadLocal<String> url = new ThreadLocal<String>();
48
49 public static String getUrl() {
50 return url.get();
51 }
52
53 public PluginTrustManager(GeneralConfigurationBean configuration) throws NoSuchAlgorithmException, KeyStoreException {
54 this.configuration = configuration;
55 TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
56 factory.init((KeyStore) null);
57 TrustManager[] trustmanagers = factory.getTrustManagers();
58
59
60 for (TrustManager trustmanager : trustmanagers) {
61 if (trustmanager instanceof X509TrustManager) {
62 standardTrustManager = (X509TrustManager) trustmanager;
63 return;
64 }
65 }
66
67 if (standardTrustManager == null) {
68 throw new NoSuchAlgorithmException("cannot retrieve default trust manager found");
69 }
70 }
71
72
73 public void checkClientTrusted(X509Certificate[] chain, String authType)
74 throws CertificateException {
75 standardTrustManager.checkClientTrusted(chain, authType);
76 }
77
78
79 private boolean isSelfSigned(X509Certificate certificate) {
80 return certificate.getSubjectDN().equals(certificate.getIssuerDN());
81 }
82
83
84 public void checkServerTrusted(final X509Certificate[] chain, String authType) throws CertificateException {
85 try {
86 standardTrustManager.checkServerTrusted(chain, authType);
87 } catch (final CertificateException
88 e) {
89
90 String strCert = chain[0].toString();
91 if (ALREADY_REJECTED_CERTS.contains(strCert)) {
92 throw e;
93 }
94
95 if (checkChain(chain, configuration.getCerts())
96 ||
97 checkChain(chain, temporarilyAcceptedCerts)) {
98 return;
99 }
100
101 String message = e.getMessage();
102 message = message.substring(message.lastIndexOf(":") + 1);
103 if (isSelfSigned(chain[0])) {
104 message = "Self-signed certificate";
105 }
106 try {
107 chain[0].checkValidity();
108 } catch (CertificateExpiredException e1) {
109 message = "Certificate expired";
110 } catch (CertificateNotYetValidException e1) {
111 message = "Certificate not yet valid";
112 }
113 final String server = AbstractHttpSession.getUrl().getHost();
114
115
116 final int[] accepted = new int[]{0};
117 synchronized (PluginTrustManager.class) {
118 try {
119 final String message1 = message;
120 EventQueue.invokeAndWait(new Runnable() {
121 public void run() {
122 CertMessageDialog dialog = new CertMessageDialog(server, message1, chain);
123 dialog.show();
124 if (dialog.isOK()) {
125 if (dialog.isTemporarily()) {
126 accepted[0] = 1;
127 return;
128 }
129 accepted[0] = 2;
130 }
131 }
132 });
133 } catch (InterruptedException e1) {
134
135 } catch (InvocationTargetException e1) {
136
137 }
138 }
139
140 switch (accepted[0]) {
141 case 1:
142 temporarilyAcceptedCerts.add(strCert);
143 break;
144 case 2:
145 synchronized (configuration) {
146
147 configuration.addCert(strCert);
148 }
149 break;
150 default:
151 synchronized (ALREADY_REJECTED_CERTS) {
152 ALREADY_REJECTED_CERTS.add(strCert);
153 }
154 throw e;
155 }
156 }
157 }
158
159 private boolean checkChain(X509Certificate[] chain, Collection<String> certs) {
160 for (X509Certificate cert : chain) {
161 if (certs.contains(cert.toString())) {
162 return true;
163 }
164 }
165 return false;
166 }
167
168
169 public X509Certificate[] getAcceptedIssuers() {
170 return standardTrustManager.getAcceptedIssuers();
171 }
172
173 }