Reputation: 793
I am writing a routine to access a remote server. This server I am connecting to requires mutual authentication so I have to provide a keystore, and while I'm at it I'd like to put a proper truststore in place as well.
I can find plenty of tutorials on how to create a keystore with keytool
and multiple ways to get an Apache HTTP client to recognize it, but not where to store it in a Tomcat environment so that the application can find it. Somehow putting it in the application's war file seems like a bad idea to me.
Again, this is not to permit Tomcat to handle inbound https connections - I have a reverse proxy set up by our admin team for that. I'm creating outgoing https connections that require mutual authentication, i.e., both accepting a self-signed destination server certificate, and providing my server's self-signed client certificate.
Where do you store the actual keystore and truststore files in a Tomcat environment for use by a web application?
Upvotes: 5
Views: 6941
Reputation: 27583
This is basically a comment to Christopher Schultz's answer, but since it involves some code snippets please excuse my putting it here
It's unfortunate that httpclient doesn't have a simple API like "here's the path to my keystore file, now use it" or "here are the bytes for my keystore, use those" (if you wanted to load the keystore from the ClassLoader or whatever), but that seems to be the case
This is how one can configure Apache HttpClient 4.3 to use a specific trust store for SSL context initialization.
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(trustStore)
.build();
CloseableHttpClient client = HttpClients.custom()
.setSslcontext(sslContext)
.build();
One can load trust material from a resource like that
URL resource = getClass().getResource("/com/mycompany/mystuff/my.truststore");
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream inputStream = resource.openStream();
try {
trustStore.load(inputStream, null /*usually not password protected*/);
} finally {
inputStream.close();
}
Upvotes: 1
Reputation: 20862
You can put your keystore wherever you want, as long as you know how to tell httpclient
where to load the keystore.
That, of course, is the trick.
Using Apache httpclient for https
Buried in all that mess of code in the accepted answer is the key (ha!) to using httpclient
with your own custom keystore. It's unfortunate that httpclient
doesn't have a simple API like "here's the path to my keystore file, now use it" or "here are the bytes for my keystore, use those" (if you wanted to load the keystore from the ClassLoader or whatever), but that seems to be the case.
The honest truth is that using keystores and truststores in Java is messy business, and there's usually no way around it. Having written a client-cert-capable HTTP client myself using nothing other than HttpsURLConnection and then also adding raw-socket components to that, I know how painful it is.
The code in the above-linked article is fairly straightforward if a bit verbose. Unfortunately, you're going to need to make it a lot messier for production-quality code because you've got to do error-checking, etc. for every step of the process to make sure your service doesn't fall-over when you are trying to set up the various stores and make your connection.
Upvotes: 5