调用具有私有证书的内部 API
了解如何使用私有或自签名证书从 AEM 向 Web API 进行 HTTPS 调用。
默认情况下,当尝试与使用自签名证书的 Web API 建立 HTTPS 连接时,连接会失败,并出现以下错误:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
此问题通常发生在 API 的 SSL 证书不是由公认的证书颁发机构 (CA) 颁发,且 Java™ 应用程序无法验证 SSL/TLS 证书时。
让我们学习如何使用 Apache HttpClient 和 AEM 的全局 TrustStore,成功调用具有私有或自签名证书的 API。
使用 HttpClient 的原型 API 调用代码
以下代码会建立一个到 Web API 的 HTTPS 连接:
...
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
...
该代码使用了 Apache HttpComponent 的 HttpClient 库类及其方法。
HttpClient 与加载 AEM TrustStore 材料
要调用带有 私有或自签名证书 的 API 端点,必须使用 AEM 的 TrustStore 加载 HttpClient 的 SSLContextBuilder,并用于促进连接。
按照下面的步骤进行操作:
-
以 管理员 身份登录AEM Author。
-
导航至 AEM Author > 工具 > 安全性 > 信任存储区,然后打开全局信任存储区。如果第一次访问,请为全局信任存储区设置密码。
-
要导入私有证书,请点击 选择证书文件 按钮,并选择带有
.cer扩展名的所需证书文件。点击 提交 按钮进行导入。 -
更新 Java™ 代码如下。请注意,要使用
@Reference来获取 AEM 的KeyStoreService服务,调用代码必须是 OSGi 组件/服务,或 Sling 模型(且在那里使用了@OsgiService)。code language-java ... // 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; } ...- 将 OOTB
com.adobe.granite.keystore.KeyStoreServiceOSGi 服务注入到您的 OSGi 组件中。 - 使用
KeyStoreService和ResourceResolver获取全局 AEM TrustStore,getAEMTrustStore(...)方法可以实现此操作。 - 创建一个
SSLContextBuilder的对象,查看 Java™ API 详情。 - 使用
loadTrustMaterial(KeyStore truststore,TrustStrategy trustStrategy)方法将全局 AEM TrustStore 加载到SSLContextBuilder中。 - 在上述方法中为
TrustStrategy传递null,它确保在 API 执行期间只有 AEM 信任的证书才会有效。
- 将 OOTB
避免更改 JVM 密钥库
使用私有证书有效调用内部 API 的传统方法涉及修改 JVM 密钥库。这是通过使用 Java™ 的 keytool 命令导入私有证书来实现的。
然而,这种方法并不符合安全最佳实践,而 AEM 通过使用 全局信任存储区 以及 KeyStoreService,提供了一种更优的选择。
解决方案包
视频中演示的示例 Node.js 项目可以从此处下载。
AEM servlet 代码可在 WKND Sites 项目的 tutorial/web-api-invocation 分支中找到,请参阅。