Monday, August 3, 2009

SSL on Tomcat, JBoss and command line client

Talking about a secure website, the first thing that comes to mind is SSL. For almost all the sites today, we do encounter a section in the website where the address bar turns yellow with a lock indicating that the data being transfered is being encrypted. That section can be a login screen or a transaction screen etc. In this post i've tried to put some steps to achieve the goal of securing a HelloWorldServlet (not much useful but the technique for this or a complex one shall be same).
In order to start with the process of securing your site, we need a certificate. You shall be able to get a valid certificate from a Certification Authority like Thwate, Verisign and many more. Here I shall use a self-signed certificate but the process shall be quite similar for the ones from a Certification Authority (CA).
First of all we create a Keystore using the keytool available in a JRE installation. You can look for it in JDK\bin or JRE\bin directory.
keytool -genkey -alias rsatest -keyalg RSA -keystore test_store -validity 60
Keep in mind while creating the keystore that the answer to the first question i.e. What is your first and last name? should be either your domain address or machine name (It should be the name by which your machine shall be referred in URL when clients are making hits to it using an HttpsURLConnection). This is the CN (Common Name).
After answering a number of self explanatory questions and providing an appropriate password, you shall see a file names test_store in your present working directory folder.
In the next step, you can create a certificate that shall be required by the client application to communicate with this machine using SSL.
keytool -export -alias rsatest -file rsatest.cer -keystore test_store
After executing this command, you shall see a rsatest.cer file created.
In order to start tomcat in https mode in addition to its default http mode, we need to modify the server.xml in the TOMCAT_HOME\CONF folder.
Paste the snippet below in server.xml.
 <Connector port="8443" minSpareThreads="5" maxSpareThreads="75" enableLookups="true" 
  disableUploadTimeout="true" acceptCount="100" maxThreads="200" scheme="https" secure="true" 
  SSLEnabled="true" keystoreFile="c:/certs/test_store" keystorePass="password" clientAuth="false" sslProtocol="TLS"/>
Replace the location of keystoreFile and the keystorePass with appropriate values.
In case of JBoss the process is quite similar to that of Tomcat. We need to edit JBOSS_HOME\server\default\deploy\jboss-web.deployer\server.xml instead and paste the below give snippet.
 <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
     maxThreads="150" scheme="https" secure="true"
     clientAuth="false" strategy="ms"
     address="${jboss.bind.address}"
     keystoreFile="C:/certs/test_store"
     keystorePass="password"
     sslProtocol="TLS"/>
Which ever server you choose to modify, after you are done with saving the server.xml file start the server. You should be able to make hits to the server url with https protocol on an appropriate port (8443 in our case). Expect to see some warning like There is a problem with this website's security certificate. on IE or localhost:8443 uses an invalid security certificate. on firefox for the reasons explained very well on that screen. This happens as ours is a self-signed certificate and not issued by a trusted certificate authority that the machine or the browsers certificate stores posses. These self signed shall be good enough for internal use or testing but for internet use you should get the certs from a trusted certificate authority.
Well, we are ready with our server running in https mode. For example purposes I had developed a very simple HelloWorldServlet. I am able to access via https://localhost:8443/WebAppDemo/HelloWorldServlet
Before we write the client code, we need to get the cert that we generated earlier. As we are on the same machine, you can re-use the trust store (for practice purposes) but in real environment (on a different machine), you shall create a new trust store and import the cert into it using the command given below:
keytool -import -alias rsatest -file rsatest.cer -keystore cacerts
The same command is used to import any ROOT certificates or the certs provided by a website that you want to connect using your java program.
With the above command we created a new keystore and imported the certificate into it. The client code is very simple i.e. a usual HttpUrlConnection code. A small snippet from my test class HelloWorld.java is given below:
  URL url = new URL("https://localhost:8443/WebAppDemo/HelloWorldServlet");
  URLConnection connection = url.openConnection();
Rest code is simple IO reading from stream hence skipping it.
The important part is are the VM arguments. If you have written a stand alone application, you shall run it using the following command:
c:\>java -Djavax.net.ssl.trustStore=c:/certs/cacerts -Djavax.net.ssl.trustStorePassword=password HelloWorld
One very important point is that in the URL the server machine should be refered by the name used in the CN while creating the keystore. So you need to use the domain name of the machine as the CN. It won't work otherwise. In my example using localhost is a bad practice but I feel you get the point and modify your codes according to the situation. The IP of the machine should not be used as a CN, so you have to use the domain name or the machine name as the CN for the cert. The same domain name or machine name (used in CN) should be used when accessing the URL or else you will encounter host name verification failure.

No comments:

Post a Comment