Llamar a API internas que tienen certificados privados

Aprenda a realizar llamadas HTTPS desde AEM a las API web mediante certificados privados o autofirmados.

De forma predeterminada, al intentar establecer una conexión HTTPS con una API web que utiliza un certificado firmado automáticamente, la conexión falla con el siguiente error:

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Este problema suele ocurrir cuando el certificado SSL de la API no es emitido por una entidad de certificación (CA) reconocida y la aplicación Java™ no puede validar el certificado SSL/TLS.

Vamos a aprender a llamar correctamente a las API que tienen certificados privados o autofirmados mediante Apache HttpClient y TrustStore global de AEM.

Código de invocación de API prototípico mediante HttpClient

El siguiente código establece una conexión HTTPS con una API web:

...
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
...

El código usa las clases de biblioteca HttpClient de Apache HttpComponent y sus métodos.

HttpClient y cargar material de AEM TrustStore

Para llamar a un punto final de API que tiene un certificado privado o autofirmado, HttpClient debe cargarse con TrustStore de AEM y usarse para facilitar la conexión.SSLContextBuilder

Siga estos pasos:

  1. Inicie sesión en AEM Author como administrador.

  2. Vaya a AEM Author > Herramientas > Seguridad > Almacén de confianza y abra el Almacén de confianza global. Si accede la primera vez, establezca una contraseña para el Almacén de confianza global.

    Almacén de confianza global

  3. Para importar un certificado privado, haga clic en el botón Seleccionar archivo de certificado y seleccione el archivo de certificado deseado con la extensión .cer. Impórtelo haciendo clic en el botón Enviar.

  4. Actualice el código Java™ como se muestra a continuación. Tenga en cuenta que para usar @Reference para obtener KeyStoreService de AEM, el código de llamada debe ser un componente o servicio OSGi o un modelo Sling (y @OsgiService se usa allí).

    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;
    }
    
    ...
    
    • Inserte el servicio OSGi OOTB com.adobe.granite.keystore.KeyStoreService en su componente OSGi.
    • Si se obtiene el AEM TrustStore mediante KeyStoreService y ResourceResolver, el método getAEMTrustStore(...) lo hace.
    • Cree un objeto de SSLContextBuilder, consulte Java™ Detalles de la API.
    • Cargue el AEM TrustStore global en SSLContextBuilder mediante el método loadTrustMaterial(KeyStore truststore,TrustStrategy trustStrategy).
    • Pase null para TrustStrategy en el método anterior, se garantiza que solo los certificados de confianza de AEM se ejecuten correctamente durante la ejecución de la API.
CAUTION
Las llamadas a la API con certificados emitidos por la CA válidos fallan cuando se ejecutan con el método mencionado. Solo las llamadas API con certificados de confianza de AEM pueden realizarse correctamente al seguir este método.
Use el método estándar para ejecutar llamadas API de certificados emitidos por CA válidos, lo que significa que solo las API asociadas con certificados privados deben ejecutarse con el método mencionado anteriormente.

Evitar cambios en el almacén de claves JVM

Un enfoque convencional para invocar de forma eficaz las API internas con certificados privados implica la modificación del repositorio de claves JVM. Se logra importando los certificados privados mediante el comando Java™ keytool.

Sin embargo, este método no está alineado con las prácticas recomendadas de seguridad y AEM ofrece una opción superior mediante el uso del Almacén de confianza global y KeyStoreService.

Paquete de soluciones

El proyecto Node.js de muestra que aparece en el vídeo se puede descargar desde aquí.

El código de servlet de AEM está disponible en la rama tutorial/web-api-invocation del proyecto WKND Sites, véase.

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