Saltar al contenido

¿Cómo uso un certificado de cliente SSL con Apache HttpClient?

Indagamos por diferentes espacios para brindarte la respuesta para tu inquietud, si tienes alguna difcultad deja tu comentario y responderemos con mucho gusto.

Solución:

Creo que la principal diferencia es que en Java, normalmente pones el key y el certificado a un key guárdelo y utilícelo desde allí. Como mencionas a menudo, las personas quieren usar una biblioteca separada para ello, como el cliente httpcomponents mencionado (al igual que estás usando la biblioteca de solicitudes en tu ejemplo de Python).

A continuación, se muestra un ejemplo del uso de un certificado de cliente de key store, utilizando la biblioteca mencionada anteriormente:

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.junit.Test;

import javax.net.ssl.SSLContext;
import java.io.InputStream;
import java.security.KeyStore;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class MyClientCertTest 

    private static final String KEYSTOREPATH = "/clientkeystore.jks"; // or .p12
    private static final String KEYSTOREPASS = "keystorepass";
    private static final String KEYPASS = "keypass";

    KeyStore readStore() throws Exception 
        try (InputStream keyStoreStream = this.getClass().getResourceAsStream(KEYSTOREPATH)) 
            KeyStore keyStore = KeyStore.getInstance("JKS"); // or "PKCS12"
            keyStore.load(keyStoreStream, KEYSTOREPASS.toCharArray());
            return keyStore;
        
    
    @Test
    public void readKeyStore() throws Exception 
        assertNotNull(readStore());
    
    @Test
    public void performClientRequest() throws Exception 
        SSLContext sslContext = SSLContexts.custom()
                .loadKeyMaterial(readStore(), KEYPASS.toCharArray()) // use null as second param if you don't have a separate key password
                .build();

        HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
        HttpResponse response = httpClient.execute(new HttpGet("https://slsh.iki.fi/client-certificate/protected/"));
        assertEquals(200, response.getStatusLine().getStatusCode());
        HttpEntity entity = response.getEntity();

        System.out.println("----------------------------------------");
        System.out.println(response.getStatusLine());
        EntityUtils.consume(entity);
    

Maven pom para versiones de dependencia:



    4.0.0

    com.acme
    httptests
    0.0.1-SNAPSHOT
    
        1.8
        1.8
    
    
        
            org.apache.httpcomponents
            httpclient
            4.5.3
        
        
            junit
            junit
            4.12
            test
        
    
    
        
            
                org.apache.maven.plugins
                maven-surefire-plugin
                2.9
                
                
                    -Djavax.net.debug=all
                
            
        
    

También publiqué una página de prueba simple para probar un certificado de cliente.


Solo para demostrar que se puede hacer, a continuación se muestra un ejemplo de cómo usar un certificado de cliente simplemente usando la API estándar de Java, sin bibliotecas adicionales.

import org.junit.Test;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyStore;

public class PlainJavaHTTPS2Test 

    @Test
    public void testJKSKeyStore() throws Exception 
        final String KEYSTOREPATH = "clientkeystore.jks";
        final char[] KEYSTOREPASS = "keystorepass".toCharArray();
        final char[] KEYPASS = "keypass".toCharArray();

        try (InputStream storeStream = this.getClass().getResourceAsStream(KEYSTOREPATH)) 
            setSSLFactories(storeStream, "JKS", KEYSTOREPASS, KEYPASS);
        
        testPlainJavaHTTPS();
    
    @Test
    public void testP12KeyStore() throws Exception 
        final String KEYSTOREPATH = "clientkeystore.p12";
        final char[] KEYSTOREPASS = "keystorepass".toCharArray();
        final char[] KEYPASS = "keypass".toCharArray();

        try (InputStream storeStream = this.getClass().getResourceAsStream(KEYSTOREPATH)) 
            setSSLFactories(storeStream, "PKCS12", KEYSTOREPASS, KEYPASS);
        
        testPlainJavaHTTPS();
    
    private static void setSSLFactories(InputStream keyStream, String keystoreType, char[] keyStorePassword, char[] keyPassword) throws Exception
    
        KeyStore keyStore = KeyStore.getInstance(keystoreType);

        keyStore.load(keyStream, keyStorePassword);

        KeyManagerFactory keyFactory =
                KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

        keyFactory.init(keyStore, keyPassword);

        KeyManager[] keyManagers = keyFactory.getKeyManagers();

        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(keyManagers, null, null);
        SSLContext.setDefault(sslContext);
    

    public void testPlainJavaHTTPS() throws Exception 
        String httpsURL = "https://slsh.iki.fi/client-certificate/protected/";
        URL myUrl = new URL(httpsURL);
        HttpsURLConnection conn = (HttpsURLConnection)myUrl.openConnection();
        try (InputStream is = conn.getInputStream()) 
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);

            String inputLine;

            while ((inputLine = br.readLine()) != null) 
                System.out.println(inputLine);
            
        
    

Y aquí hay una tercera versión con la menor cantidad de código, pero que se basa en el hecho de que a) el almacén de claves es un archivo en el disco, no dentro de jar, yb) key contraseña debe ser idéntica a la contraseña del almacén de claves.

import org.junit.BeforeClass;
import org.junit.Test;

import java.net.URL;
import java.io.*;
import javax.net.ssl.HttpsURLConnection;

public class PlainJavaHTTPSTest 

    @BeforeClass
    public static void setUp() 
        System.setProperty("javax.net.ssl.keyStore", "/full/path/to/clientkeystore-samepassword.jks");
        System.setProperty("javax.net.ssl.keyStorePassword", "keystorepass");
    

    @Test
    public void testPlainJavaHTTPS() throws Exception 
        String httpsURL = "https://slsh.iki.fi/client-certificate/protected/";
        URL myUrl = new URL(httpsURL);
        HttpsURLConnection conn = (HttpsURLConnection)myUrl.openConnection();
        try (InputStream is = conn.getInputStream()) 
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);

            String inputLine;

            while ((inputLine = br.readLine()) != null) 
                System.out.println(inputLine);
            
        
    

Por supuesto, las propiedades establecidas anteriormente en el código también se pueden proporcionar como parámetros de inicio, -Djavax.net.ssl.keyStore=/full/path/to/clientkeystore-samepassword.jks y -Djavax.net.ssl.keyStorePassword=keystorepass.

Si desea utilizar el cliente HTTP Apache en lugar del cliente HTTP Java, debe proporcionar a SSLFactory su almacén de claves y configurar DefaultHTTPClient para utilizarlo en el protocolo HTTPS.

Puede encontrar un ejemplo práctico aquí.

Espero que eso ayude.

Reseñas y valoraciones del artículo

Si para ti ha sido de provecho este post, sería de mucha ayuda si lo compartes con el resto entusiastas de la programación y nos ayudes a difundir esta información.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *