Depuración de problemas de conexión / autenticación de VerneMQ para la autenticación dual con webhooks y vmq_diversity

TL;DR

https://github.com/vernemq/vernemq/blob/master/apps/vmq_diversity/src/vmq_diversity_plugin.erl

incluye una declaración que bloqueará la autenticación / autorización a través de cualquier otro canal si su script Lua devuelve "false":

imagen

llevará a:

imagen

en lugar de probar otros plugins, como podría haber supuesto.

Para evitar este problema, basta con no devuelva nada ¡de su script Lua, si no quiere manejar el mensaje!

imagen

Depuración

VerneMQ tiene una herramienta de rastreo incorporada, que le ayudará a ver qué problemas pueden ocurrir. En primer lugar, visualiza las sesiones, para saber con qué datos intentan conectarse tus clientes:

vmq-admin session show

imagen

Entonces, ejecuta un rastreo:

vmq-admin trace client client-id=000000007eaefc47 -mountpoint=5c61a59ba6b76f558d256f42

Tenga en cuenta que el punto de montaje por defecto es "" (el punto de montaje por defecto para Verne) - si no está configurando un punto de montaje personalizado en las escuchas (como yo), entonces puede omitir esto.

imagen

Inicialmente vmq-admin trace reportará que no se encuentran sesiones para este cliente - si su cliente no está conectado actualmente.

Conecte su cliente y habrá más salida.

También es útil aumentar el nivel de verbosidad en el registrador para depurar (para vernemq.conf):

log.console.level = debug

imagen

econnrefused

En mi caso particular, mi punto final de webhook no se estaba ejecutando. Después de ponerlo en marcha, ahora obtengo (múltiples intentos con una salida similar):

imagen

Como puede ver, el cliente está siendo autenticado, pero no está autorizado a publicar. El cliente se desconecta entonces (según la especificación MQTT 3.1.1).

Y esta es la salida del registro:

imagen

Lo que ocurre aquí, es que el cliente se autentifica mediante un webhook, y luego intenta autorizarse mediante un script Lua (autorización de MongoDB).

No estoy seguro de por qué auth_on_publish para el cliente no se llama usando un webhook también. Este cliente, en cualquier caso, se supone que debe ser autenticado completamente usando MongoDB.

También veo sólo solicitudes de registro de autenticidad:

imagen

Para mostrar qué webhooks están registrados, puede ejecutar

vmq-admin webhooks show

imagen

ver: https://docs.vernemq.com/plugindevelopment/webhookplugins

Todos los webhooks son llamados con el método POST, y necesitan ser respondidos con el código HTTP 200 para ser considerados exitosos.

Una solicitud para el servidor de webhooks

Este es el aspecto de una solicitud para el servidor Webhook:

imagen

se pasan las cabeceras, con la cabecera vernemq-hook establecida en auth_on_register en este caso.

El cuerpo del mensaje incluirá diferente información sobre el cliente que intenta conectarse.

Después de usar "next" como respuesta del webhook, la publicación funciona correctamente - el cliente se autentifica contra el MongoDB, y después la publicación se autoriza, como se desea.

Así es como debería ser la respuesta del webhook para pasar la autenticación al siguiente plugin:

{"resultado": "siguiente"}

Y así es como se ve el rastro ahora:

imagen

En la parte inferior puedes ver los keepalives para el cliente (PINGREQ, PINGRESP).

Así que, un cliente está trabajando ahora. A continuación, el siguiente cliente, que debería estar autenticado y autorizado mediante webhooks.

Cliente Webhook

imagen

Como puedes ver, por cierto, el punto de montaje se reescribe de "piclient" a un punto de montaje diferente por el script Lua de MongoDB.

Básicamente estoy usando el punto de montaje en las escuchas para indicar qué método de autenticación se debe utilizar para este cliente.

En la versión 2 de VerneMQ, nos han prometido, habrá una separación de Plugins por Listener - por lo tanto podemos evitar estas comprobaciones que añaden sobrecarga a cada conexión.

imagen

aparentemente sólo se puede ejecutar una traza a la vez. Intentando de nuevo después de cerrar la otra traza:

vmq-admin trace client client-id=my_clientid -mountpoint=jsclient

imagen

imagen

imagen

Tenga en cuenta que el mensaje auth_on_publish debug es impreso por una declaración adicional que inserté en el script Lua:

imagen

en auth_commons.lua

Comprender lo que debe devolver el script Lua

Lo que queremos es, probablemente, que el script Lua devuelva que el siguiente gancho debe ser llamado.

"En caso de que el plugin no pueda validar el mensaje de publicación es mejor devolver siguiente ya que esto permitiría a los siguientes plugins de la cadena validar la solicitud".

(ver https://docs.vernemq.com/plugindevelopment/publishflow )

Supuse que devolver falso implicaría eso, pero aparentemente no?

Busquemos en el código fuente Erlang de vernemq

https://github.com/vernemq/vernemq

Este es un conjunto de pruebas para el auth_cache de vmq_diversity (donde viven los scripts de Lua):

https://github.com/vernemq/vernemq/blob/c8b92f398e76d6ce4b8cca5e438e8ae1e717d71c/apps/vmq_diversity/test/vmq_diversity_auth_cache_SUITE.erl

imagen

vmq-admin trace client client-id=my_clientid -mountpoint=jsclient

imagen

Añadiendo algo de depuración adicional para el mensaje en Lua:

function auth_on_publish(pub)
     print("***auth_on_publish debug*** (LUA)")
     para k,v en pares(pub) hacer
         print(k .. " " .. v)
     fin
     print(pub)
     devolver falso
fin

imagen

Obsérvese que el código parece ser defectuoso (aparentemente no se puede concatenar falsos usando .. en Lua - OK.)

En cualquier caso, en la tabla Lua, que se pasa como "pub", tenemos los siguientes parámetros:

  • client_id
  • punto de montaje
  • carga útil
  • qos

ahora podríamos comprobar si el punto de montaje es "jsclient" (que debería ser autentificado usando webhooks), y por ahora forzar true:

function auth_on_publish(pub)
     print("***auth_on_publish debug*** (LUA)")
     si pub["mountpoint"] == "jsclient" entonces
         devolver true
     si no
         devolver falso
     fin
fin

Este es el aspecto de un rastro para esta condición artificial:

imagen

Volver a Erlang

https://github.com/vernemq/vernemq/blob/master/apps/vmq_diversity/src/vmq_diversity_plugin.erl

imagen

cuando se llame a auth_on_publish para el vmq_diversity_plugin.erl el valor del resultado se obtendrá así:

  • si vmq_diversity_cache:match_publish_acl devuelve true, será "ok".
  • si devuelve false, lanzará un error
  • si devuelve no_cache, el resultado dependerá de la función all_till_ok (llamada con auth_on_publish)

como puedes ver aquí están los valores pasados a nuestro script Lua, incluyendo el punto de montaje

conv_res modificará el resultado devuelto:

imagen

Le recomiendo encarecidamente que si no está familiarizado con Erlang lea mi artículo anterior, https://pi3g.com/2019/05/12/understanding-erlang-lua-luerl-for-vernemq-mongodb-auth_on_register-hook/

Básicamente, si {error, lua_script_returned_false} no coincide dentro de los resultados, para cualquier nombre (_) y cualquier Otro, el resultado será Otro - simplemente pasando los resultados de all_till_ok a la función que llama.

Para el nombre lua_script_returned_falseel error será not_authorized.

No estoy del todo seguro si este vmq_plugin_helper.erl es donde está la lógica principal de control (de pasar a lo siguiente):

imagen

en cualquier caso, probablemente se espera que se devuelva "next".

Aquí, en vmq_diversity_plugin.erl se define all_till_ok:

https://github.com/vernemq/vernemq/blob/master/apps/vmq_diversity/src/vmq_diversity_plugin.erl

imagen

Como puede ver, si el script devuelve "true", el valor de retorno se establece en "ok".

Si se devuelve "false" del script, se devuelve el error mencionado anteriormente, y se detiene la ejecución -> no autorizada.

imagen

Esto significa que si devuelve false en los scripts Lua, ¡no se llamará a ningún otro plugin!

alternativamente se pueden devolver los modificadores.

El truco es para no devolver nada, en caso de que no quiera gestionar la solicitud:

function auth_on_publish(pub)
     print("***auth_on_publish debug*** (LUA)")
     si pub["mountpoint"] == "jsclient" entonces
         print("*** jsclient detectado ***")
         print("no devuelve nada")
         - devolver true
    si no
         print("+++ otro cliente detectado +++")
         devolver falso
     fin
fin

Tenga en cuenta que - (dos guiones) es un comentario en Lua.

imagen

En este caso, el gancho auth_on_publish se llama utilizando webhooks:

imagen

imagen

imagen

Bono

Error al generar la configuración con la sepia:

Esto puede ser depurado aún más estableciendo el comando en docker-compose.yml a:

comando: "vernemq config generate -l debug /vernemq/etc/vernemq.conf.local"

y haciendo aparecer el contenedor (nótese que he creado un archivo .local, por lo que ciertas configuraciones ya no se sobrescriben).

El mensaje de error que recibo es:

jalpine_morpheus | escript: error de excepción: no coincide la cláusula de la función
jalpine_morpheus | lists:unzip([[ws,ws],
jalpine_morpheus | {["log", "console", "file"],"./log/console.log"},

Al parecer, esto está relacionado con la asfixia de la sepia en las líneas que sólo contienen un espacio:

https://github.com/basho/cuttlefish/issues/222

presionando Alt + P en nano habilitará la visualización de espacios en blanco - bueno para depurar este problema en particular.

La sección problemática en mi configuración se ve así:

imagen

aquí hay dos pestañas (?) donde no debería haber nada.

Eliminar la línea problemática permitirá que VerneMQ se inicie de nuevo.

Más información

Esto también puede ser útil:

http://www.steves-internet-guide.com/mqtt-protocol-messages-overview/

Registro de cambios de VerneMQ:

https://github.com/vernemq/vernemq/blob/fe514561cbeebb2ac4f7c98a87c64d766587c1d7/changelog.md

NB: en la versión 1.8 un nuevo e interesante plugin es el vmq_pulse, que enviará la información del cluster a un backend de pulsos vía HTTP(S).

https://github.com/vernemq/vernemq/blob/c8b92f398e76d6ce4b8cca5e438e8ae1e717d71c/apps/vmq_diversity/test/cache_test.lua

Mostrando algunos scripts Lua adicionales para la diversidad de VerneMQ.