2011. július 14., csütörtök

Getting Lightstreamer v3 up and running with SSL support

or how to deal with "Unrecognized SSL message, plaintext connection?" and "Received fatal alert: bad_certificate" errors.

This description supposes that you already have Lightstreamer up and running using unencrypted http connections. In my case, I am using an HTML+Javascript client to connect to Lightstreamer v3 Evaluation version. The client part is deployed on a web server, both the client and LS push data are served from the same machine, using different names (for example ls.example.com:8080 and project.example.com:80, this is a requirement with Lightstreamer if running on a single machine).

Edit: First of all, if you want to use SSL (https) with Lightstreamer v3, you need the Vivace edition. You can get it by downloading not the free version (Moderato), but the evaluation version of the retail product. You have to request and eval licence, this one will work for 60 days. You don't get a lic file, as with Moderato, you are only sent a client ID, which you will need to put into lightstreamer_conf.xml. Also in lightstreamer_conf.xml, you have to set which edition you want to evaluate, use Vivace.

To set up Lightstreamer to use SSL, you need to edit lightstreamer_conf.xml and uncomment the section https_server. If you don't have a section called https_server, you are using the wrong edition, see above. Don't forget to set the port number. If you are using a single machine/IP to serve both the Javascript and HTML Lightstreamer client and the Lightstreamer push data, remember to use 2 different ports. I use 443 to serve client pages via apache2 and mod_ssl and 8443 to serve Lightstreamer push data.

After saving the config and restarting Lightstreamer, it should run an https service on port 8443
14.Jul.11 17:09:08,941 < INFO> SSL Server "Lightstreamer HTTPS Server" listening to *:8443 ...
14.Jul.11 17:09:08,944 < INFO> Server "Lightstreamer HTTP Server" listening to *:8080 ...
Note: I have left the unencrypted http service running too for testing, it can be removed/commented out of the config file.

For SSL to work using the HTML Lightstreamer client you need to make sure the Master Push page is loaded via https. Put it simply, the client HTML page displaying LS data needs to use https too.

You will also have to setup the Javascript client to connect to the right port number, for example by using:

lsEngine.connection.setLSPort("8443")

around the engine initialization code.

If you are connecting to the https service of Lightstreamer from a page loaded via http, you will get no data displayed and the following error on the server console:

14.Jul.11 17:18:56,776 Handshake error on Lightstreamer HTTPS Server
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
at com.sun.net.ssl.internal.ssl.EngineInputRecord.bytesInCompletePacket(EngineInputRecord.java:152)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:798)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:713)
at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:607)
at com.lightstreamer.e.a.t.a(t.java)
at com.lightstreamer.e.a.m.a(m.java)
at com.lightstreamer.e.a.a.g.b(g.java)
at com.lightstreamer.e.a.a.n.e(n.java)
at com.lightstreamer.e.a.a.n.run(n.java)

So to get the client HTML via https, I have set up apache2 SSL. As I am using Ubuntu 10.04 this is not too difficult.

Make sure you have mod_ssl installed (which I already had) and enable it:

sudo a2enmod ssl

Then enable the default-ssl site:

sudo a2ensite default-ssl

And reload apache:

sudo /etc/init.d/apache2 restart

If all is well, you should be able to access the default apache site using https.

Now all you need to do, is copy default-ssl to yoursite-ssl and modify it using settings from your non https config (DocumentRoot, logs, htaccess and the like).

When done, disable the default-ssl site:

sudo a2dissite default-ssl

and enable your ssl site config:

sudo a2ensite yoursite-ssl

Reload apache configs:

sudo /etc/init.d/apache2 reload

All done. Loading your URL via https should display your virtual site now.

Notice that we are using self-signed ssl certificates: the default ones that came with Lightstreamer (preset in the config, uncomment if necessary) and the apache2 default ones.

Now your client client page is using https and loading fine, but it may still not connect to Lightstreamer.

On the server console, I found this exception:
14.Jul.11 17:19:14,833 Handshake error on Lightstreamer HTTPS Server
javax.net.ssl.SSLException: Received fatal alert: bad_certificate
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:190)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1429)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1397)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1563)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:1023)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:837)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:713)
at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:607)
at com.lightstreamer.e.a.t.a(t.java)
at com.lightstreamer.e.a.m.a(m.java)
at com.lightstreamer.e.a.a.g.b(g.java)
at com.lightstreamer.e.a.a.n.e(n.java)
at com.lightstreamer.e.a.a.n.run(n.java)
Remember, we are using self-signed certificates? The solution is to open the LS page in the browser by going to the push page URL and port 8443 and check in your browser that you fully understand the security risks of browsing your own test site.

After doing this, it magically started to work as it should.