This weekend I started and mostly finished a Kerberos 5-based authentication
plugin for mosquitto (https://github.com/bartbes/mosquitto-krb5
). I would like
to briefly discuss my experiences with the plugin interface, followed by what I
think is the biggest shortcoming of the current interface, and a suggestion to
improve that situation.
As those familiar with Kerberos may know, it is a protocol designed solely for
authentication, and does not provide any mechanisms for authorisation. This
stands in immediate contrast with the plugin API, considering an authentication
plugin is expected to implement not only username/password checking, but also
ACL checking and possibly authentication based on TLS-PSK. As it stands, the
krb5 plugin is mostly useless (which is no less than I had hoped for in this
weekend project), as it provides no access over TLS-PSK, but more importantly,
grants everyone read/write access to every topic, as long as they have a valid
kerberos ticket to authenticate with.
As a small aside, one problem I ran into, both on the broker and on the client,
is that (lib)mosquitto deals with passwords as null-terminated strings, whereas
the MQTT 3.1 specification specifies UTF-8 strings with a specified length (note
that UTF-8 strings can contain null bytes), and MQTT 3.1.1 specifies the
password field as binary data. As it is, I am escaping null bytes in the binary
kerberos data transmitted, which works, but it would have been nicer if this
had not been necessary.
My largest gripe with the plugin interface as it is right now is that only one
plugin can be active at any given time. The krb5 plugin is intended to play a
largely supplementary role, yet the only option at the moment is to have it
replace existing authentication. Rather than split up the plugins, I realise
authentication and authorisation are usually tightly coupled, and I would
therefore suggest the option of allowing multiple plugins at once.
My suggestion is inspired by PAM, which allows a plugin to either grant access
immediately, deny access immediately or to "defer" action. Now, PAM has a much
more complicated setup, but these three actions should suffice for mosquitto, in
my opinion. The authentication/authorisation workflow would consist of the
- If the plugin returns MOSQ_AUTH_GRANTED, access is immediately granted, the
user authenticated correctly, obtained the requested access if this is an ACL
call, or provided a correct TLS-PSK.
- If the plugin returns MOSQ_AUTH_DENIED, access is immediately denied, the
plugin has an explicit rule to deny this action, either this user does not
match some criteria but does exist, the password did not match or access to
this topic is definitely denied.
- If the plugin instead returns MOSQ_AUTH_DEFERRED, the next plugin in the
(configuration) list is invoked.
- If at the end of authentication/authorisation the status is
MOSQ_AUTH_DEFERRED, there was no plugin granting access, so it is then
This, to me, seems like a relatively small modification to the plugin
architecture that would greatly enhance the possibilities the owner of a broker
has. In my case, I would first allow krb5-based authentication, then fall back
to the inbuilt mosquitto behaviour, allowing private key authentication and
lastly, passwords. Similarly, since the krb5 plugin has no information about
ACL, it would immediately return MOSQ_AUTH_DEFERRED, and the normal ACL file
would get used.
Of course this is only a suggestion, and I would appreciate any feedback you may
have, I would much rather have a good plugin architecture than have my way.
P.S. Sorry about the length, I guess the same burst of inspiration that got me
to write the plugin in the first place also hit me while writing this email.