Token-based auth_on_register webhook works for CONNECT, but ACL from MySQL not applied for SUBSCRIBE/PUBLISH

Hello everyone,

I’m using VMQ Diversity to authenticate username/password and ACL with the MySQL database. Now I want to improve authentication with the auth_on_register webhook. This allows me to enter the token in the password field and verify it via the webhook. If the password is a token, it is verified, otherwise, I simply return result=“next” for the old way of authentication. I want to continue using the ACL via MySQL. Therefore, I haven’t implemented auth_on_subscribe or auth_on_publish.

Now I can register the user with the token in the password as expected. However, I can’t subscribe to or publish topics defined in my MSSQL table. With the normal password, everything works as before. Does anyone have any ideas? Thanks for the help.

DOCKER_VERNEMQ_SWARM: 1
DOCKER_VERNEMQ_ACCEPT_EULA: ‘yes’
DOCKER_VERNEMQ_LISTENER__TCP__LOCALHOST: ‘0.0.0.0:1883’
DOCKER_VERNEMQ_LISTENER__TCP__DEFAULT: ‘0.0.0.0:1883’
DOCKER_VERNEMQ_LISTENER__SSL__USE_IDENTITY_AS_USERNAME: ‘on’
DOCKER_VERNEMQ_LISTENER__SSL__DEFAULT: ‘0.0.0.0:8883’
DOCKER_VERNEMQ_LISTENER__SSL__CAFILE: ‘/etc/ssl/vernemq/cacert.crt’
DOCKER_VERNEMQ_LISTENER__SSL__CERTFILE: ‘/etc/ssl/vernemq/server.crt’
DOCKER_VERNEMQ_LISTENER__SSL__KEYFILE: ‘/etc/ssl/vernemq/server.key’
DOCKER_VERNEMQ_PLUGINS__VMQ_WEBHOOKS: ‘on’
DOCKER_VERNEMQ_PLUGINS__VMQ_WEBHOOKS__PRIORITY: ‘5’
DOCKER_VERNEMQ_VMQ_WEBHOOKS__WEBHOOK1__HOOK: ‘auth_on_register’
DOCKER_VERNEMQ_VMQ_WEBHOOKS__WEBHOOK1__ENDPOINT: ‘http://localhost:4444/mqtt/auth’
DOCKER_VERNEMQ_VMQ_WEBHOOKS__WEBHOOK2__HOOK: ‘auth_on_register_m5’
DOCKER_VERNEMQ_VMQ_WEBHOOKS__WEBHOOK2__ENDPOINT: ‘http://localhost:4444/mqtt/auth’
DOCKER_VERNEMQ_PLUGINS__VMQ_DIVERSITY: ‘on’
DOCKER_VERNEMQ_PLUGINS__VMQ_DIVERSITY__PRIORITY: ‘10’
DOCKER_VERNEMQ_PLUGINS__VMQ_PASSWD: ‘off’
DOCKER_VERNEMQ_PLUGINS__VMQ_ACL: ‘off’
DOCKER_VERNEMQ_VMQ_DIVERSITY__AUTH_MYSQL__ENABLED: ‘on’
DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__PASSWORD_HASH_METHOD: ‘password’
DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__HOST: ‘localhost’
DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__PORT: ‘3306’
DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__USER: ‘mqtt’
DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__PASSWORD: ‘test’
DOCKER_VERNEMQ_VMQ_DIVERSITY__MYSQL__DATABASE: ‘mqtt’
DOCKER_VERNEMQ_LOG__CONSOLE: ‘console’
DOCKER_VERNEMQ_LOG__CONSOLE__LEVEL: ‘info’
DOCKER_VERNEMQ_ALLOW_REGISTER_DURING_NETSPLIT: ‘on’
DOCKER_VERNEMQ_ALLOW_PUBLISH_DURING_NETSPLIT: ‘on’
DOCKER_VERNEMQ_ALLOW_SUBSCRIBE_DURING_NETSPLIT: ‘on’
DOCKER_VERNEMQ_ALLOW_UNSUBSCRIBE_DURING_NETSPLIT: ‘on’

1 Like

Hi,
You can achieve this with a bit of Lua hacking.

The reason you need to do that is that the vmq_diversity plugin works as a single unit. During auth_on_register, the ACLs are added to the cache, so that subsequent in-session auth_on_publish and auth_on_subscribe calls can use the cache directly (implemented in Erlang).

Since your WebHook auth_on_register does not fill the diversity cache, subsequent vmq_diversity authorizations will fail. The good news is that the diversity cache access will call Lua functions when the direct (Erlang) access to the cache finds empty lines.

So what you have to do is implement auth_on_publish and auth_on_subscribe in Lua, similar to the auth_on_register function. (look at the mysql2.lua module and the auth_on_register function there).

The main trick is to add a cache insert function in those 2 Lua functions, something like:

cache_insert(reg.mountpoint, reg.client_id, reg.username, publish_acl, subscribe_acl)

What will happen then is the following:

  • The MySQL plugin will not find the user in the Cache.
  • It will fallback to call the auth_on_subscribe or auth_on_publish Lua functions.
  • The Lua functions will grab the ACLs from MySQL and add them to the cache.
  • After that first call, any subsequent in-session authorizations for Publishs and Subscribes can then use the fast cache automatically.

Note that you can (re)load changed scripts with vmq-admin script reload

I hope this helps.

1 Like

Hi afa,

thanks for the tip. I just implemented two functions for auth_on_subscribe and auth_on_pubish in mysql.lua to insert the ACL into the cache. For now, I’m just copying all the old code, modifying it in the file outside of Docker, and moving it into the container. I still need to find a better way. But it seems to be working.

In any case, I hope we’ll have an official solution for this feature soon.

@gtran-dev great to hear you have a working solution! If you think this should be an official feature, you can certainly open a PR for review. I’m not sure why we never added this, but we always considered the Lua script files “free to hack & adapt” since no recompiling is needed.
With Docker it’s a tad more complex, I see that.