Learn how to make HTTPS calls from AEM to web APIs using private or self-signed certificates.
By default when trying to make an HTTPS connection to a web API that uses a self-signed certificate, the connection fails with the error:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
This issue typically occurs when the API’s SSL certificate is not issued by a recognized certificate authority (CA) and Java™ application cannot validate SSL/TLS certificate.
Let’s learn how to successfully call APIs that have private or self-signed certificates by using Apache HttpClient and AEM’s global TrustStore.
The following code makes an HTTPS connection to a web API:
...
String API_ENDPOINT = "https://example.com";
// Create HttpClientBuilder
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
// Create HttpClient
CloseableHttpClient httpClient = httpClientBuilder.build();
// Invoke API
CloseableHttpResponse closeableHttpResponse = httpClient.execute(new HttpGet(API_ENDPOINT));
// Code that reads response code and body from the 'closeableHttpResponse' object
...
The code uses the Apache HttpComponent’s HttpClient library classes and their methods.
To call an API endpoint that has private or self-signed certificate, the HttpClient’s SSLContextBuilder
must be loaded with AEM’s TrustStore, and used to faciliate the connection.
Follow the below steps:
Login to AEM Author as an administrator.
Navigate to AEM Author > Tools > Security > Trust Store, and open the Global Trust Store. If accessing first time, set a password for the Global Trust Store.
To import a private certificate, click Select Certificate File button and select desired certificate file with .cer
extension. Import it by clicking Submit button.
Update Java™ code like below. Note that to use @Reference
to get AEM’s KeyStoreService
the calling code must be an OSGi component/service, or a Sling Model (and @OsgiService
is used there).
...
// Get AEM's KeyStoreService reference
@Reference
private com.adobe.granite.keystore.KeyStoreService keyStoreService;
...
// Get AEM TrustStore using KeyStoreService
KeyStore aemTrustStore = getAEMTrustStore(keyStoreService, resourceResolver);
if (aemTrustStore != null) {
// Create SSL Context
SSLContextBuilder sslbuilder = new SSLContextBuilder();
// Load AEM TrustStore material into above SSL Context
sslbuilder.loadTrustMaterial(aemTrustStore, null);
// Create SSL Connection Socket using above SSL Context
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslbuilder.build(), NoopHostnameVerifier.INSTANCE);
// Create HttpClientBuilder
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setSSLSocketFactory(sslsf);
// Create HttpClient
CloseableHttpClient httpClient = httpClientBuilder.build();
// Invoke API
closeableHttpResponse = httpClient.execute(new HttpGet(API_ENDPOINT));
// Code that reads response code and body from the 'closeableHttpResponse' object
...
}
/**
*
* Returns the global AEM TrustStore
*
* @param keyStoreService OOTB OSGi service that makes AEM based KeyStore
* operations easy.
* @param resourceResolver
* @return
*/
private KeyStore getAEMTrustStore(KeyStoreService keyStoreService, ResourceResolver resourceResolver) {
// get AEM TrustStore from the KeyStoreService and ResourceResolver
KeyStore aemTrustStore = keyStoreService.getTrustStore(resourceResolver);
return aemTrustStore;
}
...
com.adobe.granite.keystore.KeyStoreService
OSGi service into your OSGi component.KeyStoreService
and ResourceResolver
, the getAEMTrustStore(...)
method does that.SSLContextBuilder
, see Java™ API details.SSLContextBuilder
using loadTrustMaterial(KeyStore truststore,TrustStrategy trustStrategy)
method.null
for TrustStrategy
in above method, it ensures that only AEM trusted certificates succeed during API execution.API calls with valid CA-issued certificates fail when executed using the mentioned approach. Only API calls with AEM trusted certificates are allowed to succeed when following this method.
Use the standard approach for executing API calls of valid CA-issued certificates, meaning that only APIs associated with private certificates should be executed using the previously mentioned method.
A conventional approach to effectively invoke internal APIs with private certificates involves modifying the JVM Keystore. It is achieved by importing the private certificates using the Java™ keytool command.
However, this method is not aligned with security best practices and AEM offers a superior option through the utilization of the Global Trust Store and KeyStoreService.