I’ll quickly note here how to embbed a certificate in a store, to be used by the Apache HttpClient component in Java.
This can be useful if you want to call a Web Service within your Java code, via HTTPS requests and you only have (for dev / test purposes) a self-signed certificate. It will in this case not be trusted by default, and you will get an exception telling you that it was unable to find a path for the certificate to match.
1- The certificate & the setup
Get the certificate you installed on your remote server (personnally I’ve made a PKCS12 one) and also get the password of the certificate.
Store it into your Java project.
Here is our raw example class :
public class MyApplication { private static final String USER_AGENT = "My Application"; private static final String PATH = "https://localhost:8900/"; private final Logger log = LoggerFactory.getLogger(MyApplication.class); private HttpClient client; private URL url; private KeyStore keyStore; private HttpsURLConnection urlConnection;
}
Then, in your class, build a Constructor which will correctly initialize your HttpClient :
public MyApplication() { this.url = new URL(PATH); String password = "yourpassword"; this.keyStore = KeyStore.getInstance("pkcs12"); File cert = new File("src/main/resources/server.p12"); FileInputStream inputStream = null; if(cert.isFile()) inputStream = new FileInputStream(cert); char[] pass = password.toCharArray(); this.keyStore.load(inputStream, pass); }
By doing this, you create a KeyStore, but your certificate file into it, associated with the password. Next step is to provide a TrustManager and to add it your KeyStore :
String algorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm); trustManagerFactory.init(this.keyStore);
To finish, you’ll just have to create a SSLContext object and a SSLConnectionSocket to create the client :
SSLContext sslContext = SSLContext.getInstance("TLS"); if (sslContext != null) { if (trustManagerFactory != null) { sslContext.init(null, trustManagerFactory.getTrustManagers(), null); } } SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
The 2nd parameter of my SSLConnectionSocketFactory (ALLOW_ALL_HOSTNAME_VERIFIER) is only for test purposes, but when you have your certificate set up with the right hostname on the right server, you will not need it anymore. It will « bypass » the hostname match checker between cert and server. To test all that bunch on the localhost it may be required to put this option.
2- Make a call
Your HTTP Client is now ready to be used in a TLS context with your self-signed certificate, you will just have to write a query. Let’s take a POST request for our example, so write something like this in a class method :
public addCar(CarDTO car) { // do stuff String queryUrl = "api/car"; HttpPost request = new HttpPost(this.url + queryUrl); request.addHeader("User-Agent", USER_AGENT); HttpResponse response = this.client.execute(request); String message = ""; try { HttpEntity entity = response.getEntity(); InputStream stream = entity.getContent(); message = IOUtils.toString(stream); EntityUtils.consume(entity); } finally { return message; } }
USER_AGENT is a constant string representing the tool name which make the query (for instance, when it’s a web browser, user-agent is the name of this browser !). If everything goes well, you should now be able to send requests via HTTPS on your third party server ! 🙂