Autenticação mTLS (Mutual Transport Layer Security) do AEM
Saiba como fazer chamadas HTTPS do AEM para APIs da Web que exigem autenticação mTLS (Mutual Transport Layer Security).
A autenticação mTLS ou TLS bidirecional melhora a segurança do protocolo TLS, exigindo que o cliente e o servidor se autentiquem. Essa autenticação é feita usando certificados digitais. Normalmente, é usada em cenários em que a segurança e a verificação de identidade fortes são críticas.
Por padrão, ao tentar fazer uma conexão HTTPS com uma API da Web que requer autenticação mTLS, a conexão falha com o erro:
javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_required
Esse problema ocorre quando o cliente não apresenta um certificado para autenticação.
Saiba como chamar com êxito APIs que exigem autenticação mTLS usando o Apache HttpClient e o KeyStore e TrustStore do AEM.
HttpClient e carregar material do KeyStore do AEM
Em um nível superior, as seguintes etapas são necessárias para chamar uma API protegida por mTLS do AEM.
Geração de certificado do AEM
Solicite o certificado do AEM fazendo parceria com a equipe de segurança da sua organização. A equipe de segurança fornece ou solicita detalhes relacionados ao certificado, como chave, solicitação de assinatura do certificado (CSR) e, usando a CSR, o certificado é emitido.
Para fins de demonstração, gere os detalhes relacionados ao certificado, como chave e solicitação de assinatura do certificado (CSR). No exemplo abaixo, uma CA autoassinada é usada para emitir o certificado.
-
Primeiro, gere o certificado da autoridade de certificação (CA) interna.
code language-shell # Create an internal Certification Authority (CA) certificate openssl req -new -x509 -days 9999 -keyout internal-ca-key.pem -out internal-ca-cert.pem
-
Gere o certificado do AEM.
code language-shell # Generate Key openssl genrsa -out client-key.pem # Generate CSR openssl req -new -key client-key.pem -out client-csr.pem # Generate certificate and sign with internal Certification Authority (CA) openssl x509 -req -days 9999 -in client-csr.pem -CA internal-ca-cert.pem -CAkey internal-ca-key.pem -CAcreateserial -out client-cert.pem # Verify certificate openssl verify -CAfile internal-ca-cert.pem client-cert.pem
-
Converta a chave privada do AEM para o formato DER. O KeyStore do AEM exige a chave privada no formato DER.
code language-shell openssl pkcs8 -topk8 -inform PEM -outform DER -in client-key.pem -out client-key.der -nocrypt
Intercâmbio de certificados
Se estiver usando uma CA autoassinada para o certificado do AEM, como acima, envie o certificado ou o certificado da CA (autoridade de certificação) interna para o provedor de API.
Além disso, se o provedor de API estiver usando um certificado de CA autoassinado, receba o certificado ou o certificado da CA (autoridade de certificação) interna do provedor de API.
Importação de certificado
Para importar o certificado do AEM, siga as etapas abaixo:
-
Faça logon no AEM Author como administrador.
-
Navegue até AEM Author > Ferramentas > Segurança > Usuários > Criar ou selecionar um usuário existente.
Para fins de demonstração, um novo usuário chamado
mtl-demo-user
é criado. -
Para abrir as Propriedades do usuário, clique no nome do usuário.
-
Clique na guia Keystore e no botão Criar Keystore. Em seguida, na caixa de diálogo Definir senha de acesso do KeyStore, defina uma senha para o keystore desse usuário e clique em Salvar.
-
Na nova tela, na seção ADICIONAR CHAVE PRIVADA DO ARQUIVO DER, siga as etapas abaixo:
-
Inserir alias
-
Importe a chave privada do AEM no formato DER, gerada acima.
-
Importe os arquivos da cadeia de certificados, gerados acima.
-
Clique em Enviar.
-
-
Verifique se o certificado foi importado com êxito.
Se o provedor de API estiver usando um certificado de CA autoassinado, importe o certificado recebido para o TrustStore do AEM. Siga as etapas aqui.
Da mesma forma, se o AEM estiver usando um certificado de CA autoassinado, solicite ao provedor da API que o importe.
Protótipo de código de invocação da API mTLS usando HttpClient
Atualize o código Java™ conforme abaixo. Para usar a anotação @Reference
para obter o serviço KeyStoreService
do AEM, o código de chamada deve ser um componente/serviço OSGi ou um Modelo Sling (e @OsgiService
deve ser usado lá).
...
// Get AEM's KeyStoreService reference
@Reference
private com.adobe.granite.keystore.KeyStoreService keyStoreService;
...
// Get AEM KeyStore using KeyStoreService
KeyStore aemKeyStore = getAEMKeyStore(keyStoreService, resourceResolver);
if (aemKeyStore != null) {
// Create SSL Context
SSLContextBuilder sslbuilder = new SSLContextBuilder();
// Load AEM KeyStore material into above SSL Context with keystore password
// Ideally password should be encrypted and stored in OSGi config
sslbuilder.loadKeyMaterial(aemKeyStore, "admin".toCharArray());
// If API provider cert is self-signed, load AEM TrustStore material into above SSL Context
// Get AEM TrustStore
KeyStore aemTrustStore = getAEMTrustStore(keyStoreService, resourceResolver);
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(MTLS_API_ENDPOINT));
// Code that reads response code and body from the 'closeableHttpResponse' object
...
}
/**
* Returns the AEM KeyStore of a user. In this example we are using the
* 'mtl-demo-user' user.
*
* @param keyStoreService
* @param resourceResolver
* @return AEM KeyStore
*/
private KeyStore getAEMKeyStore(KeyStoreService keyStoreService, ResourceResolver resourceResolver) {
// get AEM KeyStore of 'mtl-demo-user' user, you can create a user or use an existing one.
// Then create keystore and upload key, certificate files.
KeyStore aemKeyStore = keyStoreService.getKeyStore(resourceResolver, "mtl-demo-user");
return aemKeyStore;
}
/**
*
* 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;
}
...
- Insira o serviço OSGi
com.adobe.granite.keystore.KeyStoreService
do OOTB no componente OSGi. - Obtenha o KeyStore do AEM do usuário usando
KeyStoreService
eResourceResolver
, o métodogetAEMKeyStore(...)
faz isso. - Se o provedor de API estiver usando um certificado de CA autoassinado, obtenha o AEM TrustStore global, o método
getAEMTrustStore(...)
fará isso. - Crie um objeto de
SSLContextBuilder
, consulte Detalhes da API do Java™. - Carregue o KeyStore do AEM do usuário no
SSLContextBuilder
usando o métodoloadKeyMaterial(final KeyStore keystore,final char[] keyPassword)
. - A senha do keystore é a senha que foi definida ao criar o keystore. Ela deve estar armazenada na configuração OSGi, consulte Valores de configuração do segredo.
Evite alterações no JVM Keystore
Uma abordagem convencional para invocar efetivamente APIs mTLS com certificados privados envolve a modificação do JVM Keystore. Isso é feito importando os certificados privados usando o comando Java™ keytool.
No entanto, esse método não está alinhado com as melhores práticas de segurança e o AEM oferece uma opção superior por meio da utilização de KeyStores específicos do usuário e TrustStore Global e KeyStoreService.
Pacote de solução
O projeto Node.js de amostra rebaixado no vídeo pode ser baixado aqui.
O código do servlet do AEM está disponível na ramificação tutorial/web-api-invocation
do Projeto do site do WKND, consulte.