For something like a week now I've been trying to read SSL Client Certificate information using:
Apache 2.0.44, Tomcat 4.1.18, mod_jk built from the connectors-4.1.18 package and the mod_ssl that comes with the 2.0.44 source distribution. I have finally got things working in my environment in a satisfactory way, and I thought I'd take a minute to post to the list some of what I learned.

Thanks to all of you who responded to my requests for help. Most of the reponses were helpful and all were appreciated.

First of all, I never could get mod_jk2 to pass SSL environment variables between Apache and Tomcat. The only one that ever seemed to get through was "javax.servlet.request.cipher_suite". After a couple of frustrating days, I gave up on mod_jk2 and went back to mod_jk. (If anybody knows how to make this work with mod_jk2, I'd still like to hear about it.) I set this up according to the excellent instructions at:

http://jakarta.apache.org/tomcat/tomcat-3.2-doc/tomcat-ssl-howto.html

In my httpd.conf file, I put the following directives in the global area:
### instruct mod_jk to play nicely with mod_ssl ##
<IfModule mod_jk.c>
JkExtractSSL On
JkHTTPSIndicator HTTPS
JkSESSIONIndicator SSL_SESSION_ID
JkCIPHERIndicator SSL_CIPHER
JkCERTSIndicator SSL_CLIENT_CERT
</IfModule>

and in the VirtualHost section that controls the Tomcat context from which I wish to read client certificate data:
<Location /safe>
SSLOptions +FakeBasicAuth +ExportCertData +StdEnvVars
SSLVerifyClient require
SSLVerifyDepth 1
SSLRequireSSL
</Location>

Obviously, you should substitute your context name where I have "safe".

Once Apache, Tomcat and mod_jk were all properly configured and playing nicely with one another, the next challenge was to write some java code in a servlet to get to the client certificate information. This proved to be pretty easy, except for one avoidable blunder that I'll talk about in a minute. Here's a code snippet that works for me:

....
import java.security.cert.*;
....
try {
Object o = request.getAttribute(
"javax.servlet.request.X509Certificate");
if (o != null) {
X509Certificate certs[] = (X509Certificate[])o;
X509Certificate cert = certs[0];
// Get the Distinguished Name for the user.
String n = cert.getSubjectDN().getName();
}
else
out.println = "Object was null.";
}
catch (Exception exc) {
out.println = exc.toString();
}
....

Nothing to it. Except that now I want to rant for a bit. The Servlet 2.3 specification says (in SRV.4.7):

....If there is an SSL certificate associated with the request, it must be exposed by the servlet container to the servlet programmer as an array of objects of type java.security.cert.X509Certificate and accessible via a ServletRequest attribute of javax.servlet.request.X509Certificate...

Now, I KNOW it's my fault for not reading carefully, but I spent hours trying to figure out why I was getting a ClassCast Exception for trying to cast the request attribute object to "javax.security.cert.X509Certificate[]". (The problem, in case it has escaped you as it did me for so long, is that I used "javax" instead of "java".) My mistake would have been a lot more transparent if not for the fact that there does exist a class named "javax.security.cert.X509Certificate". Now, I suppose there's a good reason for this but, damn, do we really need to have 2 X509Certificate classes, one in the java.security.cert package and the other in the javax.security.cert package? Yikes.

Anyway, I hope this synopsis is of some value. And thanks again to all those who tried to help me.

Robert Dana


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to