Apache, Tomcat, CAS and certified SSL for free on Linux.
Summary
I have previously had the following setup:
<Proxy balancer://tomcatservers>
BalancerMember ajp://localhost:8010 route=domainnameA retry=60
</Proxy>
<Location />
Allow From All
ProxyPass balancer://tomcatservers/ stickysession=JSESSIONID nofailover=off
</Location>
and then in the server.xml so that the <Engine> node reads:
<Engine name="Catalina" defaultHost="domainname.com" jvmRoute="domainnameA">
If you need more then you should consult Google for better instructions. Sorry, but others have already written about it and this post is to do with CAS and SSL and not Apache/Tomcat interaction.
which worked perfectly but recently I added an instance of Jasig's Central Authentication Service in there and setting up SSL became a magnificent pain in the arse. After several days work I think I now have a full proof way of getting this set up. A summary of the process goes as follows:
- Generate a certificate signing request;
- Create an account with cacert.org who will generate a certified and trusted SSL certificate for free;
- Install the SSL certificate on the Apache HTTP server;
- Translate the certificate into a Java Key Store format;
- Install the JKS format certificate into Tomcat;
- Import the SSL certificate into a new jssecacerts file;
- Install that jssecacerts file into the JVM;
- Finally restart the Apache and Tomcat servers.
I find Java such a long winded way of doing absolutely everything that I often wonder if I should have learned PHP rather than Java. I doubt that things could be as difficult to understand or to get working and I am fairly sure that PHP provides all of the facilities that I need in any website that I build. Well, enough of the moan, lets get started with this stupidly complex process.
First, you should create a directory to work in. Any directory in any location on your hard drive will do. Then set JAVA_HOME if you have not already done so:
JAVA_HOME=/opt/java
export JAVA_HOME
echo $JAVA_HOME
This should output /opt/java and means that you can now reference java by using $JAVA_HOME which is what I use below. The $JAVA_HOME folder may of course be something like /opt/jdk1.6.0_03, it simply depends on how you have things setup.
Generate a certificate signing request
There is nothing special in this. It is the standard way of generating an CSR for an Apache web server:
openssl genrsa -out domainname.key 1024
openssl req -new -key domainname.key -out domainname.csr
That should create a domainname.key and a domainname.csr file which is the file you need to generate the signed SSL certificate at cacert.org
Create an account with cacert.org
Go to cacert.org and open an account. You should then create a new server certificate for which you will be asked for the CSR that you generated in the previous step. You can open it in a text editor and then paste it into the box provided by cacert.org. They will then display your fully certified SSL file on the screen. You should then copy that into a new file called domainname.crt in the same directory as the CSR and the key file.
Install the SSL certificate on the Apache HTTP server
Again, there is nothing special about this as it is the same as installing any SSL certificate into Apache. Open your SSL VirtualHost and add the following:
SSLCertificateFile /etc/apache2/ssl-keys/domainname/domainname.crt
SSLCertificateKeyFile /etc/apache2/ssl-keys/domainname/domainname.key
You will need to change the file path to the location that you have stored your keys.
Translate the certificate into a Java Key Store format;
This is where the research got tricky. It turns out that Java needs the certificate file in a different format to the standard Open SSL format. I tried to use the standard format but it failed and so I had to find a way to convert the Open SSL certificate into a Java Key Store (JKS) format. Luckily I found this post that described the process. You need to do the following:
- Download the not-yet-commons-ssl-0.3.9.jar file into the same directory as your SSL certificate;
Run the following command:
sudo java -cp not-yet-commons-ssl-0.3.9.jar org.apache.commons.ssl.KeyStoreBuilder changeit domainaname.key domainname.crt
This will output a file called domainname.jks which is the file that Tomcat needs to start up with SSL. It contains a copy of the domainname.crt and the domainname.key files that are being used by Apache but in a format that Tomcat can use.
Install the JKS format certificate into Tomcat
Add this to your server.xml SSL Connector which by default uses port 8443. You may need to uncomment this node if it is a new install of SSL on Tomcat.
keystoreFile="/etc/apache2/ssl-keys/domainname/domainname.jks"
keystoreType="JKS"
Import the SSL certificate into a new jssecacerts file
Well, I don't know about you but I am getting pissed of with the level of complexity by now and we still haven't finished. It turns out that even though Tomcat now knows about the certificate and the certificates key the JVM doesn't! So, we need to install them into the JVM as well - this is getting pretty ridiculous if you ask me but that seems to be the way it is done. The correct way to install into the JVM is to create a new jssecacerts file:
sudo $JAVA_HOME/bin/keytool -import -keystore jssecacerts -alias domainname -file domainname.crt
This will ask you for a keystore password as it will be creating a new JKS. The default password used by keystores is changeit but you should change that so that it is secure.
Install that jssecacerts file into the JVM
Copy your newly created jssecacerts file to your $JAVA_HOME/jre/lib/security folder. That should give your JVM the knowledge that it has a key stored under the alias domainname.
Finally restart the Apache and Tomcat servers
Restart both your Apache and your Tomcat server. If everything works then you may now happily curse Java to hell and back for being ridiculous, you won't be the only one.
Adding another certificate to the jssecacerts file
If you have multiple SSL hosts on your server (using multiple IP addresses) then you may want to add a second key to the jssecacerts file. Luckily the jssecacerts file is a standard keystore and so you can use the keytool to import any additional certificates into it.
$JAVA_HOME/bin/keytool -import -alias anotherdomainname -file /etc/apache2/ssl-keys/anotherdomainname/anotherdomainname.crt -file $JAVA_HOME/jre/lib/security/jssecacerts
Using the jssecacerts file allows you to store your own keys away from the CA keys that are stored in the cacerts file. I find this a neater way of doing things but you could add your certificates directly to the cacerts file if you wanted.
20.07.2009 01:36 - Posted by doahh - Comments: 5 - Java

Comments:
You don't have to run Tomcat with SSL. We use CAS in production with Apache on the front end and Tomcat behind it with no problems at all.
It looks like you are making things more difficult than they need to be.
23.07.2009 01:20 - Posted by john smith - Permalink
Thanks for the information, I will bear that in mind next time I need to get it configured. I am pretty sure I was getting the:
javax.net.ssl.SSLHandshakeException
without having tomcat configured for SSL and running tomcat with SSL fixed it. Maybe it was something to do with the Spring Security making its callbacks over SSL that caused the problem and not the Apache, Tomcat interaction.
25.07.2009 04:08 - Posted by doahh - Permalink
You also aren't using real SSL certificates that are trusted by tomcat. If you were, you could skip a few steps. cacert.org signed certificates aren't trusted so this is causing some of the problems.
The fact that you are using non-trusted certificates is probably why you are getting the SSLHandshakeException.
29.12.2009 02:47 - Posted by John Smith - Permalink
My initially occasion in which to attend your trusty post ,I actually come across the weblog is definitely total of extremely and manner,and so happy for me.Additionally,say thanks to you for sharing the beneficial views to me.
08.05.2010 04:34 - Posted by Shox NZ - Permalink
I had the same error as you, but I just needed to import the web server's SSL certificate into the JVM keystore with something like
keytool -import -trustcacerts -file /etc/apache2/ssl/server.crt -alias <hostname> -keystore $JAVA_HOME/jre/lib/security/cacerts
07.10.2011 06:35 - Posted by Dominic Bevacqua - Permalink