2010-02-22 20 views
33

Ich muss einen wirklich leichten HTTPS-Server für eine Java-Anwendung einrichten. Es ist ein Simulator, der in unseren Entwicklungslaboren verwendet wird, um die HTTPS-Verbindungen zu simulieren, die von einem Gerät in freier Wildbahn akzeptiert werden. Da es sich um ein reines Entwicklungstool handelt, das in keiner Weise in der Produktion verwendet wird, bin ich sehr glücklich, Zertifizierungen und so viel Verhandeln wie möglich umgehen zu können.Einfacher Java HTTPS-Server

Ich plane die Verwendung der HttpsServer Klasse in Java 6 SE, aber ich habe Mühe, es funktioniert zu bekommen. Als Testclient verwende ich wget von der cygwin-Befehlszeile (wget https://[address]:[port]), aber wget meldet, dass es "SSL-Verbindung nicht herstellen konnte".

Wenn ich wget mit der Option -d zum Debuggen ausführen, sagt es mir "SSL-Handshake fehlgeschlagen".

Ich habe 30 Minuten damit verbracht zu googeln und alles scheint nur auf die ziemlich nutzlose Java6-Dokumentation zu verweisen, die die Methoden beschreibt, aber nicht wirklich darüber spricht, wie man das verdammte Ding überhaupt spricht oder einen Beispielcode liefert .

Kann mich jemand in die richtige Richtung schubsen?

Antwort

38

Was ich schließlich war benutzten:

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"); 
} 

einen Schlüsselspeicher zu generieren:

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

Siehe auch here.

Möglicherweise sind Speicherwechsel und Schlüsselpass unterschiedlich. In diesem Fall müssen ks.load und kmf.init storepass bzw. keypass verwenden.

+1

Hallo zu schaffen, bei denen Zeigen Sie Ihr Zertifikat und Ihren privaten Schlüssel an? Werden sie automatisch generiert? – Cemre

+0

Hallo, immer noch ein Neuling. Sie fragen sich nur, ob Sie den SSLContext verwenden, den Sie beim Konfigurieren des Konfigurators erstellt haben? Da Sie die configure-Methode überschreiben und getDefault() aufrufen. Nicht den SSLContext verwenden, der im Konstruktor übergeben wird. – william

+0

HI, Wie kann die Client-Authentifizierung hinzugefügt werden? – Hoysala

10

ich Ihre Antwort für einen https-Server aktualisiert (nicht auf Basis Buchse) an, mit CSRF und Ajax-Aufruf helfen kann

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(); 

     } 
    } 

} 

Um ein selbst signiertes Zertifikat

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

'setExecutor (null)' erstellt einen single-threaded Server. Um einen Multithread-Server zu haben, müssen Sie einen geeigneten Executor bereitstellen. Zum Beispiel: 'httpsServer.setExecutor (neuer ThreadPoolExecutor (4, 8, 30, TimeUnit.SECONDS, neue ArrayBlockingQueue (100)));' – rustyx

+0

Hallo, immer noch ein Neuling. Sie fragen sich nur, ob Sie den SSLContext verwenden, den Sie beim Konfigurieren des Konfigurators erstellt haben? Da Sie die configure-Methode überschreiben und getDefault() aufrufen. Nicht den SSLContext verwenden, der im Konstruktor übergeben wird. – william

+0

Streng genommen sollten Sie 't.sendResponseHeaders' mit' response.getBytes(). Length' und nicht mit 'response.length() 'aufrufen. Es funktioniert mit der Saite in Ihrem Beispiel, wird aber für '' Hëllö Wörld'' brechen. – Torgny