From 861d1b6598867a359961f50800ba743e4d42ddbe Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 1 Jun 2017 23:33:01 +0200 Subject: [PATCH 1/2] Applying SSL to the webserver (WIP) --- .../website/ButtonWebsiteModule.java | 101 ++++++++++++++++-- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/src/buttondevteam/website/ButtonWebsiteModule.java b/src/buttondevteam/website/ButtonWebsiteModule.java index 49b44bf..ffe844d 100644 --- a/src/buttondevteam/website/ButtonWebsiteModule.java +++ b/src/buttondevteam/website/ButtonWebsiteModule.java @@ -1,22 +1,98 @@ package buttondevteam.website; +import java.io.*; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.nio.file.Files; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.CertificateFactory; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Calendar; + +import javax.net.ssl.*; +import java.security.cert.Certificate; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; -import com.sun.net.httpserver.HttpServer; + +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsParameters; +import com.sun.net.httpserver.HttpsServer; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.website.page.*; public class ButtonWebsiteModule extends JavaPlugin { public static final int PORT = 8080; - private static HttpServer server; + private static HttpsServer server; public ButtonWebsiteModule() { try { - server = HttpServer.create(new InetSocketAddress((InetAddress) null, PORT), 10); + server = HttpsServer.create(new InetSocketAddress((InetAddress) null, PORT), 10); + SSLContext sslContext = SSLContext.getInstance("TLS"); + + // initialise the keystore + char[] password = "password".toCharArray(); + KeyStore ks = KeyStore.getInstance("JKS"); + String certfile = "domain-chain.crt"; /* your cert path */ + File keystoreFile = new File("keystore.keystore"); + FileInputStream is = new FileInputStream(keystoreFile); + + ks.load(is, "somepass".toCharArray()); + + String alias = "chroma"; + + ////// + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + InputStream certstream = fullStream(certfile); + Certificate[] certs = cf.generateCertificates(certstream).stream().toArray(Certificate[]::new); + + byte[] keyBytes = Files.readAllBytes(new File("domain.key").toPath()); + + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory kf = KeyFactory.getInstance("RSA"); + PrivateKey pk = kf.generatePrivate(spec); + + // Add the certificate + ks.setKeyEntry(alias, pk, password, certs); // TODO: Only set if updated + + // Save the new keystore contents + FileOutputStream out = new FileOutputStream(keystoreFile); + ks.store(out, password); + out.close(); + + // 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); + server.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"); + } + } + }); } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while starting the webserver!", e); } @@ -29,9 +105,12 @@ public class ButtonWebsiteModule extends JavaPlugin { this.getLogger().info("Starting webserver..."); ((Runnable) server::start).run(); // Totally normal way of calling a method this.getLogger().info("Webserver started"); - Thread t = new Thread(() -> AcmeClient.main("server.figytuna.com")); - t.setContextClassLoader(getClass().getClassLoader()); - t.start(); + final Calendar calendar = Calendar.getInstance(); + if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY) { // Only update every week + Thread t = new Thread(() -> AcmeClient.main("server.figytuna.com")); + t.setContextClassLoader(getClass().getClassLoader()); + t.start(); + } }); } @@ -41,4 +120,14 @@ public class ButtonWebsiteModule extends JavaPlugin { public static void addPage(Page page) { server.createContext("/" + page.GetName(), page); } + + private static InputStream fullStream(String fname) throws IOException { + FileInputStream fis = new FileInputStream(fname); + DataInputStream dis = new DataInputStream(fis); + byte[] bytes = new byte[dis.available()]; + dis.readFully(bytes); + dis.close(); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + return bais; + } } From 37ebe6d10c18f3a7c9894f1259a801482cfa1e58 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 5 Jun 2017 22:37:43 +0200 Subject: [PATCH 2/2] FULLY IMPLEMENTED HTTPS it looks like --- src/buttondevteam/website/AcmeClient.java | 2 -- .../website/ButtonWebsiteModule.java | 25 ++++++++++++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/buttondevteam/website/AcmeClient.java b/src/buttondevteam/website/AcmeClient.java index 7753d46..ce5961c 100644 --- a/src/buttondevteam/website/AcmeClient.java +++ b/src/buttondevteam/website/AcmeClient.java @@ -305,8 +305,6 @@ public class AcmeClient { LOG.info("Starting up..."); - Security.addProvider(new BouncyCastleProvider()); - Collection domains = Arrays.asList(args); try { AcmeClient ct = new AcmeClient(); diff --git a/src/buttondevteam/website/ButtonWebsiteModule.java b/src/buttondevteam/website/ButtonWebsiteModule.java index ffe844d..cd94f71 100644 --- a/src/buttondevteam/website/ButtonWebsiteModule.java +++ b/src/buttondevteam/website/ButtonWebsiteModule.java @@ -3,17 +3,20 @@ package buttondevteam.website; import java.io.*; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.nio.file.Files; -import java.security.KeyFactory; +import java.security.KeyPair; import java.security.KeyStore; import java.security.PrivateKey; +import java.security.Security; import java.security.cert.CertificateFactory; -import java.security.spec.PKCS8EncodedKeySpec; import java.util.Calendar; import javax.net.ssl.*; import java.security.cert.Certificate; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; @@ -38,9 +41,8 @@ public class ButtonWebsiteModule extends JavaPlugin { KeyStore ks = KeyStore.getInstance("JKS"); String certfile = "domain-chain.crt"; /* your cert path */ File keystoreFile = new File("keystore.keystore"); - FileInputStream is = new FileInputStream(keystoreFile); - ks.load(is, "somepass".toCharArray()); + ks.load(keystoreFile.exists() ? new FileInputStream(keystoreFile) : null, "somepass".toCharArray()); String alias = "chroma"; @@ -50,11 +52,15 @@ public class ButtonWebsiteModule extends JavaPlugin { InputStream certstream = fullStream(certfile); Certificate[] certs = cf.generateCertificates(certstream).stream().toArray(Certificate[]::new); - byte[] keyBytes = Files.readAllBytes(new File("domain.key").toPath()); + BufferedReader br = new BufferedReader(new FileReader("domain.key")); - PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); - KeyFactory kf = KeyFactory.getInstance("RSA"); - PrivateKey pk = kf.generatePrivate(spec); + Security.addProvider(new BouncyCastleProvider()); + + PEMParser pp = new PEMParser(br); + PEMKeyPair pemKeyPair = (PEMKeyPair) pp.readObject(); + KeyPair kp = new JcaPEMKeyConverter().getKeyPair(pemKeyPair); + pp.close(); + PrivateKey pk = kp.getPrivate(); // Add the certificate ks.setKeyEntry(alias, pk, password, certs); // TODO: Only set if updated @@ -95,6 +101,7 @@ public class ButtonWebsiteModule extends JavaPlugin { }); } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while starting the webserver!", e); + getServer().getPluginManager().disablePlugin(this); } }