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. TheUserNamefield is required (but we could set it empty if we don't intend to reset the SASL status). The sameRawDataLengthandRawDatafields are available in the request, but not in the response, so its use is more limited for SASL. It is however possible to use aUserRequestto switch to an alias, pseudonym or group member identity; this would change Access Control and identity logging privacy; in this caseUserNamewould be set to the desireduser@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.