2012-07-11 18 views
10

Soy un nuevo usuario de los servicios REST. Necesito consumir un servicio RESTful API generado con Jersey. El problema surge porque ese servicio está alojado en un host remoto y requiere acceso https con el certificado.Consumo de servicio RESTful sobre https con certficate usando Java

Obtuve mi certificado de la organización y puedo acceder al servicio REST API con cualquiera de mis navegadores (con certificado establecido en ellos).

He leído gran cantidad de puestos de aquí, y yo he seguido la respuesta en este tema: Using HTTPS with REST in Java

Ahora he mi configuración de certificados en mi almacén de claves Java. Pero no sé cómo usar eso en mi programa Java para que use exactamente el certificado que necesito para hacer la conexión https.

Este es mi código de conexión simple para las pruebas locales.

package rest.test.first; 
import java.net.URI; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.core.UriBuilder; 

import com.sun.jersey.api.client.Client; 
import com.sun.jersey.api.client.ClientResponse; 
import com.sun.jersey.api.client.WebResource; 
import com.sun.jersey.api.client.config.ClientConfig; 
import com.sun.jersey.api.client.config.DefaultClientConfig; 

public class TestClient{ 
public static void main(String[]args){ 
    ClientConfig config= new DefaultClientConfig(); 
    Client client=Client.create(config); 
    WebResource service=client.resource(getBaseURI()); 
    //Fluentinterfaces 
    System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_PLAIN).get(ClientResponse.class).toString()); 
    //Getplaintext 
    System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_PLAIN).get(String.class)); 
    //GetXML 
    System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_XML).get(String.class)); 
    //TheHTML 
    System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_HTML).get(String.class)); 
} 

private static URI getBaseURI(){ 
    return UriBuilder.fromUri("http://localhost:8080/rest.test").build(); 
} 
} 

Me'v leer sobre el uso de propiedades del conjunto del sistema para especificar la ruta a keystore con este código:

System.setProperty("javax.net.ssl.keyStore", "/path/to/keystore.jks"); 
System.setProperty("javax.net.ssl.keyStorePassword", "password"); 

todavía tengo 401 Error en la conexión con el servidor remoto.

Pero entonces no sé cómo hacer la conexión SSL usando mi certificado en el almacén de claves. También he estado leyendo sobre el uso de SSLSocketFactory para este propósito, pero no pude hacer que funcione como se explica en este post: How can I use different certificates on specific connections?

He conseguido recuperar mi certificado de almacén de claves con este código .. ahora sólo necesita saber cómo usarlo en la conexión:

package rest.test.first; 

    import java.io.FileInputStream; 
    import java.security.KeyStore; 
    import java.security.cert.Certificate; 

    public class keystore { 

     public static void main(String[] args) throws Exception { 
     String keystoreFilename = "/usr/lib/jvm/jdk1.6.0_32/jre/lib/security/cacerts"; 

     char[] password = "changeit".toCharArray(); 
     String alias = "remote_https_server"; 

     FileInputStream fIn = new FileInputStream(keystoreFilename); 
     KeyStore keystore = KeyStore.getInstance("JKS"); 

     keystore.load(fIn, password); 

     Certificate cert = keystore.getCertificate(alias); 

     System.out.println(cert); 
     } 
    } 

Ok, esa es la última secuencia de comandos que he escrito. Puedo conectarme a sitios https pero aún no puedo conectarme a los sitios https que requieren enviar mi certificado para autenticarse.

package rest.test.first; 


import java.io.*; 
import java.net.*; 
import java.security.*; 

import javax.net.ssl.HttpsURLConnection; 
import javax.net.ssl.SSLContext; 
import javax.net.ssl.SSLSocketFactory; 
import javax.net.ssl.TrustManager; 
import javax.net.ssl.TrustManagerFactory; 


public class urlConnection{ 
    public static void main(String args[]) throws Exception { 

    System.setProperty("javax.net.ssl.trustStore", "/usr/lib/jvm/jdk1.6.0_32/jre/lib/security/cacerts"); 
    System.setProperty("javax.net.ssl.trustStorePassword", "changeit"); 
    Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); 

     //TrustStore.. 
     char[] passphrase = "changeit".toCharArray(); //password 
     KeyStore keystore = KeyStore.getInstance("JKS"); 
     //KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
     keystore.load(new FileInputStream("/usr/lib/jvm/jdk1.6.0_32/jre/lib/security/cacerts"), passphrase); //path 

     //TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); //instance 
     TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
     tmf.init(keystore); 


     SSLContext context = SSLContext.getInstance("TLS"); 
     TrustManager[] trustManagers = tmf.getTrustManagers(); 
     context.init(null, trustManagers, null); 
     SSLSocketFactory sf = context.getSocketFactory(); 
     URL url = new URL("https://www.google.es"); 

     HttpsURLConnection httpsCon = (HttpsURLConnection) url.openConnection(); 
     httpsCon.setSSLSocketFactory(sf); 
     httpsCon.setRequestMethod("GET"); 

     /*InputStream inStrm = httpsCon.getInputStream(); 
     System.out.println("\nContent at " + url); 
     int ch; 
     while (((ch = inStrm.read()) != -1)){ 
      System.out.print((char) ch); 
     inStrm.close(); 
     }*/ 

     System.out.println("Response Message is " + httpsCon.getResponseMessage()); 

} 
} 
+1

¿Cómo generó su almacén de claves? En el código que publicaste, ¿por qué estás usando el almacén de confianza 'cacerts'? Sugeriría importar su certificado en su propio JKS y usarlo en la llamada a 'System.setProperty (" javax.net.ssl.keyStore "," ... ")'. – poida

Respuesta

2

Suponiendo que va a implementar este código en un servidor y que ha hecho todo lo demás correctamente (como la generación de núcleo almacén de claves de forma correcta y colocarla en un lugar donde se puede acceder a su servidor, utilizando la misma versión Java como su código para generar el almacén de claves), entonces creo que lo que hay que hacer es añadir siguiente

<Connector SSLEnabled="true" clientAuth="false" keystoreFile="pathToKeystore" keystorePass="password" maxThreads="150" port="443" protocol="HTTP/1.1" scheme="https" secure="true" sslProtocol="TLS"/> 

en server.xml de la instancia del servidor en el que está ejecutando el cliente y

<Connector connectionTimeout="20000" port="80" protocol="HTTP/1.1" redirectPort="8443"/> 

IMP: Si usa Skype junto con este código, asegúrese de (desmarque) cambiar el valor predeterminado, ya que también usa los mismos puertos (80 y 443) para conexiones adicionales

Cuestiones relacionadas