Overview
This blog post discusses how to enable SSL and client authentication in Tomcat 9.
A sample REST application
This post will make use of a Book API web application deployed on Tomcat to demonstrate how SSL and client auth can be used to access the books API.
Pre-requisites
- JDK 8
- Download Tomcat 9
- Download the Books API source code.
- OpenSSL (Windows version can be downloaded here.
Build the Books API application
Unzip the books-api-src.zip file to any folder. Build the source code using an IDE like IDEA IntelliJ or using Maven
When done correctly, you should get a books.war files generated in the taget directory.Deploy the books application
Copy the books.war file to Tomcat's webapp directory. You should then be able to access the API using a url like http://localhost:8080/books/api/books.
At this point Tomcat is not using SSL.Enabling SSL on Tomcat
Open a command prompt, change the directory to the conf folder of Tomcat. First thing to do is create a self-signed certificate for our server.
keytool -genkeypair -alias server -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore server.p12 -validity 3650 -ext SAN=dns:localhost,ip:127.0.0.1 -dname "CN=localhost" -storepass changeit
The next step is to edit the server.xml present in Tomcat's conf folder to enable SSL:
<Connector protocol="org.apache.coyote.http11.Http11NioProtocol" port="8443" maxThreads="200" maxParameterCount="1000" scheme="https" secure="true" SSLEnabled="true" keystoreFile="conf/server.p12" keystorePass="changeit" clientAuth="false" sslProtocol="TLS" />
Restart tomcat. Tomcat is not ready to accept SSL traffic on port 8443. We can now access the api at https://localhost:8443/books/api/books. The same can be done using curl:
curl https://localhost:8443/books/api/books -k
We should get a response like:
[{"id":1,"title":"IT","author":"Stephen King","cost":300.0},{"id":2,"title":"Different Seasons","author":"Stephen King","cost":250.0},{"id":3,"title":"Robot Dreams","author":"Isaac Asimov","cost":450.0},{"id":4,"title":"I, Robot","author":"Isaac Asimov","cost":350.0}]
Enabling certificate based client authentication
By enabling client authentication we force any client connecting to Tomcat to present a certificate which is trusted by the server. Any client failing to do so is not allowed to connect. To enable this, we need to do a couple of things.
Let's first create a self-signed client certificate:
keytool -genkeypair -alias client -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore client.p12 -validity 3650 -ext SAN=dns:localhost,ip:127.0.0.1 -dname "CN=localhost" -storepass changeit
Next, create a public certificate from the client's certificate:
keytool -export -alias client -file client.crt -keystore client.p12 -storepass changeit
Next, we create a truststore for our server, this is where client certificates which Tomcat will trust will be stored.
keytool -import -alias client -file client.crt -keystore truststore.p12 -storepass changeit -noprompt
Next step is to import the client's certificate into the truststore:
keytool -import -alias client -file client.crt -keystore truststore.p12 -storepass changeit -noprompt
We now need to reconfigure Tomcat to use the truststore. Edit the server.xml file to have the following content for the SSL connector:
<Connector protocol="org.apache.coyote.http11.Http11NioProtocol" port="8443" maxThreads="200" maxParameterCount="1000" scheme="https" secure="true" SSLEnabled="true" keystoreFile="conf/server.p12" keystorePass="changeit" clientAuth="true" sslProtocol="TLS" truststoreFile="conf/truststore.p12" truststorePass="changeit" />
Restart Tomcat. If we try to access the API using curl:
curl https://localhost:8443/books/api/books -k
We get an error:
curl: (35) schannel: next InitializeSecurityContext failed: SEC_E_CERT_UNKNOWN (0x80090327) - An unknown error occurred while processing the certificate.
So, we are required to pass a client certificate. We do this by using the following command:
curl https://localhost:8443/books/api/books --cert client.p12:changeit -k
And .. we get the response from the API:
[{"id":1,"title":"IT","author":"Stephen King","cost":300.0},{"id":2,"title":"Different Seasons","author":"Stephen King","cost":250.0},{"id":3,"title":"Robot Dreams","author":"Isaac Asimov","cost":450.0},{"id":4,"title":"I, Robot","author":"Isaac Asimov","cost":350.0}]
Hope this post was useful, until next time ... Bye!