Apache, Tomcat, CAS and certified SSL for free on Linux.

Tags:

Summary

Normally for Apache fronted by Tomcat you only need Apache to have an SSL certificate installed but if you are using CAS then it will require that you run under SSL or it will not work. Hence both Apache and Tomcat must be SSL enabled. The difference between the SSl formats of OpenSSL (as used by Apache) and the Java key Store (JKS) is what caused me some problems.

I have previously had the following setup:

browser => apache (ssl enabled) => tomcat (non-ssl enabled) => back through apache => back to the browser
IMPORTANT: I had several errors while using mod_jk and so I switched to using mod_proxy_ajp instead. I used this in my Apache VirtualHost:

<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:

  1. Generate a certificate signing request;
  2. Create an account with cacert.org who will generate a certified and trusted SSL certificate for free;
  3. Install the SSL certificate on the Apache HTTP server;
  4. Translate the certificate into a Java Key Store format;
  5. Install the JKS format certificate into Tomcat;
  6. Import the SSL certificate into a new jssecacerts file;
  7. Install that jssecacerts file into the JVM;
  8. 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:

  1. 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.

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.

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.

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.

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.

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

Post a Comment:

HTML Syntax: Allowed