调用具有私有证书的内部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 HttpComponentHttpClient库类及其方法。

HttpClient和加载AEM TrustStore资料

要调用具有​ 私有或自签名证书 ​的API终结点,HttpClientSSLContextBuilder必须使用AEM的TrustStore加载,并且用于促进连接。

请按照以下步骤操作:

  1. 以​ 管理员 ​的身份登录到​ AEM作者

  2. 导航到​ AEM Author > Tools > Security > Trust Store,然后打开​ 全局信任存储。 如果首次访问,请为全局信任存储区设置密码。

    全局信任存储区

  3. 要导入专用证书,请单击​ 选择证书文件 ​按钮,然后选择所需的扩展名为.cer的证书文件。 通过单击​ 提交 ​按钮导入它。

  4. 更新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.KeyStoreService OSGi服务注入您的OSGi组件。
    • 使用KeyStoreServiceResourceResolver获取全局AEM TrustStore,getAEMTrustStore(...)方法可做到这一点。
    • 创建SSLContextBuilder的对象,请参阅Java™ API详细信息
    • 使用loadTrustMaterial(KeyStore truststore,TrustStrategy trustStrategy)方法将全局AEM TrustStore加载到SSLContextBuilder中。
    • 通过上述方法中的TrustStrategynull,它可确保在API执行期间只有AEM信任证书能够成功。
CAUTION
使用上述方法执行时,具有有效CA颁发证书的API调用失败。 在遵循此方法时,只允许使用AEM受信任证书的API调用成功。
使用标准方法执行有效CA颁发的证书的API调用,这意味着应仅使用上述方法执行与私有证书关联的API。

避免JVM密钥库更改

使用私有证书有效调用内部API的传统方法涉及修改JVM密钥库。 这是通过使用Java™ keytool命令导入私有证书来实现的。

但是,此方法不符合安全最佳实践,AEM通过利用​ 全局信任存储区 ​和KeyStoreService提供了优异的选项。

解决方案包

可从此处下载视频中降级的Node.js示例项目。

AEM servlet代码在WKND站点项目的tutorial/web-api-invocation分支中可用,请参见

recommendation-more-help
c92bdb17-1e49-4e76-bcdd-89e4f85f45e6