Apache, Tomcat and SSL

Its a popular thing to use Apache (or nginx, etc.) as a reverse-proxy server fronting Tomcat. However, documentation on such practices tends to gloss over certain important things. Specifically:

1. Who owns the SSL cert that manages such a configuration. Apache or Tomcat?

2. Is the Apache-to-Tomcat tunnel encrypted? If so, how?

I finally decided to determine by experimentation. Here’s the scoop:

1. Encryption between Apache and Tomcat is not supported by the AJP protocol. If you need back-end encryption, use Apache’s mod_proxy, not mod_ajp.

2. If you make an https connection to a website hosted by Apache or proxied by Apache to Tomcat, the cert that’s applied will be the (x509) cert for that Apache host. Not a Tomcat jks cert.

3. You can configure Apache to proxy incoming SSL traffic to Tomcat even though Tomcat  itself isn’t configured for SSL.  Simply forward from your Apache ProxyPass/ProxyPassReverse to the Tomcat http port (8080 by default).

Note If you forward SSL to Tomcat via its http port, then none of the traffic between Apache and Tomcat will be encrypted. That’s OK if you are doing a forward within the local machine (using loopback) or if you are OK with security on your LAN.

4. If clear-text between Apache and Tomcat is not acceptable, you can do SSL from Apache to Tomcat. In that case, Tomcat needs its own keystore and certs, independent of the Apache certs. Apache will decrypt incoming Internet traffic so that it can do whatever it needs to do with headers and rewrites, then re-encrypt the proxy data using Tomcat’s cert.

To do SSL between Apache and Tomcat, the ProxyPass/ProxyPassReverse directives should address Tomcat’s HTTPS port (8443). Presumably you can even take plain HTTP coming into Apache and SSL it to Tomcat, but I didn’t bother to check.

Note that between Apache and Tomcat, a self-signed cert is probably good enough. In fact, since the cert won’t be officially registered, it’s one less internal secret for people to learn on the Internet. Apache’s handling of the finer aspects of backend certs are tunable, but the defaults are sufficient for most purposes.

Tomcat ignores FORM based authentication, uses BASIC authentication

Here’s a week of my life down the drain. I’m setting up a new production site with Apache AJP fronting Tomcat and when the Tomcat webapp needs authentication, it ignores the FORM authentication directive, presenting a BASIC authentication dialog, instead!

I thought it had to do with AJP and SSL tunneling. It didn’t. I finally confirmed that by firing up a text-only browser (this is a remote hosting location with no GUI) and bypassing the firewall, Apache, AJP and everything but Tomcat itself.

The culprit turned out to be insidious. I was overriding an authentication option in order to fine-tune client caching. However, the examples I’d been pilfering from were using BASIC authentication, not FORM authentication. So when I added the config option, it was the Tomcat Valve for BasicAuthenticator.

Turns out that if you do that, the BasicAuthenticator silently takes over, overriding the FORM authentication configuration in web.xml.

The cure: use the FormAuthenticator Valve!

Making Apache mod_rewrite and the ajp Tomcat connector work together

Apache’s URL rewriting facility can be used to shape URLs piped to Tomcat, but it’s not as simple as it seems.

The basic action is straightforward. First incoming URLs are processed by mod_rewrite, then they are matched up against JkMount definitions to find the appropriate Tomcat connector to use.

The problem is, what Tomcat sees isn’t what you’d expect to have come out from the rewrite process.

What actually happens is that before being submitted to mod_rewrite, the incoming URL is converted to server-relative form. After rewriting, the resulting URL is then reassembled, including the parts that Tomcat doesn’t want or need. Including the Apache DocumentBase path.

To prevent this problem, just qualify the last rewrite rule in the process with the “PT” directive to let Apache know to “Pass Through” the URL without reassembly. So, for example:

RewriteRule ^/$ /mywebapp/index.jsp [L,PT]
JkMount /mywebapp/* ajp13

Eclipse: Tomcat FileNotFoundException

After happily using the sysdeo Tomcat plugin for years. I’ve finally been pushed into using the Server facility bundled into Eclipse Ganymede’s JEE drop. For some reason, once started, sysdeo cannot be stopped or restarted – it loses track of the logfile classes.

In theory, you just create a new server of your choice in the Eclipse Servers View. In practice, it’s not quite so simple. Here’s why:

Tomcat actually consists of 2 aspects: a sharable codebase (CATALINA_HOME) and a per-instance part (CATALINA_BASE). This allows multiple copies of Tomcat to run on a single server using one codebase. Most of the time, CATALINA_HOME and CATALINA_BASE are the same value, since more often than not, only one copy of a given version of Tomcat is is use – at least on a developer’s machine.

When you create a Tomcat server using the Eclipse Servers facility, however, it clandestinely creates its own CATALINA_BASE, copying selected files – and only those files into a directory owned by the plugin.

I got burned. I was keeping a file of my own in CATALINA_HOME and using a relative reference to it in server.xml. The file didn’t copy and Tomcat didn’t start clean.

The simplest solution was to edit server.xml and replace the relative path to an absolute path, so that the copied configuration would be able to locate the original (and in this case, the only) copy of my file.

Apparently, however, the copying of the CATALINA_BASE data occurs only when you create a new Server definition. I had to delete the old Server definition from Eclipse and create a new one to get the changes to take.

JSF/Facelets/RichFaces – and Maven

SF itself is fairly straightforward. Getting it functional in an appserver is another matter. Originally, I used MyFaces and Tomahawk. More recently, I’ve replaced MyFaces with the Sun JSF Reference Implementation (RI). Tomahawk, although a MyFaces library works just fine with the RI.

The JSF-impl jar is part of the server for JEE-compliant servers, such as recent versions of JBoss. For Tomcat, it has to be explicitly linked into the WAR (?). At any rate, it has to be put into the application’s classpath, and everyone seems to be putting it into the WAR and not the server lib directory. Since there are possible threading implications, I’m doing likewise.

Tomcat5 also needs the EL-ri JAR placed in its classpath. Tomcat6 includes the required classes as part of the base distribution.

For the whole set of dependencies, see the Maven POM for my sandbox project: here

OpenJPA/Spring/Tomcat6

Oh, what a tangled web we weave…

In theory, using JPA and Spring is supposed to make magical things happen that will make me more productive and allow me to accomplish wonderful things.

Someday. At the moment, I gain tons of productivity only to waste it when deployment time comes and I have to fight the variations in servers.

JPA allows coding apps using POJOs for data objects. You can then designate their persistence via external XML files or using Java Annotations. The Spring Framework handles a lot of the “grunt” work in terms of abstract connection to the data source, error handling and so forth.

But that, alas, is just the beginning.

First and foremost, I had to build and run using Java 1.5. OpenJPA 1.2 doesn’t support Java 6.

Tomcat is not a full J2EE stack. To serve up JPA in Tomcat requires a JPA service – I used Hibernate-entitymanager.

JPA requires a little help. Specifically, I used the InstrumentationLoadTimeWeaver to provide the services needed to process the annotations.

The weaver itself requires help. And to enable the weaver in Tomcat, I needed the spring-agent.

To the Tomcat6 lib directory I added:

  • spring-tomcat-weaver jar
  • spring-agent jar

But that’s not enough! The agent won’t turn itself on automatically. So I need to add a “-javaagent” to Tomcat’s startup. The easiest way to do that was to create a CATALINA_BASE/bin/setenv.sh file:

#!/bin/sh
CATALINA_BASE=/usr/local/apache-tomcat-6.0.18
JAVA_OPTS=”-javaagent:$CATALINA_BASE/lib/spring-agent-2.5.4.jar”

Tomcat 5

I think this all works more or less the same in Tomcat5, except that there are 3 library directories instead of the one library that Tomcat6 uses so the location for the spring suport jars is different. common/lib seems to work, although I’m not sure it’s the best choice.

That’s half the battle. Next up: JSF/RichFaces – and Maven