Reputation: 205
I am currently able to access a web service that requires a client certificate using the following curl command:
curl -k -v --cert ./certificate.pem https://api.com/unit
How do I make this request in a Java application?
Notice that I need the -k flag which allows curl to make "insecure" SSL connections. This needs to be done in the Java application as well.
Upvotes: 2
Views: 9453
Reputation: 205
The solution to this problem was to include the server's certificates in the Java trust store.
To download and import the above certificates of the server I used InstallCert Java code from GitHub.
The keyStore
and trustStore
were then defined in system properties like below:
-Djavax.net.ssl.keyStore=/home/wildfly/key.pfx
-Djavax.net.ssl.keyStorePassword=xxxx
-Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/cacerts
-Djavax.net.ssl.trustStorePassword=xxxx
-Djavax.net.ssl.keyStoreType=PKCS12"
Upvotes: 0
Reputation: 391
The code below provides a "sendSSLRequest" method that sends an HTTP GET request with client SSL authentication.
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.client.methods.HttpGet;
public class SSLExample {
private final static String ENDPOINT_URL = "https://api.com/unit";
public void sendSSLRequest() {
final SSLContext sslContext = SSLContextLoader.initSSLContext();
final HttpClient client = HttpClients.custom()
.setSSLContext(sslContext)
.build();
final HttpGet request = new HttpGet(ENDPOINT_URL);
try {
client.execute(request);
} catch (final IOException e) {
//do some exception handling...
}
}
}
Now, the SSLContext: you need to initialize it somewhere. The "initSSLContext" method below will load key material from a given keystore, and trust material (certificates that are to be trusted) from a given truststore.
public class SSLContextLoader {
private final static String clientKeyStorePath = "/path/to/client/keystore";
private final static String trustStorePath = "/path/to/truststore";
private final static String clientKeyStorePassword = "/password/for/client/keystore";
private final static String trustStorePassword = "/password/for/truststore";
private final static String keyPassword = "/passphrase/for/private/key";
public static SSLContext initSSLContext () {
try {
final KeyStore clientKeystore = KeyStore.getInstance("JKS");
clientKeystore.load(new FileInputStream(clientKeyStorePath), clientKeyStorePassword.toCharArray());
final KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream(trustStorePath), trustStorePassword.toCharArray());
final SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(trustStore, null)
.loadKeyMaterial(clientKeystore, keyPassword.toCharArray())
.build();
return sslContext;
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return null;
}
}
Regarding the -k option, I invite you to have a look at the following question/answer: Trusting all certificates using HttpClient over HTTPS.
Upvotes: 1