Connecting to a secured websocket
The correct way would be to configure your Client keystore / truststore to trust your specific self signed server certificate. There's plenty of answers on stackoverflow demonstrating how to do this with Java by simply configuring the keystore and/or truststore file contents appropriately. (no code necessary).
If you want to "just connect", and you don't care about trust, certificate validity, or even endpoint identification validation (basically all of the good things that make up a well secured connection) then you don't need to mess with keystores, and truststores, or custom X509TrustManagers
or even customized SSLContexts
to connect to the service. This need is common during development/testing/qa time, but should not be used in production code.
How you would do this with Jetty 9.4.35.v20201120 is to just configure the SslContextFactory.Client
(that belongs to the HttpClient
, which WebSocketClient
is using) to trust all certificates.
import java.net.URI;
import java.util.concurrent.Future;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.WebSocketClient;
@WebSocket
public class SecureClientSocket
{
private static final Logger LOG = Log.getLogger(SecureClientSocket.class);
public static void main(String[] args)
{
String url = "wss://qa.sockets.stackexchange.com/";
SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
// Tell sslContextFactory to trust all server certificates
// This is suitable for test/qa environments, and internal environments,
// but IS NOT SUITABLE FOR PRODUCTION.
// Note: this is not actually necessary for wss://qa.sockets.stackexchange.com/
sslContextFactory.setTrustAll(true);
// If you do choose to comment out the above, this option will cause the
// Java client side SSL/TLS to validate the server certificate name
// against the URL used to connect to the server, if it doesn't match
// then the connection is not established.
sslContextFactory.setEndpointIdentificationAlgorithm("HTTPS");
HttpClient httpClient = new HttpClient(sslContextFactory);
try
{
httpClient.start();
WebSocketClient client = new WebSocketClient(httpClient);
client.start();
SecureClientSocket socket = new SecureClientSocket();
Future<Session> fut = client.connect(socket, URI.create(url));
Session session = fut.get();
session.getRemote().sendString("Hello");
session.getRemote().sendString("155-questions-active");
}
catch (Throwable t)
{
LOG.warn(t);
}
}
@OnWebSocketConnect
public void onConnect(Session sess)
{
LOG.info("onConnect({})", sess);
}
@OnWebSocketClose
public void onClose(int statusCode, String reason)
{
LOG.info("onClose({}, {})", statusCode, reason);
}
@OnWebSocketError
public void onError(Throwable cause)
{
LOG.warn(cause);
}
@OnWebSocketMessage
public void onMessage(String msg)
{
LOG.info("onMessage() - {}", msg);
}
}
Which will have results like this ...
2020-12-21 14:03:28.228:INFO::main: Logging initialized @173ms to org.eclipse.jetty.util.log.StdErrLog
2020-12-21 14:03:28.401:WARN:oejusS.config:main: Trusting all certificates configured for Client@4b5a5ed1[provider=null,keyStore=null,trustStore=null]
2020-12-21 14:03:28.402:WARN:oejusS.config:main: No Client EndPointIdentificationAlgorithm configured for Client@4b5a5ed1[provider=null,keyStore=null,trustStore=null]
2020-12-21 14:03:28.862:INFO:j.SecureClientSocket:HttpClient@3712b94-60: onConnect(WebSocketSession[websocket=JettyAnnotatedEventDriver[jetty.SecureClientSocket@3f38289c],behavior=CLIENT,connection=WebSocketClientConnection@7556df66::DecryptedEndPoint@11c4a450{l=/192.168.1.217:46512,r=qa.sockets.stackexchange.com/198.252.206.25:443,OPEN,fill=-,flush=-,to=66/300000},remote=WebSocketRemoteEndpoint@278a12bf[batching=true],incoming=JettyAnnotatedEventDriver[jetty.SecureClientSocket@3f38289c],outgoing=ExtensionStack[queueSize=0,extensions=[],incoming=org.eclipse.jetty.websocket.common.WebSocketSession,outgoing=org.eclipse.jetty.websocket.client.io.WebSocketClientConnection]])
2020-12-21 14:03:30.648:INFO:j.SecureClientSocket:HttpClient@3712b94-62: onMessage() - {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"graphicdesign.stackexchange.com\",\"id\":138914,\"titleEncodedFancy\":\"How to achieve purple, paper background texture look?\",\"bodySummary\":\"How is the below purple background texture look achieved? I'm assuming it is a paper texture effect with different layers of light? However when I try to apply both the effect it never turns out the ...\",\"tags\":[\"texture\"],\"lastActivityDate\":1608581010,\"url\":\"https://graphicdesign.stackexchange.com/questions/138914/how-to-achieve-purple-paper-background-texture-look\",\"ownerUrl\":\"https://graphicdesign.stackexchange.com/users/155152/homan-cheung\",\"ownerDisplayName\":\"Homan Cheung\",\"apiSiteParameter\":\"graphicdesign\"}"}
2020-12-21 14:03:30.791:INFO:j.SecureClientSocket:HttpClient@3712b94-60: onMessage() - {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"unix.stackexchange.com\",\"id\":457386,\"titleEncodedFancy\":\"IPtables logging is not working in CentOS 7\",\"bodySummary\":\"I want to log all the traffic which comes in and out from the port X. I have followed below steps.\\r\\nEdited /etc/syslog.conf , /etc/rsyslog.conf , /etc/systemd/system/rsyslog.service.d/rsyslog.conf ...\",\"tags\":[\"centos\",\"kernel\",\"iptables\",\"logs\"],\"lastActivityDate\":1608581010,\"url\":\"https://unix.stackexchange.com/questions/457386/iptables-logging-is-not-working-in-centos-7\",\"ownerUrl\":\"https://unix.stackexchange.com/users/301499/karthikeyan-s\",\"ownerDisplayName\":\"Karthikeyan s\",\"apiSiteParameter\":\"unix\"}"}
2020-12-21 14:03:32.235:INFO:j.SecureClientSocket:HttpClient@3712b94-62: onMessage() - {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"math.stackexchange.com\",\"id\":812563,\"titleEncodedFancy\":\"Jacobian of exponential mapping in SO3/SE3\",\"bodySummary\":\"Following this post\\nJacobian matrix of the Rodrigues' formula (exponential map)\\n\\nWhat if I really need the Jacobian of the exponential mapping function in $\\\\omega \\\\neq 0$?\\n\\nBasically, I want to ...\",\"tags\":[\"lie-groups\",\"3d\",\"rotations\",\"numerical-optimization\",\"rigid-transformation\"],\"lastActivityDate\":1608581012,\"url\":\"https://math.stackexchange.com/questions/812563/jacobian-of-exponential-mapping-in-so3-se3\",\"ownerUrl\":\"https://math.stackexchange.com/users/153816/user153816\",\"ownerDisplayName\":\"user153816\",\"apiSiteParameter\":\"math\"}"}
2020-12-21 14:03:35.343:INFO:j.SecureClientSocket:HttpClient@3712b94-60: onMessage() - {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"raspberrypi.stackexchange.com\",\"id\":76325,\"titleEncodedFancy\":\"GCC version for compiling a loadable kernel module\",\"bodySummary\":\"I am not very familiar with Linux, so may be my question is a little bit foolish.\\n\\nI would like to compile kernel module without recompiling the kernel (USB Wi-Fi stick driver for MT7106U chip). I ...\",\"tags\":[\"kernel\",\"modules\",\"gcc\"],\"lastActivityDate\":1608581015,\"url\":\"https://raspberrypi.stackexchange.com/questions/76325/gcc-version-for-compiling-a-loadable-kernel-module\",\"ownerUrl\":\"https://raspberrypi.stackexchange.com/users/77643/cyclone125\",\"ownerDisplayName\":\"cyclone125\",\"apiSiteParameter\":\"raspberrypi\"}"}
2020-12-21 14:03:36.775:INFO:j.SecureClientSocket:JettyShutdownThread: onClose(1006, Disconnected)
Well, I tried using your code to replicate the problem with no avail ( get the certificate, import it with keytool command and then run the code ). my output is like this.
2015-03-22 23:03:16.192:INFO::main: Logging initialized @503ms
Socket Connected:WebSocketSession[websocket=JettyListenerEventDriver[com.ivan.Main],behavior=CLIENT,connection=WebSocketClientConnection@77ae29b0{IDLE}{f=Flusher[queueSize=0,aggregateSize=0,failure=null],g=Generator[CLIENT,validating],p=Parser@4e086d6d[ExtensionStack,s=START,c=0,len=0,f=null,p=WebSocketPolicy@7c0ceccc[behavior=CLIENT,maxTextMessageSize=65536,maxTextMessageBufferSize=32768,maxBinaryMessageSize=65536,maxBinaryMessageBufferSize=32768,asyncWriteTimeout=60000,idleTimeout=300000,inputBufferSize=4096]]},remote=WebSocketRemoteEndpoint@49f64[batching=true],incoming=JettyListenerEventDriver[com.ivan.Main],outgoing=ExtensionStack[queueSize=0,extensions=[],incoming=org.eclipse.jetty.websocket.common.WebSocketSession,outgoing=org.eclipse.jetty.websocket.client.io.WebSocketClientConnection]]
Received TEXT message: {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"cogsci.stackexchange.com\",\"id\":9404,\"titleEncodedFancy\":\"What's the difference between repetition suppression and habituation?\",\"bodySummary\":\"Neural repetition suppression seems to be describing behavioral habituation on a neuronal level. What's the difference between these two terms?\\n\",\"tags\":[\"cognitive-neuroscience\",\"terminology\",\"conditioning\",\"perceptual-learning\"],\"lastActivityDate\":1427036607,\"url\":\"http://cogsci.stackexchange.com/questions/9404/whats-the-difference-between-repetition-suppression-and-habituation\",\"ownerUrl\":\"http://cogsci.stackexchange.com/users/7569/recursive-farts\",\"ownerDisplayName\":\"RECURSIVE FARTS\",\"apiSiteParameter\":\"cogsci\"}"}
Received TEXT message: {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"mathematica.stackexchange.com\",\"id\":77933,\"titleEncodedFancy\":\"FunctionDomain doesn't work with If\",\"bodySummary\":\"When I call FunctionDomain for function defined by formule with If, for example \\n\\nf[x_]:=If[x<0, x, x^3], \\n\\nI get \\\"Unable to find the domain with the available methods\\\". What should I do to get a ...\",\"tags\":[\"functions\"],\"lastActivityDate\":1427036609,\"url\":\"http://mathematica.stackexchange.com/questions/77933/functiondomain-doesnt-work-with-if\",\"ownerUrl\":\"http://mathematica.stackexchange.com/users/27150/adolzi\",\"ownerDisplayName\":\"adolzi\",\"apiSiteParameter\":\"mathematica\"}"}
Received TEXT message: {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"serverfault.com\",\"id\":677390,\"titleEncodedFancy\":\"Smart Array E200i battery on 350ML did not fix the warning message (battery failure)\",\"bodySummary\":\"I have got this warning message on the System Management in a Proliant server 350ML G5.\\n\\nDegraded Accelerator\\nName Value\\nStatus: Temporarily Disabled\\nError Code: Cache Disabled Low Batteries\\nSerial ...\",\"tags\":[\"hp-proliant\",\"hp-smart-array\"],\"lastActivityDate\":1427036609,\"url\":\"http://serverfault.com/questions/677390/smart-array-e200i-battery-on-350ml-did-not-fix-the-warning-message-battery-fail\",\"ownerUrl\":\"http://serverfault.com/users/164557/dlopezgonzalez\",\"ownerDisplayName\":\"dlopezgonzalez\",\"apiSiteParameter\":\"serverfault\"}"}
Received TEXT message: {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"askubuntu.com\",\"id\":599889,\"titleEncodedFancy\":\"Is downgrading back to 14.04 from 14.10 possible?\",\"bodySummary\":\"I am using Ubuntu 14.10 alongside Windows 7 and I want to degrade to 14.04. I made a bootable pendrive using Universal USB Installer and seems like the pendrive is working fine. On the Installer Boot ...\",\"tags\":[\"14.04\",\"boot\",\"upgrade\",\"downgrade\"],\"lastActivityDate\":1427036610,\"url\":\"http://askubuntu.com/questions/599889/is-downgrading-back-to-14-04-from-14-10-possible\",\"ownerUrl\":\"http://askubuntu.com/users/374332/pkj\",\"ownerDisplayName\":\"pkj\",\"apiSiteParameter\":\"askubuntu\"}"}
Received TEXT message: {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"superuser.com\",\"id\":814765,\"titleEncodedFancy\":\"External Harddrive Shutting Off and On Every So Often While Listening to Music\",\"bodySummary\":\"I am always listening to music on my PC (always via VLC Player) and every so often - maybe once every 2 songs, sometimes more frequently- the music stops playing (VLC's buffer/progress bar stops ...\",\"tags\":[\"hard-drive\",\"power\",\"external\"],\"lastActivityDate\":1427036610,\"url\":\"http://superuser.com/questions/814765/external-harddrive-shutting-off-and-on-every-so-often-while-listening-to-music\",\"ownerUrl\":\"http://superuser.com/users/338547/supercookie47\",\"ownerDisplayName\":\"SuperCookie47\",\"apiSiteParameter\":\"superuser\"}"}
Received TEXT message: {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"math.stackexchange.com\",\"id\":1200778,\"titleEncodedFancy\":\"Continuity of a piecewise function at a specific point\",\"bodySummary\":\"I am having trouble proving the following function is not continuous at $x = 0$ using a formal definition of continuity.\\n\\n$\\nf(x) = \\\\left\\\\{\\n \\\\begin{array}{lr}\\n \\\\sin(\\\\frac{1}{x}) & : x \\\\neq 0\\\\\\\\\\n ...\",\"tags\":[\"real-analysis\",\"functions\",\"continuity\",\"epsilon-delta\"],\"lastActivityDate\":1427036612,\"url\":\"http://math.stackexchange.com/questions/1200778/continuity-of-a-piecewise-function-at-a-specific-point\",\"ownerUrl\":\"http://math.stackexchange.com/users/222744/george\",\"ownerDisplayName\":\"George\",\"apiSiteParameter\":\"math\"}"}
So i guess if you want a running web socket client in java, I guess you could just accept all certificate like the link that @tinker has gave to you.
The code should be like this. maybe you could try it and see what happen in your place.
import java.net.URI;
import java.security.cert.X509Certificate;
import java.util.concurrent.Future;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.eclipse.jetty.websocket.client.WebSocketClient;
public class Main extends WebSocketAdapter {
public static void main(String[] args) {
String url = "wss://qa.sockets.stackexchange.com/"; // or
// "wss://echo.websocket.org"
SslContextFactory sslContextFactory = new SslContextFactory();
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
} };
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
sslContextFactory.setSslContext(sc);
WebSocketClient client = new WebSocketClient(sslContextFactory);
client.start();
Future<Session> fut = client.connect(new Main(), URI.create(url));
Session session = fut.get();
session.getRemote().sendString("Hello");
session.getRemote().sendString("155-questions-active");
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
@Override
public void onWebSocketConnect(Session sess) {
super.onWebSocketConnect(sess);
System.out.println("Socket Connected: " + sess);
}
@Override
public void onWebSocketText(String message) {
super.onWebSocketText(message);
System.out.println("Received TEXT message: " + message);
}
@Override
public void onWebSocketClose(int statusCode, String reason) {
super.onWebSocketClose(statusCode, reason);
System.out.println("Socket Closed: [" + statusCode + "] " + reason);
}
@Override
public void onWebSocketError(Throwable cause) {
super.onWebSocketError(cause);
cause.printStackTrace(System.err);
}
}
Here's my Tyrus-java client using stub that I used to connect to my Jetty 9.3.6 server running HTTPS with a self-signed certificate (adapted from Tyrus websocket client, Section 8.1):
client = ClientManager.createClient();
//System.getProperties().put("javax.net.debug", "all"); // Useful for debugging SSL interaction
// The keystore in the next two lines is the same keystore you used for running the server,
// likely in ${jetty.base}/etc/keystore
System.getProperties().put(SSLContextConfigurator.KEY_STORE_FILE, "/tmp/keystore");
System.getProperties().put(SSLContextConfigurator.TRUST_STORE_FILE, "/tmp/keystore");
// The following two passwords are what you used for your self-signed cert
System.getProperties().put(SSLContextConfigurator.KEY_STORE_PASSWORD, "HumanReadablePassword");
System.getProperties().put(SSLContextConfigurator.TRUST_STORE_PASSWORD, "HumanReadablePassword");
final SSLContextConfigurator defaultConfig = new SSLContextConfigurator();
defaultConfig.retrieve(System.getProperties());
// or setup SSLContextConfigurator using its API.
SSLEngineConfigurator sslEngineConfigurator = new SSLEngineConfigurator(defaultConfig, true, false, false);
client.getProperties().put(GrizzlyEngine.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
client.connectToServer(sillyWebSocketClient , ClientEndpointConfig.Builder.create().build(),
new URI("wss://localhost:8443/sillyWebSocketServer/echo"));
System.out.println ("Connected .... ");
Where SillyWebSocketClient sillyWebSocketClient
extends javax.websocket.Endpoint
.
I am using a Java 8/Gradle 2.7 environment, and my build.gradle
looks like this:
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile 'javax:javaee-api:7.0'
compile 'org.glassfish.grizzly:grizzly-core:2.3.23'
compile 'org.glassfish.tyrus:tyrus-container-grizzly:1.2.1'
compile 'org.glassfish.tyrus:tyrus-client:1.6'
compile 'javax.websocket:javax.websocket-client-api:1.1'
}
Hope this helps.