If you’ve decided to read this fairly technical blogpost, then you probably have at least a rough idea what SASL is about and why one would want to create custom SASL auth mechanisms or whitelist the supported mechanisms.
I’ll therefore provide just a very brief recap of the topics involved:
The Simple Authentication and Security Layer or SASL RFC 4422 is a framework for adding authentication support to connection-based protocols.
It provides an abstraction layer for authentication mechanisms, so that protocols, such as XMPP don’t have to deal with the intricacies and complexities of supporting multiple authentication mechanisms.
It therefore makes auth mechanisms pluggable (if they are SASL compatible).
Strophe.js has supported SASL since a long time, but it didn’t provide an easy way add custom SASL mechanisms, or to whitelist the mechanisms to be used.
Until now… or rather, since the 1.2.9 release.
Creating a custom SASL auth mechanism
To create a custom SASL authentication mechanism is fairly simple.
You can glean what’s required by simply looking at how the default mechanisms are created.
See for example how the SASLPlain mechanism is defined.
And look as the SASLMechanism prototype to see the interface that the mechanism supports.
Perty much it boils down to creating constructor, settings its prototype to an invoked Strophe.SASLMechanism instance, providing its name, a boolean to indicate whether it should proactively respond without an initial server challenge, and an integer value specifying its priority amongst the supported mechanisms.
The default mechanisms and their respective priorities are:
- EXTERNAL - 60
- OAUTHBEARER - 50
- SCRAM-SHA1 - 40
- DIGEST-MD5 - 30
- PLAIN - 20
- ANONYMOUS - 10
Then it’s a matter of implementing onChallenge
and any of the other
methods provided by the SASLMechanism prototype.
onChallenge
is called once the server challenges the client to
authenticate itself or proactively if the mechanism requires that the
client initiates authentication (configured with the isClientFirst
parameter of Strophe.SASLMechanism).
So, lets create a fictional auth mechanism called SASL-FOO which works similarly to SASL-PLAIN, except that the password is encrypted with double-encoding ROT13 (hint: this is a joke).
We would then create the authentication mechanism like so:
Strophe.SASLFoo = function () {};
Strophe.SASLFoo.prototype = new Strophe.SASLMechanism("FOO", true, 60);
Strophe.SASLFoo.prototype.onChallenge = function (connection) {
let auth_str = connection.authzid;
auth_str = auth_str + "u0000";
auth_str = auth_str + connection.authcid;
auth_str = auth_str + "u0000"; auth_str = auth_str + DoubleROT13(connection.pass);
return utils.utf16to8(auth_str);
};
Whitelisting the supported SASL auth mechanisms
Now with SASL-FOO in hand, we can whitelist the supported authentication
mechanisms by specifying a list of mechanisms in the options
map
passed in when we instantiate a new Strohe.Connection.
var service = 'chat.example.org';
var options = { 'mechanisms': [SASLFoo, Strophe.SASLPlain ] };
var conn = new Strophe.Connection(service, options);
Bonus: Whitelisting SASL auth mechanisms in Converse.js
Due to the above changes it’ll also be possible to whitelist SASL mechanisms in Converse.js (version 2.0.1 and upwards).
This is done via the connection_options configuration setting:
converse.initialize({
connection_options: {
'mechanisms': [converse.env.Strophe.SASLMD5, converse.env.Strophe.SASLPlain]
}
});
Happy hacking.