View Javadoc

1   /**
2    * Copyright (C) 2008 Atlassian
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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();  // workaround
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 //			info.setBackground(Color.GRAY);
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;  //To change body of implemented methods use File | Settings | File Templates.
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 //				super(true, collapsed, title);
263 //				setContent(panel);
264 //
265 //				setCollapsed(!collapsed); // workaround
266 //				setCollapsed(collapsed);
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 			// cheating obviously but this seems to do the right thing, so whatever :)
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 	}