SSL and Self Signed Certs
Connecting to web servers over https that have self signed certificates has always been a hassle in Swing applications. Hopefully, with some recently added code and API in the SwingX-WS project this is no longer the case.
I don't know about you, but I don't have the $$ to shell out for a real certificate for my own home-run webserver. That, or I'm too lazy to do it, I'm not sure which. But in either case, test servers are often setup that don't have a real SSL certificate, such as Verisign or Thawte might sell. Instead, they have self-signed certificates. Glassfish, for instance, has such a certificate. It is easy enough to enable SSL in Glassfish, but expensive to use a real certificate.
Web browsers typically don't have a problem connecting to web servers that have self-signed certs. At least, Safari doesn't complain. It simply shows a dialog indicating that the domain the browser is connecting to has a self signed cert, and asks the user whether they want to continue. Nice.
Java, on the other hand, by default won't deal with self-signed certs. Period. You also get a very unfriendly error:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed
It turns out, you need to write your own X509TrustManager, and this is well documented. Just such a pain that I suspect most folks simply use http and hope they don't get into trouble (or just use http since they are on internal networks).
SwingX-WS uses HttpClient behind the scenes for all work with HTTP, and as it turns out, HttpClient has support for installing new secure socket factories -- which is a good thing because I'm gonna need one of those guys in order to use my X509TrustManager. [note: An X509TrustManager can be made the default VM-wide, but you need security rights. The other approach is to install the X509TrustManager on each HttpConnection, which does not require any extra priviledges. I use this approach so I don't have problems with webstart].
Enough theory, here's the practice.:
Session s = new Session();
Response r = s.get("https://myselfsigneddomain.com");
This code sample works exactly like Safari (and I assume the other browsers). It encounters a valid self signed cert and instead of bombing with an esoteric error message, it prompts the user. Cool!
Session now sports a couple new properties that help in this process:
- sslSecurityLevel: Can be one of SecurityLevel.High, SecurityLevel.Medium, or SecurityLevel.Low. High security will act the same as Java has always acted -- simply fail if a valid certificate doesn't exist (self-signed won't work here!). Medium security is the default, and this level will prompt the user. Low security won't prompt the user if it encounters a self-signed cert, it will simply accept it. Do not use the Low security level in production applications. You will expose yourself to security vulnerabilities!
- mediumSecurityHandler: Allows you to specify a SecurityHandler. SecurityHandler is an interface with one method:
public boolean isServerSecure(String host, X509Certificate cert);. This allows you to customize the way you ask the user whether a self-signed cert should be accepted or not.
And that's it. So, go to and write a bunch of web-oriented secure Swing applications!
PS: Hopefully this all actually works :-). I've tested it, but sure has some bugs. Among which include internationalization. If anybody wants to submit patches, let me know!