How to setup Tomcat as a foaf+ssl server

foaf+ssl is a standards based protocol enabling one click identification/authentication to web sites, without requiring the user to enter either a username or a password. It can be used as a global distributed access control mechanism. It works with current browsers. It is RESTful, thereby working with Linked Data and especially linked foaf files, enabling thereby distributed social networks.

I will show here what is needed to get foaf+ssl working for Tomcat 6x. The general principles are documented on the Tomcat ssl howto page, which should be used for detailed reference. Here I will document the precise setup needed for foaf+ssl. If you want to play with this protocol quickly without bothering with this procedure I recommend using the foaf+ssl Identity Provider service which you can point to on your web pages, and which will then redirect your users to the service of your choosing with the URLEncoded WebId of your visitor.

foaf+ssl works by having the server request a client certificate on an https connection. The server therefore needs an https end point which can be specified in Tomcat by adding the following connector to the conf/server.xml file:

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
           maxThreads="50" scheme="https" secure="true"
           sslProtocol="TLS"/>
Note: the default https port is 443, but it requires root privileges.

Servers authentify themselves by sending the client a certificate signed by a well known Certificate Authority (CA) whose public key is shipped in all browsers. Browsers use the public key to verify the signature sent by the server. If the server sends a certificate that is not signed by one of these CAs (perhaps it is self signed) then the web browser will usually display some pretty ugly error message, warning the user to stay clear of that site, with some complex way of bypassing the warning, which if the user is courageous and knowledgeable enough will allow him to add the certificate to a list of trusted certs. This warning will put most people off. It is best therefore to buy a CA certified cert.(I found one for €15 at trustico.) Usually the CA's will have very detailed instructions for installing the cert for a wide range of servers. In the case of Tomcat you will end up with the following addition property values:

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
           maxThreads="50" scheme="https" secure="true"
           keystoreFile="conf/yourServerCert.kdb" 
               keystoreType="JKS" keystorePass="changeme" 
           sslProtocol="TLS"/>

And of course this requires placing the server cert file at the keystoreFile path.

There are usually two ways for the server to respond to the client not sending a (valid) certificate. Either it can simply fail, or it can allow the server app to decide what to do. Automatic failure is not a good option, especially for a login service, as the user will then be confronted with a blank page. Much better is to allow the server to redirect the user to another page explaining how to get a certificate and giving him the option of authentication using OpenId or simply the well known username/password pattern. To enable Tomcat to respond this way you need to add the clientAuth="want" attribute value pair:

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
           maxThreads="50" scheme="https" secure="true"
           keystoreFile="conf/yourServerCert.kdb" 
               keystoreType="JKS" keystorePass="changeme" 
           sslProtocol="TLS" clientAuth="want" />

Most Java Web Servers on receiving a client certificate, attempt to automatically validate it, by verifying that it is correctly signed by one of the CA's shipped with the Java Runtime Environment (JRE), verifying that the cert is still valid, ... As the SSL library that ships with the JRE does not implement foaf+ssl we will need to do the authentication at the application layer. We therefore need to bypass the SSL Implementation. To do this Bruno Harbulot put together the JSSLUtils library available on Google Code. As mentioned in the JSSLUtils Tomcat documentation page this will require you to place two jars in the Tomcat lib directory: jsslutils-0.5.1.jar and jsslutils-extra-apachetomcat6-0.5.2.jar (the version numbers may differ as the library evolves). You will also need to specify the SSLImplementation in the conf file as follows:

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
           maxThreads="50" scheme="https" secure="true"
           keystoreFile="conf/yourServerCert.kdb" 
               keystoreType="JKS" keystorePass="changeme" 
           SSLImplementation="org.jsslutils.extra.apachetomcat6.JSSLutilsImplementation" 
           sslProtocol="TLS" clientAuth="want" />

Usually servers send in the request to the client a list of Distinguished Names of certificates authorities (CA) they trust, so that the client can filter from the certificates available in the browser those that match. Getting client certificates signed by CA's is a complex and expensive procedure, which in part explains why requesting client certificates is very rarely used: very few people have certificates signed by well known CAs. Instead those services that rely on client certificate tend to sign those certificates themselves, becoming their own CA. This means that certificates end up being valid for only one domain. foaf+ssl bypasses this problem by accepting certificates signed by any CA, going so far as to allow even self signed certs. The server must therefore send an empty list of CAs meaning that the browser can send any certificate (TLS 1.1). With the JSSLutils library available to Tomcat, this is specified in the conf/server.xml file with the acceptAnyCert=true attribute.

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
           maxThreads="50" scheme="https" secure="true"
           keystoreFile="conf/yourServerCert.kdb" 
               keystoreType="JKS" keystorePass="changeme" 
           SSLImplementation="org.jsslutils.extra.apachetomcat6.JSSLutilsImplementation"
           acceptAnyCert="true" sslProtocol="TLS" clientAuth="want" />

At this point you have set up your Apache Server correctly. A user that arrives at your SSL endpoint and that has a couple of certificates will be asked to choose between them. Your client code can the extract the certificate with the following code:

       X509Certificate[] certificates = (X509Certificate[]) request
                       .getAttribute("javax.servlet.request.X509Certificate");

You can use these certificates then to extract the WebId, and verify the SSL certificates. I will write more about how to do this in my next blog post.

Comments:

For instructions on how to do the same with JBoss AS 4.2.3 see Stephanie Stroka's blog entry
http://stexx.wordpress.com/2009/07/24/client-certificate-authentication-with-jboss-as-4-2-3/

Posted by Henry Story on July 25, 2009 at 05:36 AM CEST #

Note: Stephanie found that she needed the two extra attribute value pairs

truststoreFile="/usr/lib/jvm/java-6-sun-1.6.0.10/jre/lib/security/cacerts"
truststorePass="changeit"

I also use those in my current server. In this blog I did not include them because Bruno told me that they were not needed. I did not myself test that statement unlike Stephanie. If the above does not work try adding the correct values for them, and please let me know.

Posted by Henry Story on July 27, 2009 at 04:18 PM CEST #

"As the SSL library that ships with the JRE does not implement foaf+ssl we will need to do the authentication at the application layer. We therefore need to bypass the SSL Implementation. "

The configuration does not bypass the SSL implementation, it merely changes the policies implemneted by the layer 7 element of one of the server's https endpoints. The layer 4 element still performs the SSL handshake over the SSL record layer, as normal. At the layer 7 entity, this configuration does allow one now to control the signaling of the trust requirements (for the server-side of the handshake) and one does get to validates the inbound client certificate [chain] (for PKI-enabled SSL ciphersuites).

Quite properly, one can set these policies to anything the problem domain requires. There is nothing standard or set by "virtue of consensus" in tomcat or Java JDK.

Posted by peter williams on September 08, 2009 at 04:52 PM CEST #

Post a Comment:
Comments are closed for this entry.
About

bblfish

Search

Archives
« April 2014
MonTueWedThuFriSatSun
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today