WebSocket over SSL in embedded Jetty 9
Asked Answered
R

1

5

For this question I have prepared a test project WssEmbedded, which listens for incoming WebSocket connections at localhost:8080 and localhost:8443.

In the MyHandler class I create 2 connectors for this purpose:

public class MyHandler extends WebSocketHandler {
    @Override
    public void configure(WebSocketServletFactory factory) {
        factory.register(MyListener.class);
    }

    public static void main(String[] args) throws Exception {
        SslContextFactory sslContextFactory = new SslContextFactory();
        sslContextFactory.setKeyStorePath("keystore.jks");
        sslContextFactory.setKeyStorePassword("OBF:1l1a1s3g1yf41xtv20731xtn1yf21s3m1kxs");

        Server server = new Server();
        server.setHandler(new MyHandler());

        ServerConnector wsConnector = new ServerConnector(server);
        wsConnector.setHost("127.0.0.1");
        wsConnector.setPort(8080);
        server.addConnector(wsConnector);

        ServerConnector wssConnector = new ServerConnector(server,
            new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()));
        wssConnector.setHost("127.0.0.1");
        wssConnector.setPort(8443);
        server.addConnector(wssConnector);

        server.start();
        server.join();
    }
}

I have added a key/certificate pair to keystore.jks with:

keytool -genkey -alias key1 -keyalg RSA -keypass password1 -keystore keystore.jks -storepass password1

screenshot

The server starts without problems:

2016-06-22 13:34:45.254:INFO::main: Logging initialized @641ms
2016-06-22 13:34:45.404:INFO:oejs.Server:main: jetty-9.3.9.v20160517
2016-06-22 13:34:45.544:INFO:oejs.AbstractConnector:main: Started ServerConnector@3b354e17{HTTP/1.1,[http/1.1]}{127.0.0.1:8080}
2016-06-22 13:34:45.594:INFO:oejus.SslContextFactory:main: x509=X509@64d2d351(key1,h=[],w=[]) for SslContextFactory@1b68b9a4(file:///C:/Users/user1/jetty-newbie/WssEmbedded/keystore.jks,null)
2016-06-22 13:34:46.084:INFO:oejs.AbstractConnector:main: Started ServerConnector@1e53a15{SSL,[ssl]}{127.0.0.1:8443}
2016-06-22 13:34:46.084:INFO:oejs.Server:main: Started @1476ms

Then I have prepared a simple WssClient project for testing the above server:

public static void main(String[] args) {
    final String WS_URL = "ws://127.0.0.1:8080";

    MyListener socket = new MyListener("Hello world");
    SslContextFactory sslContextFactory = new SslContextFactory();
    sslContextFactory.setTrustAll(true); 
    WebSocketClient client = new WebSocketClient(sslContextFactory);

    try {
        client.start();
        URI uri = new URI(WS_URL);
        ClientUpgradeRequest cur = new ClientUpgradeRequest();
        client.connect(socket, uri, cur);
        socket.awaitClose(5, TimeUnit.SECONDS);
    } catch (Throwable t) {
        t.printStackTrace();
    } finally {
        try {
            client.stop();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

The client works well and prints:

2016-06-22 13:36:06.130:INFO::main: Logging initialized @205ms
onWebSocketConnect: /127.0.0.1:8080
REQUEST:
Hello world
RESPONSE:
Hello /127.0.0.1:58518
onWebSocketClose: 1000 null

The server works well and prints:

2016-06-22 13:35:54.057:INFO:daw.MyListener:qtp1597462040-19: onWebSocketConnect: /127.0.0.1:58511
2016-06-22 13:35:54.097:INFO:daw.MyListener:qtp1597462040-14: onWebSocketText: Hello world
2016-06-22 13:35:54.107:INFO:daw.MyListener:qtp1597462040-13: onWebSocketClose: 1000 - null

However, when I change to WS_URL = "wss://127.0.0.1:8443" then it fails with:

2016-06-22 13:36:29.063:INFO::main: Logging initialized @208ms
onWebSocketError: java.nio.channels.ClosedChannelException

What have I missed here please? How to debug this?

UPDATE:

Thinking that the problem could be the self-signed certificate used above, I have taken a Thawte certificate valid for 3 years for my web domains slova.de and www.slova.de (they point to different IP addresses!) and imported it on CentOS 7 Linux into keystore using Oracle jdk1.8.0_91-1.8.0_91-fcs.x86_64:

# keytool  -importcert -file /etc/pki/tls/certs/slova.de.crt -keystore keystore.jks -storepass password1

Owner: CN=slova.de
Issuer: CN=thawte DV SSL SHA256 CA, OU=Domain Validated SSL, O="thawte, Inc.", C=US
Serial number: 9354a665699cafbfa7875490d5a9894
Valid from: Mon Apr 04 02:00:00 CEST 2016 until: Fri Apr 05 01:59:59 CEST 2019
Certificate fingerprints:
     MD5:  33:BB:62:8A:09:24:11:0F:C9:40:AA:68:F4:CD:2A:B7
     SHA1: 52:E2:B6:79:55:F4:FE:05:0D:2E:7C:18:78:58:22:16:ED:28:4F:B6
     SHA256: A3:D3:83:4E:99:01:BF:AE:FB:EB:59:40:23:74:1D:28:93:4B:20:15:1D:E1:AC:1A:97:31:C6:0C:9B:E1:2D:03
     Signature algorithm name: SHA256withRSA
     Version: 3

As you can see, I have now a trusted certificate there:

# keytool  -list -keystore keystore.jks -storepass password1

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 2 entries

key1, Jun 22, 2016, PrivateKeyEntry, 
Certificate fingerprint (SHA1): 8F:7D:8E:E0:8F:9E:39:A1:0C:23:D3:FF:4B:47:F5:0D:BA:EC:EE:F3
mykey, Jun 22, 2016, trustedCertEntry, 
Certificate fingerprint (SHA1): 52:E2:B6:79:55:F4:FE:05:0D:2E:7C:18:78:58:22:16:ED:28:4F:B6

Then I have started the WssEmbedded program at the www.slova.de:8443 (at my Linux server it is different IP address from slova.de on which Apache is running):

# java -classpath $CPATHS de.afarber.wssembedded.MyHandler 144.76.184.154:8443

2016-06-22 19:45:21.093:INFO::main: Logging initialized @73ms
2016-06-22 19:45:21.144:INFO:oejs.Server:main: jetty-9.3.9.v20160517
2016-06-22 19:45:21.167:INFO:oejs.AbstractConnector:main: Started ServerConnector@6a38e57f{HTTP/1.1,[http/1.1]}{www.slova.de:8080}
2016-06-22 19:45:21.188:INFO:oejus.SslContextFactory:main: x509=X509@7a46a697(key1,h=[],w=[]) for SslContextFactory@5f205aa(file:///usr/share/java/words/keystore.jks,null)
2016-06-22 19:45:21.189:INFO:oejus.SslContextFactory:main: x509=X509@6d86b085(mykey,h=[slova.de, www.slova.de],w=[]) for SslContextFactory@5f205aa(file:///usr/share/java/words/keystore.jks,null)
2016-06-22 19:45:21.327:INFO:oejs.AbstractConnector:main: Started ServerConnector@71bbf57e{SSL,[ssl]}{www.slova.de:8443}
2016-06-22 19:45:21.327:INFO:oejs.Server:main: Started @309ms

And then I have run WssClient against wss://www.slova.de:8443 in NetBeans at my Macbook:

Executing command line: /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/bin/java -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=56634 -classpath /Users/afarber/src/jetty-newbie/WssClient/target/classes:/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-client/9.3.9.v20160517/websocket-client-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-util/9.3.9.v20160517/jetty-util-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-io/9.3.9.v20160517/jetty-io-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-common/9.3.9.v20160517/websocket-common-9.3.9.v20160517.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/websocket/websocket-api/9.3.9.v20160517/websocket-api-9.3.9.v20160517.jar de.afarber.wssclient.Main
2016-06-22 19:45:31.718:INFO::main: Logging initialized @325ms
onWebSocketError: java.nio.channels.ClosedChannelException

(Nothing changed at the WssEmbedded server output).

Please help, how to get WSS working with embedded Jetty 9?

Rigmarole answered 22/6, 2016 at 11:57 Comment(2)
What specific JVM are you using? As the SSL/TLS security settings at the JVM level could be getting in your way.Giuliana
I use Oracle Java 1.8.0_66-b18 on 64-bit Win 7 and my production server is 64-bit CentOS 7 Linux with: java-1.8.0-openjdk-1.8.0.91-0.b14.el7_2.x86_64 and also Oracle jdk1.8.0_91. And just tried with with Oracle jdk1.8.0_45.jdk on Mac OSX Yosemite and get onWebSocketError: org.eclipse.jetty.io.EofException in WssClientRigmarole
R
7

After adding -Dorg.eclipse.jetty.LEVEL=DEBUG -Djavax.net.debug=ssl friendly folks at the Jetty mailing list have pointed out, that there were NPEs at the server side caused by missing HttpConnectionFactory.

I have missed to copy that part from the embedded/LikeJettyXML example.

The following code in wssembedded/MyHandler.java works better:

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

    Server server = new Server();
    server.setHandler(new MyHandler());

    HttpConfiguration http_config = new HttpConfiguration();
    http_config.setSecureScheme("https");
    http_config.setSecurePort(8443);

    HttpConfiguration https_config = new HttpConfiguration(http_config);
    https_config.addCustomizer(new SecureRequestCustomizer());

    SslContextFactory sslContextFactory = new SslContextFactory();
    sslContextFactory.setKeyStorePath("keystore.jks");
    sslContextFactory.setKeyStorePassword("OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0");

    ServerConnector wsConnector = new ServerConnector(server);
    wsConnector.setHost("localhost");
    wsConnector.setPort(8080);
    server.addConnector(wsConnector);

    ServerConnector wssConnector = new ServerConnector(server,
        new SslConnectionFactory(sslContextFactory,
            HttpVersion.HTTP_1_1.asString()),
        new HttpConnectionFactory(https_config)); // THIS WAS MISSING

    wssConnector.setHost("localhost");
    wssConnector.setPort(8443);
    server.addConnector(wssConnector);

    server.start();
    server.join();
}
Rigmarole answered 25/6, 2016 at 7:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.