We've got asked a couple of times about how to do authentication and authorization with a database like PostgreSQL or Redis. "Easy, write a plugin!", has been our standard answer. But without a proper plugin development guide, this is easier said than done. Brave folks already checked out the VerneMQ Demo Plugin repo on Github that gives all the boilerplate needed together with some explanations on how to implement the hooks. To provide another plugin example, we developed a PostgreSQL plugin that handles the authentication and authorization of clients. (It's under 100 LoC and was done in about 2 hours this morning). While this plugin is fully functional it isn't built for production and should only be used for educational purposes. Hint: we can make this production ready in a day or two, if you need it ;)
The plugin is implemented as an Erlang OTP application. It relies on the great Erlang Postgres client implementation epgsql and uses the poolboy library for connection pooling. To talk to PostgreSQL using epgsql and poolboy we just adjusted the example from the poolboy readme.
A pretty naive database schema is used in the plugin; there's certainly much room to improve this if necessary, including the implemented queries. Note: plaintext password... hash & salt for production use please. You have been warned ;) The schema consists of three tables:
Note that the table names are chosen after the hooks they relate to. This is just to make things a little clearer.
VerneMQ currently provides three hooks, concerned with authentication and authorization:
auth_on_register
: Checks if a client is allowed to connect auth_on_publish
: Checks if a client is allowed to publish auth_on_subscribe
: Checks if a client is allowed to subscribe A plugin isn't required to implement all of them. The default vmq_acl plugin only implements the auth_on_register hook for example. For our PostgreSQL example it certainly makes sense to implement all 3 hooks in one plugin.
auth_on_register
As you see, the plugin uses 'SELECT COUNT' to obtain the number of rows, as the content is not needed itself. If the result of the query is a count of 1 the plugin is allowed to return 'ok'. This indicates to the underlying plugin system that the client was authenticated successfully . For any other query result the plugin returns 'next'. This tells VerneMQ to look for (and try) other auth plugins for this user.
auth_on_publish
Auth_on_publish uses 'SELECT COUNT' in a similar way. In this case we allow the plugin to check if the client is allowed to publish retained messages, and also whether the message size and chosen quality of service level is appropriate or not.
auth_on_subscribe
Just obtaining the resulting row count isn't enough for the auth_on_subscribe hook. Here the plugin has to verify that every provided topic/qos pair is stored in the database. Instead of creating multiple queries we fold through the result set.
We hope you'll agree that it's quite simple to get started implementing an authorization plugin with a third-party database. Let us know, if any questions remain. Further notes on how to compile and start the plugin can be found on its github repo. To make this more production ready, we'd have to address at least the following points:
Have fun!
The VerneMQ Mission Engineers.