Search code examples
javawebsocketjava-websocketws

How to give certificate to Java Websocket?


Forgive me for the newb question, but I am confused and obviously not understanding the fundamentals or explanations of how to use a Websocket server hosted over HTTPS. Everything I find online leads me to have more questions than answers.

I have a Websocket server hosted on my HTTPS website using Java code.

This is my WebsocketServer.java file:

import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Set;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class WebsocketServer extends WebSocketServer {

    private static final Logger logger = LogManager.getLogger(WebsocketServer.class);

    private static int TCP_PORT = 6868;

    private static Set<WebSocket> conns;

    public WebsocketServer() {
        super(new InetSocketAddress(TCP_PORT));
        conns = new HashSet<>();
    }

    @Override
    public void onOpen(WebSocket conn, ClientHandshake handshake) {
        conns.add(conn);
        logger.info("New connection from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
        logger.info("Size of connection list: " + conns.size());
    }

    @Override
    public void onClose(WebSocket conn, int code, String reason, boolean remote) {
        conns.remove(conn);
        logger.info("Closed connection to " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
    }

    @Override
    public void onMessage(WebSocket conn, String message) {
        logger.info("Message from client: {}", message);
        // for (WebSocket sock : conns) {
        // sock.send("SENDING BACK" + message);
        // }
    }

    @Override
    public void onError(WebSocket conn, Exception ex) {

        // ex.printStackTrace();
        try {
            if (conn != null) {
                conns.remove(conn);
                // do some thing if required
            }
            logger.info("ERROR from {}", conn.getRemoteSocketAddress().getAddress().getHostAddress());
        } catch (Exception e) {
            logger.info("onError: WebSocketServer may already be running");

        }

    }

    public Set<WebSocket> getConns() {
        return conns;
    }

}

Then I started the WebsocketServer like this:

WebsocketServer websocketServer;
// Start socket server
websocketServer = new WebsocketServer();
websocketServer.start();

And on the client side, I connect to it like this:

    // APP_WEB_SOCKET is the url to my site: api.my_custom_domain.com
    var connection = new WebSocket("wss://" + APP_WEB_SOCKET + ":6868");

QUESTIONS: I keep reading that I need a certificate if I want to use wss over HTTPS, but cannot find any documents that explain what this means in a way that I can understand.

My app is hosted in AWS Elastic Beanstalk environment. Do I need to somehow add a certificate to the setup of the WebsocketServer in my Java code? Example:

WebsocketServer websocketServer;
// Start socket server
websocketServer = new WebsocketServer();

// example guessing
websocketServer.cert = "SOMETHING";??
websocketServer.start();

Does the client code need to be changed at all?

Who needs the certificate?

If someone could please explain what I am missing or point me in the correct direction, I would really appreciate it.


Solution

  • Keep it easy.
    Certs inside your application are complex - they are hard to manage and you will get problems to run your application in a modern cloud environment (start new environments, renew certs, scale your application, ...).

    Simple conclusion: Dont implement any certs.

    How-to get encrypted connections?

    As Mike already pointed out in the comments: WebSockets are just upgraded HTTP(S) connections. A normal webserver (nginx, apache) takes care about the certs. It can be done in kubernetes (as ingress-controller) or with a "bare-metal" webserver.
    Both of them should act as a reverse-proxy. This means: Your java-application doesn't know anything about certs. It has just unencrypted connections - like in your code on port 6868.
    But the client will not use this port. 6868 is only internally reachable.

    The client will call your reverse-proxy at the normal HTTPS port (=443). The reverse-proxy will forward the connection to your java-application.

    Here some links for further information: