Testing FME WebSocket with OpenSSL and WSCAT

Learn how to validate that FME WebSockets are correctly configured and operational.

Projects: c2platform/rws/ansible-gis, c2platform.wincore, c2platform.gis


When FME Flow is installed, WebSockets are configured by default using the ws protocol. In the Ansible inventory project c2platform/rws/ansible-gis, WebSockets are configured to be secure and use the wss protocol. Misconfiguration can break the WebSockets feature. This guide offers three methods to verify WebSocket functionality:

  1. Using the OpenSSL Library.
  2. Using the WSCAT utility.
  3. Using a custom PowerShell script.

Prerequisites

  • Follow Setting Up FME Flow with Ansible to set up the FME environment, which consists of gsd-fme-core, gsd-ad, gsd-db1, and gsd-rproxy1. These nodes should be up and running.

SSH into gsd-rproxy1

To run the tests using OpenSSL and WSCAT, connect to gsd-rproxy1:

vagrant ssh gsd-rproxy1

Test WebSocket using OpenSSL

The gsd-rproxy1 node has the OpenSSL library installed by default.

  1. Establish a secure SSL/TLS connection to the server:

    openssl s_client -connect gsd-fme-core:7078
    

    Show me

    root@gsd-rproxy1:~# openssl s_client -connect gsd-fme-core:7078
    CONNECTED(00000003)
    Can't use SSL_get_servername
    depth=1 CN = c2
    verify return:1
    depth=0 C = NL, ST = Zuid-Holland, L = Den Haag, O = C2, OU = C2 GIS Platform Team, CN = gsd-fme-core
    verify return:1
    ---
    Certificate chain
    0 s:C = NL, ST = Zuid-Holland, L = Den Haag, O = C2, OU = C2 GIS Platform Team, CN = gsd-fme-core
       i:CN = c2
       a:PKEY: rsaEncryption, 4096 (bit); sigalg: RSA-SHA256
       v:NotBefore: Sep  2 07:34:13 2024 GMT; NotAfter: Aug 31 07:34:13 2034 GMT
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    MIIFyjCCA7KgAwIBAgIUFMVOmvJuY7/68kemIj6HCLuiTy4wDQYJKoZIhvcNAQEL
    BQAwDTELMAkGA1UEAwwCYzIwHhcNMjQwOTAyMDczNDEzWhcNMzQwODMxMDczNDEz
    WjB6MQswCQYDVQQGEwJOTDEVMBMGA1UECAwMWnVpZC1Ib2xsYW5kMREwDwYDVQQH
    (lines deleted)
    bocbN6ZKuDSO4087FzwjMOJ5yGxMAQymcGmiyZrM4D5iIrf3ozr8SAQ3lXDAnfZ9
    0RG2T5QteaD9ThQOsseGBq6HURphzOFtzL/FGR1nNr6jCGA5001+FQ/77dP84A==
    -----END CERTIFICATE-----
    subject=C = NL, ST = Zuid-Holland, L = Den Haag, O = C2, OU = C2 GIS Platform Team, CN = gsd-fme-core
    issuer=CN = c2
    ---
    No client certificate CA names sent
    Peer signing digest: SHA256
    Peer signature type: RSA-PSS
    Server Temp Key: X25519, 253 bits
    ---
    SSL handshake has read 2274 bytes and written 373 bytes
    Verification: OK
    ---
    New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
    Server public key is 4096 bit
    Secure Renegotiation IS NOT supported
    Compression: NONE
    Expansion: NONE
    No ALPN negotiated
    Early data was not sent
    Verify return code: 0 (ok)
    ---
    ---
    Post-Handshake New Session Ticket arrived:
    SSL-Session:
       Protocol  : TLSv1.3
       Cipher    : TLS_AES_256_GCM_SHA384
       Session-ID: 8AC31E962569F35F4A9C6FD9DE5FF5308D819A012DB754FFF88ED573E19C5DF1
       Session-ID-ctx:
       Resumption PSK: 727A2C1C5D2B4EC513E941C9C759998493743FADED7E74E92AADC4C951EDF6A43E59775010FB465920C07B57DE42F96A
       PSK identity: None
       PSK identity hint: None
       SRP username: None
       TLS session ticket lifetime hint: 86400 (seconds)
       TLS session ticket:
       0000 - 7a b5 a3 f2 b0 91 51 91-6a 90 1c 40 3f 8f 79 f4   z.....Q.j..@?.y.
       0010 - fe 9f 42 86 fe 69 b1 20-45 2c 04 ff 0a 6f cd 6a   ..B..i. E,...o.j
       0020 - 29 8c 99 c2 d8 79 aa 17-11 53 56 ab c8 2a fc 22   )....y...SV..*."
    (lines deleted)
       06a0 - 43 d6 b3 c1 7f 62 55 50-7d a3 53 a4 3d 2c c3 30   C....bUP}.S.=,.0
       06b0 - 56 5d a9 ef 21 e0 8e 1e-27 0c f9 cf 61 ed         V]..!...'...a.
    
       Start Time: 1725356133
       Timeout   : 7200 (sec)
       Verify return code: 0 (ok)
       Extended master secret: no
       Max Early Data: 0
    

  2. Initiate the WebSocket handshake by manually inputting the following lines after the secure connection is established:

    GET /websocket HTTP/1.1
    Host: gsd-fme-core:7078
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: h3aOngl22xTlrMuoCGC4+w==
    Sec-WebSocket-Version: 13
    

    Note: Sec-WebSocket-Key is a Base64-encoded random value1.

  3. To submit your input, press enter twice to send a double newline.

  4. The response should be something like:

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: AEwKHncza7ZXcfBb5yM/aluzmpE=
    

    This response indicates a successful WebSocket handshake, confirming that the HTTP connection is now upgraded to a WebSocket connection.

To perform a more comprehensive test that also validates the wss scheme, you will need a WebSocket client library like WSCAT2.

WSCAT

This section describes how to validate FME WebSockets using WSCAT  .

Install NodeJS, NPM, and WSCAT

To install WSCAT, run the following commands on the gsd-proxy1 node:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
nvm install 20
node -v
npm -v
npm install -g wscat

Show me

vagrant@gsd-rproxy1:~$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
nvm install 20
node -v
npm -v
npm install -g wscat
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 15916  100 15916    0     0  68354      0 --:--:-- --:--:-- --:--:-- 68603
=> Downloading nvm from git to '/home/vagrant/.nvm'
=> Cloning into '/home/vagrant/.nvm'...
remote: Enumerating objects: 376, done.
remote: Counting objects: 100% (376/376), done.
remote: Compressing objects: 100% (324/324), done.
remote: Total 376 (delta 43), reused 168 (delta 25), pack-reused 0 (from 0)
Receiving objects: 100% (376/376), 374.67 KiB | 6.46 MiB/s, done.
Resolving deltas: 100% (43/43), done.
* (HEAD detached at FETCH_HEAD)
  master
=> Compressing and cleaning up git repository

=> Appending nvm source string to /home/vagrant/.bashrc
=> Appending bash_completion source string to /home/vagrant/.bashrc
=> Close and reopen your terminal to start using nvm or run the following to use it now:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
Downloading and installing node v20.17.0...
Downloading https://nodejs.org/dist/v20.17.0/node-v20.17.0-linux-x64.tar.xz...
#################################################################################################### 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v20.17.0 (npm v10.8.2)
Creating default alias: default -> 20 (-> v20.17.0)
v20.17.0
10.8.2

added 9 packages in 1s
npm notice
npm notice New patch version of npm available! 10.8.2 -> 10.8.3
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.8.3
npm notice To update run: npm install -g npm@10.8.3
npm notice
vagrant@gsd-rproxy1:~$ wscat --help
Usage: wscat [options] (--listen <port> | --connect <url>)

Options:
  -V, --version                       output the version number
  --auth <username:password>          add basic HTTP authentication header (--connect only)
  --ca <ca>                           specify a Certificate Authority (--connect only)
  --cert <cert>                       specify a Client SSL Certificate (--connect only)
  --host <host>                       optional host
  --key <key>                         specify a Client SSL Certificate's key (--connect only)
  --max-redirects [num]               maximum number of redirects allowed (--connect only) (default: 10)
  --no-color                          run without color
  --passphrase [passphrase]           specify a Client SSL Certificate Key's passphrase (--connect only).
                                      If you don't provide a value, it will be prompted for
  --proxy <[protocol://]host[:port]>  connect via a proxy. Proxy must support CONNECT method
  --slash                             enable slash commands for control frames (/ping [data], /pong
                                      [data], /close [code [, reason]])
  -c, --connect <url>                 connect to a WebSocket server
  -H, --header <header:value>         set an HTTP header. Repeat to set multiple (--connect only)
                                      (default: [])
  -L, --location                      follow redirects (--connect only)
  -l, --listen <port>                 listen on port
  -n, --no-check                      do not check for unauthorized certificates
  -o, --origin <origin>               optional origin
  -p, --protocol <version>            optional protocol version
  -P, --show-ping-pong                print a notification when a ping or pong is received
  -s, --subprotocol <protocol>        optional subprotocol (default: [])
  -w, --wait <seconds>                wait given seconds after executing command
  -x, --execute <command>             execute command after connecting
  -h, --help                          display help for command
vagrant@gsd-rproxy1:~$

Test WebSocket using WSCAT

To test the WebSocket using WSCAT, run the following command on gsd-rproxy1:

wscat -c wss://gsd-fme-core:7078/websocket --ca /vagrant/.ca/c2/c2.crt

This command should respond with “Connected (press CTRL+C to quit)”. Note that you have to provide the Certificate Authority (CA) bundle/certificate c2.crt. Alternatively, you can provide -n or --no-check to skip certificate verification. See wscat --help for more options.

Show me

vagrant@gsd-rproxy1:~$ wscat -c wss://gsd-fme-core:7078/websocket --ca /vagrant/.ca/c2/c2.crt
Connected (press CTRL+C to quit)
> vagrant@gsd-rproxy1:~$ wscat -c wss://gsd-fme-core:7078/websocket -n
Connected (press CTRL+C to quit)
> vagrant@gsd-rproxy1:~$ wscat -c wss://gsd-fme-core:7078/websocket
error: unable to verify the first certificate
> vagrant@gsd-rproxy1:~$

Test WebSocket using PowerShell

You can also use a simple PowerShell script to test the connection. First, connect to the FME Flow node gsd-fme-core:

vagrant ssh gds-fme-core

Start PowerShell:

powershell

Execute the script websocket-test.ps1:

cd c:\vagrant\scripts\gsd-fme-core
.\websocket-test.ps1

Show me

Microsoft Windows [Version 10.0.20348.707]
(c) Microsoft Corporation. All rights reserved.

vagrant@GSD-FME-CORE C:\Users\vagrant>cd c:\vagrant\scripts\gsd-fme-core

vagrant@GSD-FME-CORE c:\vagrant\scripts\gsd-fme-core>powershell
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows

PS C:\vagrant\scripts\gsd-fme-core> .\websocket-test.ps1
Successfully established secure WebSocket connection
PS C:\vagrant\scripts\gsd-fme-core>

Footnotes


  1. The key Sec-WebSocket-Key is a Base64-encoded random value generated by the client. This value is used by the server to generate a response key for agreeing to the WebSocket connection. You can generate your own Sec-WebSocket-Key using the command:

    openssl rand -base64 16
    
     ↩︎
  2. The test using the OpenSSL library command opens a TLS/SSL connection to the specified server. This ensures that the underlying transport (from client to server) is encrypted using TLS/SSL. However, the WebSocket protocol negotiated over that connection is separate from the security offered by the transport layer. To test wss specifically, use a WebSocket client library (like WSCAT or a browser with WebSocket support), specifying the wss scheme. ↩︎



Last modified September 4, 2024: rws websocket test RWS-949 (d65ce1b)