2010-02-22 26 views
33

Necesito configurar un servidor HTTPS realmente liviano para una aplicación Java. Es un simulador que se utiliza en nuestros laboratorios de desarrollo para simular las conexiones HTTPS aceptadas por un equipo en la naturaleza. Debido a que es una herramienta de desarrollo ligera y no se utiliza en la producción de ninguna manera, estoy feliz de eludir las certificaciones y la mayor cantidad de negociación posible.Servidor Java HTTPS simple

Planeo utilizar la clase HttpsServer en Java 6 SE, pero estoy luchando para que funcione. Como cliente de prueba estoy usando wget desde la línea de comandos de cygwin (wget https://[address]:[port]) pero wget informa que fue "No se puede establecer una conexión SSL".

Si ejecuto wget con la opción -d para la depuración me dice "SSL handshake failed".

He pasado 30 minutos buscando en Google esto y todo parece indicar simplemente la inútil documentación de Java6 que describe los métodos, pero que no habla sobre cómo hablar ni cómo dar ningún código de ejemplo. .

¿Alguien puede empujarme en la dirección correcta?

Respuesta

38

Lo que el tiempo utilizado fue el siguiente:

try 
{ 
    // setup the socket address 
    InetSocketAddress address = new InetSocketAddress (InetAddress.getLocalHost(), config.getHttpsPort()); 

    // initialise the HTTPS server 
    HttpsServer httpsServer = HttpsServer.create (address, 0); 
    SSLContext sslContext = SSLContext.getInstance ("TLS"); 

    // initialise the keystore 
    char[] password = "simulator".toCharArray(); 
    KeyStore ks = KeyStore.getInstance ("JKS"); 
    FileInputStream fis = new FileInputStream ("lig.keystore"); 
    ks.load (fis, password); 

    // setup the key manager factory 
    KeyManagerFactory kmf = KeyManagerFactory.getInstance ("SunX509"); 
    kmf.init (ks, password); 

    // setup the trust manager factory 
    TrustManagerFactory tmf = TrustManagerFactory.getInstance ("SunX509"); 
    tmf.init (ks); 

    // setup the HTTPS context and parameters 
    sslContext.init (kmf.getKeyManagers(), tmf.getTrustManagers(), null); 
    httpsServer.setHttpsConfigurator (new HttpsConfigurator(sslContext) 
    { 
     public void configure (HttpsParameters params) 
     { 
      try 
      { 
       // initialise the SSL context 
       SSLContext c = SSLContext.getDefault(); 
       SSLEngine engine = c.createSSLEngine(); 
       params.setNeedClientAuth (false); 
       params.setCipherSuites (engine.getEnabledCipherSuites()); 
       params.setProtocols (engine.getEnabledProtocols()); 

       // get the default parameters 
       SSLParameters defaultSSLParameters = c.getDefaultSSLParameters(); 
       params.setSSLParameters (defaultSSLParameters); 
      } 
      catch (Exception ex) 
      { 
       ILogger log = new LoggerFactory().getLogger(); 
       log.exception (ex); 
       log.error ("Failed to create HTTPS port"); 
      } 
     } 
    }); 
    LigServer server = new LigServer (httpsServer); 
    joinableThreadList.add (server.getJoinableThread()); 
} 
catch (Exception exception) 
{ 
    log.exception (exception); 
    log.error ("Failed to create HTTPS server on port " + config.getHttpsPort() + " of localhost"); 
} 

Para generar un almacén de claves:

$ keytool -genkey -alias alias -keypass simulator \ 
    -keystore lig.keystore -storepass simulator 

Ver también here.

Potencialmente storepass y keypass pueden ser diferentes, en cuyo caso el ks.load y kmf.init deben usar storepass y keypass, respectivamente.

+1

Hola, en el cual punto ¿especifica su certificado y clave privada? se generan automáticamente? – Cemre

+0

Hola, todavía soy un novato. ¿Me pregunto si está utilizando el SSLContext que creó al configurar el configurador? Como anulas el método de configuración y llamas a getDefault(). No se utiliza el SSLContext que se pasa en el constructor. – william

+0

HI, ¿Cómo agregar autenticación de cliente? – Hoysala

10

He actualizado su respuesta para un servidor https (no sockets basados), podría ayudar con CSRF y AJAX llamada

import java.io.*; 
import java.net.InetSocketAddress; 
import java.lang.*; 
import java.net.URL; 
import com.sun.net.httpserver.HttpsServer; 
import java.security.KeyStore; 
import javax.net.ssl.KeyManagerFactory; 
import javax.net.ssl.TrustManagerFactory; 
import com.sun.net.httpserver.*; 
import javax.net.ssl.SSLEngine; 
import javax.net.ssl.SSLParameters; 

import java.io.InputStreamReader; 
import java.io.Reader; 
import java.net.URLConnection; 

import javax.net.ssl.HostnameVerifier; 
import javax.net.ssl.HttpsURLConnection; 
import javax.net.ssl.SSLContext; 
import javax.net.ssl.SSLSession; 
import javax.net.ssl.TrustManager; 
import javax.net.ssl.X509TrustManager; 
import java.security.cert.X509Certificate; 

import java.net.InetAddress; 
import com.sun.net.httpserver.HttpExchange; 
import com.sun.net.httpserver.HttpHandler; 
import com.sun.net.httpserver.HttpServer; 
import com.sun.net.httpserver.HttpsExchange; 

public class SimpleHTTPSServer { 

    public static class MyHandler implements HttpHandler { 
     @Override 
     public void handle(HttpExchange t) throws IOException { 
      String response = "This is the response"; 
      HttpsExchange httpsExchange = (HttpsExchange) t; 
      t.getResponseHeaders().add("Access-Control-Allow-Origin", "*"); 
      t.sendResponseHeaders(200, response.length()); 
      OutputStream os = t.getResponseBody(); 
      os.write(response.getBytes()); 
      os.close(); 
     } 
    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) throws Exception { 

     try { 
      // setup the socket address 
      InetSocketAddress address = new InetSocketAddress(8000); 

      // initialise the HTTPS server 
      HttpsServer httpsServer = HttpsServer.create(address, 0); 
      SSLContext sslContext = SSLContext.getInstance("TLS"); 

      // initialise the keystore 
      char[] password = "password".toCharArray(); 
      KeyStore ks = KeyStore.getInstance("JKS"); 
      FileInputStream fis = new FileInputStream("testkey.jks"); 
      ks.load(fis, password); 

      // setup the key manager factory 
      KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 
      kmf.init(ks, password); 

      // setup the trust manager factory 
      TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 
      tmf.init(ks); 

      // setup the HTTPS context and parameters 
      sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 
      httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext) { 
       public void configure(HttpsParameters params) { 
        try { 
         // initialise the SSL context 
         SSLContext c = SSLContext.getDefault(); 
         SSLEngine engine = c.createSSLEngine(); 
         params.setNeedClientAuth(false); 
         params.setCipherSuites(engine.getEnabledCipherSuites()); 
         params.setProtocols(engine.getEnabledProtocols()); 

         // get the default parameters 
         SSLParameters defaultSSLParameters = c.getDefaultSSLParameters(); 
         params.setSSLParameters(defaultSSLParameters); 

        } catch (Exception ex) { 
         System.out.println("Failed to create HTTPS port"); 
        } 
       } 
      }); 
      httpsServer.createContext("/test", new MyHandler()); 
      httpsServer.setExecutor(null); // creates a default executor 
      httpsServer.start(); 

     } catch (Exception exception) { 
      System.out.println("Failed to create HTTPS server on port " + 8000 + " of localhost"); 
      exception.printStackTrace(); 

     } 
    } 

} 

para crear un certificado autofirmado

keytool -genkey -keyalg RSA -alias selfsigned -keystore testkey.jks -storepass password -validity 360 -keysize 2048 
+2

'setExecutor (null)' crea un servidor de subproceso único. Para tener un servidor multiproceso, debe proporcionar un ejecutor adecuado. Por ejemplo: 'httpsServer.setExecutor (new ThreadPoolExecutor (4, 8, 30, TimeUnit.SECONDS, new ArrayBlockingQueue (100)));' – rustyx

+0

Hola, todavía soy un novato. ¿Me pregunto si está utilizando el SSLContext que creó al configurar el configurador? Como anulas el método de configuración y llamas a getDefault(). No se utiliza el SSLContext que se pasa en el constructor. – william

+0

Estrictamente hablando, debe llamar 't.sendResponseHeaders' con' response.getBytes(). Length' en lugar de 'response.length()'. Funciona con la cadena en el ejemplo, pero se romperá para '" Hëllö Wörld "'. – Torgny