KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > subversion > client > SvnClientExceptionHandler


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.subversion.client;
20
21 import java.awt.Dialog JavaDoc;
22 import java.io.File JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.InputStream JavaDoc;
25 import java.io.OutputStream JavaDoc;
26 import java.io.UnsupportedEncodingException JavaDoc;
27 import java.net.Socket JavaDoc;
28
29 import java.security.KeyManagementException JavaDoc;
30 import java.security.MessageDigest JavaDoc;
31 import java.security.NoSuchAlgorithmException JavaDoc;
32 import java.security.cert.CertificateEncodingException JavaDoc;
33 import java.security.cert.CertificateExpiredException JavaDoc;
34 import java.security.cert.CertificateNotYetValidException JavaDoc;
35 import java.security.cert.X509Certificate JavaDoc;
36 import java.util.ArrayList JavaDoc;
37 import java.util.List JavaDoc;
38 import javax.net.ssl.SSLContext;
39 import javax.net.ssl.SSLPeerUnverifiedException;
40 import javax.net.ssl.SSLSocket;
41 import javax.net.ssl.SSLSocketFactory;
42 import javax.net.ssl.TrustManager;
43 import javax.net.ssl.X509TrustManager;
44
45 import javax.swing.JButton JavaDoc;
46 import org.netbeans.modules.proxy.ConnectivitySettings;
47 import org.netbeans.modules.subversion.Diagnostics;
48 import org.netbeans.modules.subversion.SvnModuleConfig;
49 import org.netbeans.modules.subversion.config.CertificateFile;
50 import org.netbeans.modules.subversion.config.SvnConfigFiles;
51 import org.netbeans.modules.subversion.ui.repository.Repository;
52 import org.netbeans.modules.subversion.ui.repository.RepositoryConnection;
53 import org.netbeans.modules.subversion.util.FileUtils;
54 import org.netbeans.modules.subversion.util.SvnUtils;
55 import org.openide.DialogDescriptor;
56 import org.openide.DialogDisplayer;
57 import org.openide.ErrorManager;
58 import org.openide.util.HelpCtx;
59 import org.openide.util.NbBundle;
60 import org.tigris.subversion.svnclientadapter.ISVNClientAdapter;
61 import org.tigris.subversion.svnclientadapter.SVNClientException;
62 import org.tigris.subversion.svnclientadapter.SVNUrl;
63
64 /**
65  *
66  * @author Tomas Stupka
67  */

68 public class SvnClientExceptionHandler extends ExceptionHandler {
69     
70     private final ISVNClientAdapter adapter;
71     private final SvnClient client;
72     private static final String JavaDoc NEWLINE = System.getProperty("line.separator"); // NOI18N
73
private final String JavaDoc CHARSET_NAME = "ASCII7"; // NOI18N
74
private final int handledExceptions;
75     
76     private class CertificateFailure {
77         int mask;
78         String JavaDoc error;
79         String JavaDoc message;
80         CertificateFailure(int mask, String JavaDoc error, String JavaDoc message) {
81             this.mask = mask;
82             this.error = error;
83             this.message = message;
84         }
85     };
86    
87     private CertificateFailure[] failures = new CertificateFailure[] {
88         new CertificateFailure (1, "certificate is not yet valid" , NbBundle.getMessage(SvnClientExceptionHandler.class, "MSG_CertFailureNotYetValid")), // NOI18N
89
new CertificateFailure (2, "certificate has expired" , NbBundle.getMessage(SvnClientExceptionHandler.class, "MSG_CertFailureHasExpired")), // NOI18N
90
new CertificateFailure (4, "certificate issued for a different hostname" , NbBundle.getMessage(SvnClientExceptionHandler.class, "MSG_CertFailureWrongHostname")), // NOI18N
91
new CertificateFailure (8, "issuer is not trusted" , NbBundle.getMessage(SvnClientExceptionHandler.class, "MSG_CertFailureNotTrusted")) // NOI18N
92
};
93     
94     public SvnClientExceptionHandler(SVNClientException exception, ISVNClientAdapter adapter, SvnClient client, int handledExceptions) {
95         super(exception);
96         this.adapter = adapter;
97         this.client = client;
98         this.handledExceptions = handledExceptions;
99     }
100     
101     public boolean handleException() throws Exception JavaDoc {
102         int exceptionMask = getExceptionMask();
103         if(exceptionMask != EX_UNKNOWN) {
104             if( (handledExceptions & exceptionMask & EX_NO_HOST_CONNECTION) == exceptionMask) {
105                 return handleRepositoryConnectError();
106             } if( (handledExceptions & exceptionMask & EX_NO_CERTIFICATE) == exceptionMask) {
107                 return handleNoCertificateError();
108             } if( (handledExceptions & exceptionMask & EX_AUTHENTICATION) == exceptionMask) {
109                 return handleRepositoryConnectError();
110             }
111         }
112         throw getException();
113     }
114         
115     private boolean handleRepositoryConnectError() {
116         SVNUrl url = client.getSvnUrl();
117         String JavaDoc title = org.openide.util.NbBundle.getMessage(SvnClientExceptionHandler.class, "MSG_Error_ConnectionParameters"); // NOI18N
118
Repository repository = new Repository(title);
119         repository.selectUrl(url, true);
120         
121         JButton JavaDoc retryButton = new JButton JavaDoc(org.openide.util.NbBundle.getMessage(SvnClientExceptionHandler.class, "CTL_Action_Retry")); // NOI18N
122
Object JavaDoc option = repository.show(org.openide.util.NbBundle.getMessage(SvnClientExceptionHandler.class, "MSG_Error_AuthFailed"), // NOI18N
123
new HelpCtx(this.getClass()),
124                                         new Object JavaDoc[] {retryButton, org.openide.util.NbBundle.getMessage(SvnClientExceptionHandler.class, "CTL_Action_Cancel")}); // NOI18N
125

126
127         boolean ret = (option == retryButton);
128         if(ret) {
129             RepositoryConnection rc = repository.getSelectedRC();
130             String JavaDoc username = rc.getUsername();
131             String JavaDoc password = rc.getPassword();
132
133             adapter.setUsername(username);
134             adapter.setPassword(password);
135             SvnModuleConfig.getDefault().insertRecentUrl(rc);
136         }
137         return ret;
138     }
139
140     private boolean handleNoCertificateError() throws Exception JavaDoc {
141
142         // copy the certificate if it already exists
143
SVNUrl url = client.getSvnUrl();
144         String JavaDoc hostString = SvnUtils.ripUserFromHost(url.getHost());
145         String JavaDoc realmString = url.getProtocol() + "://" + hostString + ":" + url.getPort(); // NOI18N
146
File JavaDoc certFile = CertificateFile.getSystemCertFile(realmString);
147         File JavaDoc nbCertFile = CertificateFile.getNBCertFile(realmString);
148         if( !nbCertFile.exists() && certFile.exists() ) {
149             FileUtils.copyFile(certFile, CertificateFile.getNBCertFile(realmString));
150             return true;
151         }
152
153         // otherwise try to retrieve the certificate from the server ...
154
TrustManager[] trust = new TrustManager[] {
155             new X509TrustManager() {
156                 public X509Certificate JavaDoc[] getAcceptedIssuers() { return null; }
157                 public void checkClientTrusted(X509Certificate JavaDoc[] certs, String JavaDoc authType) { }
158                 public void checkServerTrusted(X509Certificate JavaDoc[] certs, String JavaDoc authType) { }
159             }
160         };
161
162         SSLContext context = null;
163         try {
164             context = SSLContext.getInstance("SSL"); // NOI18N
165
context.init(null, trust, null);
166         } catch (NoSuchAlgorithmException JavaDoc ex) {
167             ErrorManager.getDefault().notify(ex);
168             return false;
169         } catch (KeyManagementException JavaDoc ex) {
170             ErrorManager.getDefault().notify(ex);
171             return false;
172         }
173
174         SSLSocketFactory factory = context.getSocketFactory();
175         SSLSocket socket = null;
176         try {
177             socket = (SSLSocket) factory.createSocket(hostString, url.getPort());
178             socket.startHandshake();
179         } catch (IOException JavaDoc ex) {
180             throw ex;
181         }
182
183         X509Certificate JavaDoc cert = null;
184         java.security.cert.Certificate JavaDoc[] serverCerts = null;
185         try {
186             serverCerts = socket.getSession().getPeerCertificates();
187         } catch (SSLPeerUnverifiedException ex) {
188             ErrorManager.getDefault().notify(ex);
189             return false;
190         }
191         for (int i = 0; i < serverCerts.length; i++) {
192             Diagnostics.println("Cert[" + i + "] type - " + serverCerts[i].getType()); // NOI18N
193
if(serverCerts[i] instanceof X509Certificate JavaDoc) {
194                 cert = (X509Certificate JavaDoc) serverCerts[i];
195                 Diagnostics.println("Cert[" + i + "] - notAfter " + cert.getNotAfter()); // NOI18N
196
Diagnostics.println("Cert[" + i + "] - notBefore " + cert.getNotBefore()); // NOI18N
197
try {
198                     cert.checkValidity();
199                 } catch (CertificateExpiredException JavaDoc ex) {
200                     Diagnostics.println("Cert[" + i + "] - " + ex); // NOI18N
201
continue; // try to get the next one
202
} catch (CertificateNotYetValidException JavaDoc ex) {
203                     Diagnostics.println("Cert[" + i + "] - " + ex); // NOI18N
204
continue; // try to get the next one
205
}
206                 break;
207             }
208         }
209
210         AcceptCertificatePanel acceptCertificatePanel = new AcceptCertificatePanel();
211         acceptCertificatePanel.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(SvnClientExceptionHandler.class, "CTL_Error_CertFailed")); // NOI18N
212
acceptCertificatePanel.certificatePane.setText(getCertMessage(cert, hostString));
213         DialogDescriptor dialogDescriptor = new DialogDescriptor(acceptCertificatePanel, org.openide.util.NbBundle.getMessage(SvnClientExceptionHandler.class, "CTL_Error_CertFailed")); // NOI18N
214
Dialog JavaDoc dialog = DialogDisplayer.getDefault().createDialog(dialogDescriptor);
215         JButton JavaDoc permanentlyButton = new JButton JavaDoc(org.openide.util.NbBundle.getMessage(SvnClientExceptionHandler.class, "CTL_Cert_AcceptPermanently")); // NOI18N
216
JButton JavaDoc temporarilyButton = new JButton JavaDoc(org.openide.util.NbBundle.getMessage(SvnClientExceptionHandler.class, "CTL_Cert_AcceptTemp")); // NOI18N
217
JButton JavaDoc rejectButton = new JButton JavaDoc(org.openide.util.NbBundle.getMessage(SvnClientExceptionHandler.class, "CTL_Cert_Reject")); // NOI18N
218
dialogDescriptor.setOptions(new Object JavaDoc[] {permanentlyButton, temporarilyButton, rejectButton});
219
220         showDialog(dialogDescriptor);
221
222         if(dialogDescriptor.getValue()!=permanentlyButton && dialogDescriptor.getValue()!=temporarilyButton) {
223             return false;
224         }
225
226         CertificateFile cf = null;
227         try {
228             boolean temporarily = dialogDescriptor.getValue() == temporarilyButton;
229             cf = new CertificateFile(cert, url.getProtocol() + "://" + hostString + ":" + url.getPort(), getFailuresMask(), temporarily); // NOI18N
230
cf.store();
231         } catch (CertificateEncodingException JavaDoc ex) {
232             ErrorManager.getDefault().notify(ex);
233             return false;
234         } catch (IOException JavaDoc ex) {
235             ErrorManager.getDefault().notify(ex);
236             return false;
237         }
238             
239         return true;
240     }
241
242     private void showDialog(DialogDescriptor dialogDescriptor) {
243         dialogDescriptor.setModal(true);
244         dialogDescriptor.setHelpCtx(new HelpCtx(this.getClass()));
245         dialogDescriptor.setValid(false);
246
247         Dialog JavaDoc dialog = DialogDisplayer.getDefault().createDialog(dialogDescriptor);
248         dialog.setVisible(true);
249     }
250     
251     private void connectProxy(Socket JavaDoc tunnel, String JavaDoc host, int port, String JavaDoc proxyHost, int proxyPort) throws IOException JavaDoc {
252       
253       String JavaDoc connectString = "CONNECT "+ host + ":" + port + " HTTP/1.0\r\n" + "Connection: Keep-Alive\r\n\r\n"; // NOI18N
254

255       byte connectBytes[];
256       try {
257          connectBytes = connectString.getBytes(CHARSET_NAME);
258       } catch (UnsupportedEncodingException JavaDoc ignored) {
259          connectBytes = connectString.getBytes();
260       }
261       
262       OutputStream JavaDoc out = tunnel.getOutputStream();
263       out.write(connectBytes);
264       out.flush();
265
266       byte reply[] = new byte[200];
267       int replyLen = 0;
268       int newlinesSeen = 0;
269       boolean headerDone = false;
270       InputStream JavaDoc in = tunnel.getInputStream();
271       
272       while (newlinesSeen < 2) {
273          byte b = (byte) in.read();
274          if (b < 0) {
275             throw new IOException JavaDoc("Unexpected EOF from proxy"); // NOI18N
276
}
277          if (b == '\n') {
278             headerDone = true;
279             ++newlinesSeen;
280          } else if (b != '\r') {
281             newlinesSeen = 0;
282             if (!headerDone && replyLen < reply.length) {
283                reply[replyLen++] = b;
284             }
285          }
286       }
287
288       String JavaDoc ret = ""; // NOI18N
289
try {
290         ret = new String JavaDoc(reply, 0, replyLen, CHARSET_NAME);
291       } catch (UnsupportedEncodingException JavaDoc ignored) {
292         ret = new String JavaDoc(reply, 0, replyLen);
293       }
294         if (!isOKresponse(ret.toLowerCase())) {
295             throw new IOException JavaDoc("Unable to connect through proxy " // NOI18N
296
+ proxyHost + ":" + proxyPort // NOI18N
297
+ ". Proxy returns \"" + ret + "\""); // NOI18N
298
}
299    }
300     
301     private boolean isOKresponse(String JavaDoc ret) {
302         return ret.startsWith("http/1.1 200") || ret.startsWith("http/1.0 200"); // NOI18N
303
}
304
305     private String JavaDoc getCertMessage(X509Certificate JavaDoc cert, String JavaDoc host) {
306         CertificateFailure[] certFailures = getCertFailures();
307         Object JavaDoc[] param = new Object JavaDoc[6];
308         param[0] = host;
309         param[1] = cert.getNotBefore();
310         param[2] = cert.getNotAfter();
311         param[3] = cert.getIssuerDN().getName();
312         param[4] = getFingerprint(cert, "SHA1"); // NOI18N
313
param[5] = getFingerprint(cert, "MD5"); // NOI18N
314

315         String JavaDoc message = NbBundle.getMessage(SvnClientExceptionHandler.class, "MSG_BadCertificate", param); // NOI18N
316
for (int i = 0; i < certFailures.length; i++) {
317             message = certFailures[i].message + message;
318         }
319         return message;
320     }
321
322     private CertificateFailure[] getCertFailures() {
323         List JavaDoc<CertificateFailure> ret = new ArrayList JavaDoc<CertificateFailure>();
324         String JavaDoc exceptionMessage = getException().getMessage();
325         for (int i = 0; i < failures.length; i++) {
326             if(exceptionMessage.indexOf(failures[i].error) > -1) {
327                 ret.add(failures[i]);
328             }
329         }
330         return ret.toArray(new CertificateFailure[ret.size()]);
331     }
332    
333     private int getFailuresMask() {
334         CertificateFailure[] certFailures = getCertFailures();
335         if(certFailures.length == 0) {
336             return 15; // something went wrong, 15 should work for everything
337
}
338         int mask = 0;
339         for (int i = 0; i < certFailures.length; i++) {
340             mask |= certFailures[i].mask;
341         }
342         return mask;
343     }
344     
345     private String JavaDoc getFingerprint(X509Certificate JavaDoc cert, String JavaDoc alg) {
346         String JavaDoc str;
347         try {
348             str = new sun.misc.BASE64Encoder().encode(cert.getEncoded());
349             str = str.replace(NEWLINE, ""); // NOI18N
350
MessageDigest JavaDoc md5 = MessageDigest.getInstance(alg);
351             byte[] url = new sun.misc.BASE64Decoder().decodeBuffer(str);
352             md5.update(url);
353             byte[] md5digest = md5.digest();
354             String JavaDoc ret = ""; // NOI18N
355
for (int i = 0; i < md5digest.length; i++) {
356                 String JavaDoc hex = Integer.toHexString(md5digest[i] & 0x000000FF);
357                 if(hex.length()==1) {
358                     hex = "0" + hex; // NOI18N
359
}
360                 ret += hex + (i < md5digest.length - 1 ? ":" : ""); // NOI18N
361
}
362             return ret;
363         } catch (CertificateEncodingException JavaDoc ex) {
364             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); // should not happen
365
} catch (NoSuchAlgorithmException JavaDoc ex) {
366             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); // should not happen
367
} catch (IOException JavaDoc ex) {
368             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); // should not happen
369
}
370         return ""; // NOI18N
371
}
372     
373 }
374
Popular Tags