Authenticating¶
Once a client receives a CONNECTED frame, it must authenticate
the session, using the scheme specified in the authenticate header. Authentication is performed by
sending a SEND frame with a destination header value of /setup/authenticate and an
authorization header with the appropriate credentials, the syntax of which depends on the scheme
used. The only supported scheme at this time is SNS.
Note
The scheme might require additional headers, some of which may be provided on the CONNECTED
frame. Consult the scheme documentation for more details.
After publishing the SEND authentication frame, if the authentication is successful nothing will
happen and the client application can move on to subscribing to the setup topic
to start interacting with the STOMP Server. If the authentication fails, the server will send an
ERROR frame to the client and close the connection.
SNS authentication scheme¶
The SNS scheme uses an HMAC+SHA256 digest of various parts of the STOMP frame, signed using
a secret key derived from the SolarNode user's hashed password. SolarNode does not store a
plain-text version of a user's password, so that is why the hashed password is used for the signing
key.
The required SEND headers for SNS authentication are:
| Header | Description |
|---|---|
authorization |
The SNS authorization value, e.g. SNS Credential=me@example.com,SignedHeaders=date,Signature=168365.... |
date |
The request date, e.g. Mon, 16 Aug 2021 02:27:39 GMT. |
SEND
destination:/setup/authenticate
date:Mon, 16 Aug 2021 02\c27\c39 GMT
authorization: SNS Credential=me@example.com,SignedHeaders=date,Signature=168365...
Escaping the date header for STOMP
When encoding the date header, be sure to escape the : character in the date value with \c,
per the STOMP specification.
This encoding is only needed in the STOMP header, not in the SNS signature calculation.
The canonical request message of the signing message must use the following values:
| Component | Description |
|---|---|
| Verb | Must be SEND. |
| Path | Must be /setup/authenticate. |
| Signed header names | Only date is required. |
SNS authentication example¶
Here is a basic example in Java that uses the
SnsAuthorizationBuilder class to generate the required
authorization and date headers required by the SNS scheme:
String secret = "value-derived-from-password"; // depends on `auth-hash` CONNECTED header
SnsAuthorizationBuilder authBuilder = new SnsAuthorizationBuilder("me@example.com")
.date(now)
.verb("SEND")
.path("/setup/authenticate");
String authHeader = authBuilder.build(secret);
String dateHeader = authBuilder.headerValue("date");
BCrypt secret derivation¶
The auth-hash:bcrypt CONNECTED header indicates that the
BCrypt digest algorithm must be used to derive the SNS secret value used to sign the request, that
in turn converted into by a hex-encoded SHA-256 digest. At a high level the algorithm in pseudo-code
looks like this:
secret := Hex(Sha256(BCrypt(password, salt)))
The auth-hash-param-salt header value from the CONNECTED
frame will determine the BCrypt salt that must be used to digest the user's plain-text password. The
salt will take the form of
$2a$10$1234567890123456789012
Here $2a indicates the version of BCrypt used, $10 indicates the number of iterations used, and
everything after the final $ is the Base64 encoded salt used.
BCrypt secret example¶
The SnsAuthorizationBuilder class can be used to generate the
required authorization header value. See this example for
more details; here is that example distilled:
String salt = "$2a$10$upVbEZHge9Iph1NN3L6ENO"; // from auth-hash-param-salt CONNECTED header
String secret = DigestUtils.sha256Hex(BCrypt.hashpw("password123", salt));
SnsAuthorizationBuilder authBuilder = new SnsAuthorizationBuilder("me@example.com")
.date(now)
.verb("SEND")
.path("/setup/authenticate");
String authHeader = authBuilder.build(secret);
String dateHeader = authBuilder.headerValue("date");