From a77e69cc743cd838ee7a9d37ce2f5759c86d83df Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 27 Apr 2024 17:54:30 +0200 Subject: [PATCH] Add TLS support to basic server. --- .../jgrapes/http/test/BasicTestServer.java | 93 +++++++++++++++---- .../org/jgrapes/http/test/ClientTest.java | 6 +- .../test/org/jgrapes/http/test/GetTest.java | 6 +- .../org/jgrapes/http/test/NotFoundTests.java | 6 +- .../test/org/jgrapes/http/test/PostTest.java | 6 +- .../http/test/UnsupportedProtocolTests.java | 3 +- 6 files changed, 85 insertions(+), 35 deletions(-) diff --git a/org.jgrapes.http/test/org/jgrapes/http/test/BasicTestServer.java b/org.jgrapes.http/test/org/jgrapes/http/test/BasicTestServer.java index f9e186e5bf1..4cf2e911c0a 100644 --- a/org.jgrapes.http/test/org/jgrapes/http/test/BasicTestServer.java +++ b/org.jgrapes.http/test/org/jgrapes/http/test/BasicTestServer.java @@ -18,15 +18,28 @@ package org.jgrapes.http.test; +import java.io.FileInputStream; import java.io.IOException; -import java.net.InetAddress; import java.net.InetSocketAddress; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; import java.util.concurrent.ExecutionException; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import org.jgrapes.core.Channel; import org.jgrapes.core.Component; +import org.jgrapes.core.NamedChannel; import org.jgrapes.http.HttpServer; import org.jgrapes.http.events.Request; import org.jgrapes.io.NioDispatcher; +import org.jgrapes.io.util.PermitsPool; import org.jgrapes.net.SocketServer; +import org.jgrapes.net.SslCodec; import org.jgrapes.net.events.Ready; import static org.junit.Assert.fail; @@ -34,40 +47,86 @@ * */ public class BasicTestServer extends Component { - private InetSocketAddress addr; - private WaitForTests readyMonitor; + private InetSocketAddress unsecureAddr; + private InetSocketAddress secureAddr; + private WaitForTests unsecureMonitor; + private WaitForTests secureMonitor; @SafeVarargs public BasicTestServer(Class... fallbacks) - throws IOException, InterruptedException, ExecutionException { + throws IOException, InterruptedException, ExecutionException, + KeyStoreException, NoSuchAlgorithmException, CertificateException, + UnrecoverableKeyException, KeyManagementException { attach(new NioDispatcher()); - SocketServer networkServer = attach(new SocketServer()); - attach(new HttpServer(channel(), networkServer.channel(), - fallbacks)); - readyMonitor = new WaitForTests<>( - this, Ready.class, networkServer.channel().defaultCriterion()); + + // Network level unencrypted channel. + Channel httpTransport = new NamedChannel("serverTransport"); + + // Create a TCP server + SocketServer unsecureNetwork = attach(new SocketServer(httpTransport)); + unsecureMonitor = new WaitForTests<>(this, Ready.class, + unsecureNetwork.channel().defaultCriterion()); + + // Create TLS "converter" + KeyStore serverStore = KeyStore.getInstance("JKS"); + try (FileInputStream kf + = new FileInputStream("test-resources/localhost.jks")) { + serverStore.load(kf, "nopass".toCharArray()); + } + KeyManagerFactory kmf = KeyManagerFactory.getInstance( + KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(serverStore, "nopass".toCharArray()); + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(kmf.getKeyManagers(), null, new SecureRandom()); + + // Create a TCP server for SSL + SocketServer securedNetwork = attach(new SocketServer() + .setBacklog(3000) + .setConnectionLimiter(new PermitsPool(50))); + attach(new SslCodec(httpTransport, securedNetwork, sslContext)); + + // Create an HTTP server as converter between transport and + // application layer. + attach(new HttpServer(channel(), + httpTransport, fallbacks).setAcceptNoSni(true)); + + secureMonitor = new WaitForTests<>(this, Ready.class, + securedNetwork.channel().defaultCriterion()); } - public InetSocketAddress getSocketAddress() + public InetSocketAddress getUnsecureAddress() throws InterruptedException, ExecutionException { - if (addr == null) { - Ready readyEvent = (Ready) readyMonitor.get(); + if (unsecureAddr == null) { + Ready readyEvent = (Ready) unsecureMonitor.get(); if (!(readyEvent.listenAddress() instanceof InetSocketAddress)) { fail(); } - addr = ((InetSocketAddress) readyEvent.listenAddress()); + unsecureAddr = ((InetSocketAddress) readyEvent.listenAddress()); } - return addr; + return unsecureAddr; } - public InetAddress getAddress() + public InetSocketAddress getSecureAddress() throws InterruptedException, ExecutionException { - return getSocketAddress().getAddress(); + if (secureAddr == null) { + Ready readyEvent = (Ready) secureMonitor.get(); + if (!(readyEvent.listenAddress() instanceof InetSocketAddress)) { + fail(); + } + secureAddr = ((InetSocketAddress) readyEvent.listenAddress()); + } + return secureAddr; + } public int getPort() throws InterruptedException, ExecutionException { - return getSocketAddress().getPort(); + return getUnsecureAddress().getPort(); + } + + public int getTlsPort() + throws InterruptedException, ExecutionException { + return getSecureAddress().getPort(); } } diff --git a/org.jgrapes.http/test/org/jgrapes/http/test/ClientTest.java b/org.jgrapes.http/test/org/jgrapes/http/test/ClientTest.java index e4958b5ee83..ff8c395c281 100644 --- a/org.jgrapes.http/test/org/jgrapes/http/test/ClientTest.java +++ b/org.jgrapes.http/test/org/jgrapes/http/test/ClientTest.java @@ -65,8 +65,7 @@ public class ClientTest { public static class TestServer extends BasicTestServer { - public TestServer() - throws IOException, InterruptedException, ExecutionException { + public TestServer() throws Exception { super(Request.In.Get.class); } @@ -205,8 +204,7 @@ public void onCloseConnection(CloseConnection event) { private static TestClient clntApp; @BeforeClass - public static void startApps() throws IOException, InterruptedException, - ExecutionException { + public static void startApps() throws Exception { srvApp = new TestServer(); srvApp.attach(new InMemorySessionManager(srvApp.channel())); srvApp.attach(new TopProvider(srvApp.channel())); diff --git a/org.jgrapes.http/test/org/jgrapes/http/test/GetTest.java b/org.jgrapes.http/test/org/jgrapes/http/test/GetTest.java index 4e114a0d99b..33254d64604 100644 --- a/org.jgrapes.http/test/org/jgrapes/http/test/GetTest.java +++ b/org.jgrapes.http/test/org/jgrapes/http/test/GetTest.java @@ -55,8 +55,7 @@ public class GetTest { public static class TestServer extends BasicTestServer { - public TestServer() - throws IOException, InterruptedException, ExecutionException { + public TestServer() throws Exception { super(Request.In.Get.class); } @@ -153,8 +152,7 @@ public void getFromJar(Request.In.Get event, IOSubchannel channel) } @BeforeClass - public static void startServer() throws IOException, InterruptedException, - ExecutionException { + public static void startServer() throws Exception { server = new TestServer(); server.attach(new ContentProvider(server.channel())); Components.start(server); diff --git a/org.jgrapes.http/test/org/jgrapes/http/test/NotFoundTests.java b/org.jgrapes.http/test/org/jgrapes/http/test/NotFoundTests.java index f31abe658c8..b80d41d8f2f 100644 --- a/org.jgrapes.http/test/org/jgrapes/http/test/NotFoundTests.java +++ b/org.jgrapes.http/test/org/jgrapes/http/test/NotFoundTests.java @@ -36,8 +36,7 @@ public class NotFoundTests { public static class TestServer extends BasicTestServer { - public TestServer() - throws IOException, InterruptedException, ExecutionException { + public TestServer() throws Exception { super(Request.In.Get.class); } @@ -46,8 +45,7 @@ public TestServer() private static TestServer server; @BeforeClass - public static void startServer() throws IOException, InterruptedException, - ExecutionException { + public static void startServer() throws Exception { server = new TestServer(); Components.start(server); } diff --git a/org.jgrapes.http/test/org/jgrapes/http/test/PostTest.java b/org.jgrapes.http/test/org/jgrapes/http/test/PostTest.java index 05233f85084..3c84e8a81ef 100644 --- a/org.jgrapes.http/test/org/jgrapes/http/test/PostTest.java +++ b/org.jgrapes.http/test/org/jgrapes/http/test/PostTest.java @@ -39,8 +39,7 @@ public class PostTest { public static class TestServer extends BasicTestServer { - public TestServer() - throws IOException, InterruptedException, ExecutionException { + public TestServer() throws Exception { super(Request.In.Get.class); } @@ -50,8 +49,7 @@ public TestServer() static ReflectProvider contentProvider; @BeforeClass - public static void startServer() throws IOException, InterruptedException, - ExecutionException { + public static void startServer() throws Exception { server = new TestServer(); server.attach(new ReflectProvider(server.channel())); Components.start(server); diff --git a/org.jgrapes.http/test/org/jgrapes/http/test/UnsupportedProtocolTests.java b/org.jgrapes.http/test/org/jgrapes/http/test/UnsupportedProtocolTests.java index 1978c0f3235..fa810356419 100644 --- a/org.jgrapes.http/test/org/jgrapes/http/test/UnsupportedProtocolTests.java +++ b/org.jgrapes.http/test/org/jgrapes/http/test/UnsupportedProtocolTests.java @@ -35,8 +35,7 @@ public class UnsupportedProtocolTests { private static BasicTestServer server; @BeforeClass - public static void startServer() throws IOException, InterruptedException, - ExecutionException { + public static void startServer() throws Exception { server = new BasicTestServer(); Components.start(server); }