1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.atlassian.theplugin.idea.ui;
18
19 import com.intellij.openapi.ui.DialogWrapper;
20 import com.intellij.openapi.ui.VerticalFlowLayout;
21 import com.intellij.ui.components.labels.BoldLabel;
22 import com.jgoodies.forms.builder.ButtonBarBuilder;
23 import com.jgoodies.forms.builder.DefaultFormBuilder;
24 import com.jgoodies.forms.layout.FormLayout;
25
26 import javax.swing.*;
27 import java.security.cert.X509Certificate;
28 import java.security.MessageDigest;
29 import java.awt.event.ActionListener;
30 import java.awt.event.ActionEvent;
31 import java.awt.*;
32 import java.util.Map;
33 import java.util.LinkedHashMap;
34 import java.util.HashMap;
35
36 import org.jetbrains.annotations.Nullable;
37
38 public class CertMessageDialog extends DialogWrapper {
39 private String server;
40
41 private X509Certificate[] chain;
42
43 private InfoPanel generalInfo = new InfoPanel();
44 private CollapsiblePanel infoPanel = new CollapsiblePanel(false, false, "General Information");
45
46
47 private JLabel details = new JLabel();
48
49 private JButton accept = new JButton("Accept");
50
51 private JButton acceptTmp = new JButton("Accept temporarily");
52
53 private JButton cancel = new JButton("Cancel");
54
55 private boolean temporarily = false;
56 private String message;
57 private static final int MARGIN = 5;
58
59
60 public CertMessageDialog(String serverName, String message, X509Certificate[] chain) {
61 super(false);
62 this.server = serverName;
63 this.message = message;
64 this.chain = chain;
65 setTitle("Security Alert");
66 setModal(true);
67 accept.addActionListener(new ActionListener() {
68 public void actionPerformed(ActionEvent event) {
69 close(JOptionPane.OK_OPTION);
70 }
71 });
72 acceptTmp.addActionListener(new ActionListener() {
73 public void actionPerformed(ActionEvent event) {
74 temporarily = true;
75 close(JOptionPane.OK_OPTION);
76 }
77 });
78 cancel.addActionListener(new ActionListener() {
79 public void actionPerformed(ActionEvent event) {
80 temporarily = true;
81 close(JOptionPane.CANCEL_OPTION);
82 }
83 });
84
85 init();
86 }
87
88 public boolean isTemporarily() {
89 return temporarily;
90 }
91
92
93 @Override
94 @Nullable
95 protected JComponent createSouthPanel() {
96 ButtonBarBuilder builder = new ButtonBarBuilder();
97 builder.addRelatedGap();
98 builder.addGlue();
99 builder.addGriddedButtons(new JButton[]{accept, acceptTmp, cancel});
100 return builder.getPanel();
101 }
102
103 private ScrollablePanel certInfo = new ScrollablePanel();
104
105 private Map<String, String> fields = new LinkedHashMap<String, String>() {
106 {
107 put("CN", "Common Name");
108 put("O", "Organisation");
109 put("OU", "Organisational Unit");
110 put("C", "Country code");
111 put("S", "State");
112 put("ST", "State ");
113 put("L", "Location");
114 put("E", "E-mail adress");
115 }
116 };
117
118 private void initCertInfo() {
119 X509Certificate cert = chain[0];
120 certInfo.add(infoPanel);
121 infoPanel.setContent(generalInfo);
122 infoPanel.collapse();
123 infoPanel.expand();
124 generalInfo.addSeparator("Issued To");
125 buildDNPanel(cert.getSubjectDN().getName(), generalInfo);
126 generalInfo.addSeparator("Issued By");
127 buildDNPanel(cert.getIssuerDN().getName(), generalInfo);
128 generalInfo.addSeparator("Validity");
129 generalInfo.addRow("From", cert.getNotBefore().toString());
130 generalInfo.addRow("To", cert.getNotAfter().toString());
131 generalInfo.addSeparator("Fingerprints");
132 try {
133 generalInfo.addRow("SHA1 fingerprint", getCertificateFingerprint("SHA1", cert));
134 generalInfo.addRow("MD5 fingerprint", getCertificateFingerprint("MD5", cert));
135 } catch (Exception e) {
136
137 }
138
139 CollapsiblePanel detailsPanel = new CollapsiblePanel(true, true, "Details");
140 details.setText("<html><pre>" + cert.toString());
141 detailsPanel.setContent(details);
142 certInfo.add(detailsPanel);
143 }
144
145 private String getCertificateFingerprint(String s, X509Certificate certificate)
146 throws Exception {
147 MessageDigest digest = MessageDigest.getInstance(s);
148 byte fing[] = digest.digest(certificate.getEncoded());
149 return toHexString(fing);
150 }
151
152
153 private String toHexString(byte bytes[]) {
154 StringBuffer stringBuffer = new StringBuffer();
155 int i = bytes.length;
156 for (int j = 0; j < i; j++) {
157 byte2hex(bytes[j], stringBuffer);
158 if (j < i - 1)
159 stringBuffer.append(":");
160 }
161 return stringBuffer.toString();
162 }
163
164 private static final String[] HEX_DIGITS = {"0", "1", "2", "3", "4",
165 "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
166
167 private void byte2hex(byte b, StringBuffer stringbuffer) {
168 int nb = b & 0xFF;
169 int i_1 = (nb >> 4) & 0xF;
170 int i_2 = nb & 0xF;
171 stringbuffer.append(HEX_DIGITS[i_1] + HEX_DIGITS[i_2]);
172 }
173
174
175 private void buildDNPanel(String strDN, InfoPanel panel) {
176 Map<String, String> fields;
177 fields = parse(strDN);
178 for (Map.Entry<String, String> field : this.fields.entrySet()) {
179 String key = field.getKey();
180 if (fields.containsKey(key)) {
181 panel.addRow(this.fields.get(key) + " (" + key + ")", fields.get(key));
182 }
183 }
184 }
185
186 private Map<String, String> parse(String name) {
187 Map<String, String> result = new HashMap<String, String>();
188 String[] fields = name.split(",");
189 for (String field : fields) {
190 String[] parts = field.trim().split("=");
191 result.put(parts[0], parts[1]);
192 }
193 return result;
194 }
195
196
197 @Nullable
198 protected JComponent createCenterPanel() {
199 JPanel panel = new JPanel(new GridBagLayout());
200 JScrollPane scroll = new JScrollPane();
201
202
203 JPanel msgPanel = new JPanel(new BorderLayout(20, 0));
204 JLabel titleLabel = new BoldLabel("Server " + server
205 + " uses an invalid security certificate.");
206 msgPanel.add(titleLabel, BorderLayout.NORTH);
207 JPanel info = new JPanel();
208 JLabel msgLabel = new BoldLabel(message);
209 msgLabel.setForeground(Color.RED);
210 info.add(msgLabel);
211
212 msgPanel.add(info, BorderLayout.CENTER);
213 JLabel qLabel = new BoldLabel("Do you want to accept it anyway?");
214 msgPanel.add(qLabel, BorderLayout.SOUTH);
215 msgPanel.setBorder(BorderFactory.createEmptyBorder(MARGIN, MARGIN, MARGIN, MARGIN));
216
217 GridBagConstraints gbc = new GridBagConstraints();
218 gbc.weightx = 1.0;
219 gbc.weighty = 0;
220 gbc.gridx = 0;
221 gbc.gridy = 0;
222 gbc.fill = GridBagConstraints.BOTH;
223 panel.add(msgPanel, gbc);
224
225 gbc.gridx = 0;
226 gbc.gridy = 3;
227 gbc.gridwidth = 2;
228 gbc.insets = new Insets(0, 0, 0, 0);
229 gbc.fill = GridBagConstraints.BOTH;
230 gbc.weightx = 1.0;
231 gbc.weighty = 1.0;
232 certInfo.setLayout(new VerticalFlowLayout());
233 scroll.setViewportView(certInfo);
234 scroll.getViewport().setOpaque(false);
235 scroll.setOpaque(false);
236 scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
237 scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
238 scroll.setBorder(BorderFactory.createEmptyBorder());
239 panel.add(scroll, gbc);
240 panel.setPreferredSize(new Dimension(800, 500));
241
242 gbc.gridy = 4;
243 gbc.weighty = 0;
244 gbc.fill = GridBagConstraints.HORIZONTAL;
245
246 initCertInfo();
247 return panel;
248 }
249
250 protected boolean shouldSaveOptionsOnCancel() {
251 return false;
252 }
253
254 private class InfoPanel extends JPanel {
255
256 private JPanel panel = new JPanel();
257
258 private DefaultFormBuilder builder;
259
260 private InfoPanel() {
261 super();
262
263
264
265
266
267 FormLayout layout = new FormLayout("right:pref, 4dlu, pref:grow", "");
268 builder = new DefaultFormBuilder(layout, this);
269 builder.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
270 }
271
272 void addSeparator(String title) {
273 builder.appendSeparator(title);
274 }
275
276 void addRow(String caption, String value) {
277 builder.append(new BoldLabel(caption));
278 builder.append(value);
279 builder.nextLine();
280 }
281
282 }
283
284 private class ScrollablePanel extends JPanel implements Scrollable {
285
286 private static final int A_LOT = 100000;
287
288
289 public Dimension getPreferredScrollableViewportSize() {
290 return new Dimension(1, A_LOT);
291 }
292
293 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
294 return 1;
295 }
296
297 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
298 return 1;
299 }
300
301 public boolean getScrollableTracksViewportWidth() {
302 return true;
303 }
304
305 public boolean getScrollableTracksViewportHeight() {
306 return false;
307 }
308
309 }
310
311 }