How to use XMPP SASL EXTERNAL with Node.js

Almost a year ago I came across Node.js for the first time. Without going into details I must admit that a kind of like it. It has been useful to me in various projects. I especially like it for rapid prototyping or for creating some temporary service that is useful within a development environment. Like every framework, Node.js has some issues. Personally I don’t like for larger, more complex, projects.

But… This post is not about Node.js. I wanted to give a brief introduction because I never blogged about Node.js before.

The post is about using SASL EXTERNAL in node-xmpp, a Node.js module for XMPP communication. For a project that I am a part of I investigated certificate based authentication to an XMPP server. I found the node-xmpp module to be the best available XMPP module for Node.js out there but it didn’t support the EXTERNAL authentication scheme as describe in XEP-0178, so I decided to add it myself.

SASL EXTERNAL is not used widely in the XMPP world. There are only a few clients and servers supporting it (as far as I know of). Openfire and Prosody support EXTERNAL for client to server authentication on the server side. Since I was already running an Openfire server I decided to give it a try on that.

To get stuff working I went trough the following steps:

  1. Create a test certificate authority (CA) and configure Openfire to use the EXTERNAL authentication mechanism
  2. Pull node-xmpp from the git (EXTERAL will hopefully be part of the 0.4 release of node-xmpp)
  3. Create a test client
  4. Test if it works

I will go through these steps in more detail below.

Create a test CA and configure Openfire

On the Pidgin wiki I found a walkthrough that guided me to most of these steps. I am not going to repeat these steps but I will give some pointers to solve issues I ran in to:

  • Configure Openfire first. Openfire will create a client.trustore when it is restarted
  • Restart Openfire after adding the CA key to the keystore
  • The property sasl.mechs should have a comma separated list of SASL mechanisms as the value. For example: EXTERNAL,DIGEST-MD5,PLAIN,CRAM-MD5
  • Create a test CA. Convert the public certificate of the CA to x509 and import it into the client.trusttore. After that create certificate/key pair for each user and sign the certificates with the CA.

Pull node-xmpp from the git

That is simple, just issue:


git clone git://github.com/astro/node-xmpp.git

Create a test client

I did that piece of work already, just copy my echo_bot_sasl_external.js gist.


#!/usr/bin/env node
/**
* Echo Bot – the XMPP Hello World
*
* Copied from the echo_bot.js example from node-xmpp.
**/
var xmpp = require('../lib/node-xmpp');
var argv = require('optimist').argv;
var fs = require('fs');
var argv = require('optimist')
.usage('Usage: echo_bot_sasl_external.js –jid=<my-jid> [–host=<host>] [–port=<port>] [–legacy_ssl]')
.demand(['jid'])
.boolean('legacy_ssl')
.argv;
var credentials = {
// These are necessary only if using the client certificate authentication
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem'),
// You might want to put the passphrase of the key file here. You'll be prompted otherwise.
// passphrase: 'YOUR_PASSPHRASE'
};
var options = { jid: argv.jid, 'credentials': credentials };
if (argv.host) options['host'] = argv.host;
if (argv.port) options['port'] = argv.port;
if (argv.legacy_ssl) options['legacySSL'] = argv.legacy_ssl;
var cl = new xmpp.Client(options);
cl.on('online', function() {
console.log('online');
cl.send(new xmpp.Element('presence', { }).
c('show').t('chat').up().
c('status').t('Happily echoing your <message/> stanzas')
);
});
cl.on('stanza', function(stanza) {
if (stanza.is('message') &&
// Important: never reply to errors!
stanza.attrs.type !== 'error') {
// Swap addresses…
stanza.attrs.to = stanza.attrs.from;
delete stanza.attrs.from;
// and send back.
cl.send(stanza);
}
});
cl.on('error', function(e) {
console.error(e);
});

Finally, test if it works

If you are using the test script from my gist you should copy the key and certifiate of your test user to the folder the script is in. The key file should be called key.pem and the certificate should be called cert.pem.

To connect via starttls run:

node echo_bot_sasl_external.js --jid=user@domain.com

To use the legacy SSL port run:

node echo_bot_sasl_external.js --jid=user@domain.com --server=domain.com --legacy_ssl

Thats it.

Advertisement
This entry was posted in programming and tagged , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s