Using SASL in FIX
This defines a mechanism for SASL authentication in the FIX protocol.
We define SASL as a modified authentication flow at the start of the FIX protocol. The existing fields suffice, and because authentication flows are generally pairwise agreements, the modification should not catch anyone by surprise.
Messages
FIX sessions start with a
Logon
request
and yield a response of the same type. For SASL, one or more of these exchanges is also used.
Note: The customary interpretation of a Logon
response is that authentication succeeded.
For that reason, the server must be willing to explicitly reject orders from non-SASL-compliant clients, which it can do on grounds of insufficient rights.
Related: FIX 5.0 defines messages
[UserRequest'](https://www.onixs.biz/fix-dictionary/5.0/msgType_BE_6669.html)
and
[
UserResponse](https://www.onixs.biz/fix-dictionary/5.0/msgType_BF_6670.html)
which are presumably sent at any time during the FIX protocol progress.
The
UserNamefield is required (but we could set it empty if we don't intend to reset the SASL status).
The same
RawDataLengthand
RawDatafields are available in the request, but not in the response, so its use is more limited for SASL.
It is however possible to use a
UserRequestto switch to an alias, pseudonym or group member identity; this would change Access Control and identity logging privacy; in this case
UserNamewould be set to the desired
user@domain.name` identity and ARPA2 Access would be used to validate the right to switch from the original authentication identity from SASL login at the session start; this means that the identity may be changed between alter-egos in the course of a FIX connection.
Fields
Target Domain.
The field
Username
can be sent by the client in user@domain.name
or @domain.name
form.
This calls for SASL handling with Realm Crossover, so with a Diameter backcall to one's domain.
This field is optional, and should only be used to initiate a new SASL authentication process.
Tokens.
The fields
RawDataLength
and subsequent
RawData
can be used to pass a SASL token in either direction in its binary form.
FIX takes care of this mixture of binary data by skipping the RawDataLength
bytes in the immmediately following RawData
field, so as to not get confused by any <SOH>
separators that could occur in the binary SASL token.
These fields are optional in SASL requests, so the necessary distinction can be made between not sending a token or sending an empty token.
Mechanisms.
The field
Password
can at some point be added to relay a mechanism list (server to client) or mechanism choice (client to server).
This field is optional and must only be used as an explicit signal. Generally, when the server sends this field it indicates a reset of the SASL exchange. Generally, when the client sends this field it indicates an attempt to use a SASL mechanism. Note how these definitions leave some room for play, including clients that start right away doin what they think is right, or servers restarting the exchange as a way to notify failure to the client.
It is permitted for the server to slow down or disconnect after (repeated) failures, or making an unavailable SASL mechanism choice after this has been submitted; but note that one frivolous attempt, namely before the first submission of a mechanism list by the server, is basically permitted (with a possible exception under denial-of-service attacks).
Security
SASL cannot generally be trusted over plaintext messaging, but when run over TLS without (routing) intermediates it should work well. TLS also assures that the authentication and subsequent business messages are tied together. In short, it is rarely safe to not use TLS.
Infrastructure
This exchange can be implemented with a FIX proxy, which would receive a TLS connection, then performs SASL authentication against the Realm Crossover infrastructure, and then continues imposing Access Control restrictions on messages passing through. There is a general
BusinessMessageReject
message to reject application-level messages, based on BusinessRejectReason
6, not authorized.
It would be improper use of the session-level
Reject
message to reject a message on grounds of authentication or authorisation.
Note how this also takes care of rejection of orders prior to having completed SASL authentication, because these are business-level or application-level messages. Authorisation failures are a reasonable ground for rejection when not even the underlying authentication has been completed.
Those application messages that do pass will be forwarded to a trading engine, anything else is rejected. The backend to this FIX proxy can now assume that the orders placed are legitimate, and may commence.
Implementation on QuickFix
The API for QuickFix is widely used, so it is a good testbed; it is also used often by developers who connect their tools to a new exchange; in that sense, introducing SASL in code extending QuickFix is not a wild idea.
The call that sends the LogOn
message in Session::generatoLogon
, with no argument or a Message&
argument. Both call sendRaw()
with a stack-allocated Message
object and update the state by calling m_state.setLogon(true)
.
After the (desired) response, the function m_state.receivedLogon()
returns true
. This function is called with a boolean argument to set it. This is set within Session::nextLogon()
after successful verify(logon,false,true)
; and it is reset by Session::disconnect()
. The call to nextLogin()
is made from Session::next()
for a message whose msgType == MsgType_Logon
.
The Session::verify()
method is quite general, the parameters are (msg,[checkTooHigh],[checkTooLow])
. It is about message integrity, not about account validity.
Picking up on the call to Session::nextLogin()
is the proper point of intervention. Are we being served with a challenge at this point, then we should formulate a reaction and reset timers and such for the newly sent Logon message. Otherwise, the message can be passed up to the original code that handles the LogOn
message as-is.