Débogage des problèmes de connexion / authentification VerneMQ pour la double authentification avec webhooks et vmq_diversity
TL;DR
https://github.com/vernemq/vernemq/blob/master/apps/vmq_diversity/src/vmq_diversity_plugin.erl
comprend une déclaration qui bloquera l'authentification/autorisation par le biais de tout autre canal si votre script Lua renvoie "false" :
conduira à :
au lieu d'essayer d'autres plugins, comme vous auriez pu le supposer !
Afin d'éviter ce problème, il suffit de ne rendez rien de votre script Lua, si vous ne voulez pas traiter le message !
Débogage
VerneMQ a un outil de traçage intégré, qui vous aidera à voir quels problèmes peuvent survenir. Tout d'abord, affichez les sessions, afin de savoir avec quelles données vos clients essaient de se connecter :
vmq-admin session show
Puis lancez une trace :
vmq-admin trace client client-id=000000007eaefc47 -mountpoint=5c61a59ba6b76f558d256f42
Notez que le point de montage par défaut est "" (le point de montage par défaut pour Verne) - si vous ne définissez pas un point de montage personnalisé sur les auditeurs ( comme moi), alors vous pouvez omettre ceci.
Initialement, vmq-admin trace signalera qu'aucune session n'est trouvée pour ce client - si votre client n'est pas actuellement connecté.
Connectez votre client, et il y aura plus de résultats.
Il est également utile d'augmenter le niveau de verbosité dans le logger pour le déboguer (pour vernemq.conf) :
log.console.level = debug
econnus
Dans mon cas particulier, mon point de terminaison webhook n'était pas en cours d'exécution. Après l'avoir démarré, j'obtiens maintenant (plusieurs tentatives avec des résultats similaires) :
Comme vous pouvez le voir, le client est maintenant authentifié, mais n'est pas autorisé à publier. Le client est alors déconnecté (conformément à la spécification MQTT 3.1.1).
Et voici la sortie du journal :
Ce qui se passe ici, c'est que le client est authentifié à l'aide d'un webhook, puis il essaie d'être autorisé à l'aide d'un script Lua (autorisation MongoDB).
Je ne sais pas pourquoi auth_on_publish pour le client n'est pas appelé en utilisant un webhook également. Dans tous les cas, ce client est censé être pleinement authentifié par MongoDB.
Je ne vois également que des demandes de registre d'authentification :
Pour montrer quels webhooks sont enregistrés, vous pouvez exécuter
vmq-admin webhooks show
voir : https://docs.vernemq.com/plugindevelopment/webhookplugins
Tous les webhooks sont appelés avec la méthode POST, et doivent recevoir une réponse avec le code HTTP 200 pour être considérés comme réussis.
Une demande pour le serveur webhook
Voici à quoi ressemblera une requête pour le serveur Webhook :
sont passés, avec l'en-tête vernemq-hook réglé sur auth_on_register dans ce cas.
Le corps du message comprendra différentes informations sur le client qui tente de se connecter.
Après avoir utilisé "next" comme réponse du webhook, la publication fonctionne correctement - le client est authentifié par rapport à MongoDB, et ensuite la publication est autorisée, comme souhaité.
Voici à quoi devrait ressembler la réponse du webhook pour transmettre l'authentification au plugin suivant :
{"résultat" : "suivant"}
Et voici à quoi ressemble la trace maintenant :
En bas, vous pouvez voir les keepalives pour le client (PINGREQ, PINGRESP).
Donc, un client fonctionne maintenant. On passe au client suivant - qui devrait être authentifié et autorisé en utilisant les webhooks !
Client Webhook
Comme vous pouvez le voir, le script Lua de MongoDB réécrit le point de montage de "piclient" à un autre point de montage.
En fait, j'utilise le point de montage sur les écouteurs pour indiquer quelle méthode d'authentification doit être utilisée pour ce client.
Dans la version 2 de VerneMQ, on nous promet qu'il y aura une séparation des Plugins par Listener - donc nous pouvons éviter ces vérifications qui ajoutent de la surcharge à chaque connexion.
apparemment, une seule trace peut être exécutée à la fois. J'essaie à nouveau après avoir fermé l'autre trace :
vmq-admin trace client client-id=my_clientid -mountpoint=jsclient
Veuillez noter que le message auth_on_publish debug est imprimé par une instruction supplémentaire que j'ai insérée dans le script Lua :
dans auth_commons.lua
Comprendre ce qui doit être renvoyé par le script Lua
Ce que nous voulons, c'est probablement retourner du script Lua que le prochain hook doit être appelé.
"Dans le cas où le plugin ne peut pas valider le message de publication, il est préférable de renvoyer suivant
car cela permettrait aux plugins suivants dans la chaîne de valider la demande."
(voir https://docs.vernemq.com/plugindevelopment/publishflow )
J'ai supposé que le retour faux impliquerait cela, mais apparemment non ?
Regardons dans la source Erlang de vernemq
https://github.com/vernemq/vernemq
C'est une suite de tests pour le auth_cache de vmq_diversity (où se trouvent les scripts Lua) :
vmq-admin trace client client-id=my_clientid -mountpoint=jsclient
Ajout d'un débogage supplémentaire pour le message en Lua :
fonction auth_on_publish(pub)
print("***auth_on_publish debug*** (LUA)")
pour k,v dans paires(pub) faire
print(k .. " " .. v)
fin
print(pub)
retournez à la case départ
fin
Notez que le code semble être défectueux (les faux ne peuvent apparemment pas être concaténés en utilisant .. en Lua - OK.)
Quoi qu'il en soit, dans le tableau Lua, qui est transmis en tant que "pub", nous avons les paramètres suivants :
- client_id
- point de montage
- charge utile
- qos
maintenant nous pourrions vérifier si le point de montage est "jsclient" (qui devrait être authentifié en utilisant les webhooks), et pour l'instant forcer true :
fonction auth_on_publish(pub)
print("***auth_on_publish debug*** (LUA)")
si pub["mountpoint"] == "jsclient" alors
retourner vrai
sinon
retournez à la case départ
fin
fin
Voici à quoi ressemble une trace pour cette condition artificielle :
Retour à Erlang
https://github.com/vernemq/vernemq/blob/master/apps/vmq_diversity/src/vmq_diversity_plugin.erl
lorsque auth_on_publish est appelé pour le vmq_diversity_plugin.erl la valeur du résultat sera obtenue comme ceci :
- si vmq_diversity_cache:match_publish_acl renvoie vrai, ce sera "ok".
- si elle renvoie false, elle lancera une erreur
- si elle retourne no_cache, le résultat dépendra de la fonction all_till_ok (appelée avec auth_on_publish).
Comme vous pouvez le voir, voici les valeurs transmises à notre script Lua, y compris le point de montage.
conv_res modifiera le résultat retourné :
Si vous n'êtes pas familier avec Erlang, je vous recommande vivement de lire mon article précédent, https://pi3g.com/2019/05/12/understanding-erlang-lua-luerl-for-vernemq-mongodb-auth_on_register-hook/
En gros, si {error, lua_script_returned_false} ne correspond pas aux résultats, pour tout nom (_) et tout autre, le résultat sera Autre - en passant simplement les résultats de all_till_ok à la fonction appelante.
Pour le nom lua_script_returned_falsel'erreur sera not_authorized.
Je ne suis pas tout à fait sûr que ce vmq_plugin_helper.erl soit l'endroit où se trouve la logique de contrôle principale (du passage au suivant) :
dans tous les cas, on s'attend probablement à ce que "next" soit retourné.
Ici, dans vmq_diversity_plugin.erl all_till_ok est défini :
https://github.com/vernemq/vernemq/blob/master/apps/vmq_diversity/src/vmq_diversity_plugin.erl
Comme vous pouvez le voir, si le script renvoie "true", la valeur de retour est fixée à "ok".
Si "false" est renvoyé par le script, l'erreur mentionnée précédemment est renvoyée, et l'exécution s'arrête -> non autorisé.
Cela signifie que si vous renvoyez false dans les scripts Lua, aucun autre plugin ne sera appelé !
des modificateurs peuvent également être renvoyés.
L'astuce est de ne rien rendre, dans le cas où vous ne voulez pas traiter la demande :
fonction auth_on_publish(pub)
print("***auth_on_publish debug*** (LUA)")
si pub["mountpoint"] == "jsclient" alors
print("*** jsclient detected ***")
print("ne renvoie rien")
- retourner vrai
sinon
print("+++ autre client détecté +++")
retournez à la case départ
fin
fin
Notez que - (deux tirets) est un commentaire en Lua.
Dans ce cas, le hook auth_on_publish est appelé à l'aide de webhooks :
Bonus
Erreur de génération de la configuration avec la seiche :
Cela peut être débogué davantage en définissant la commande dans docker-compose.yml comme :
commande : "vernemq config generate -l debug /vernemq/etc/vernemq.conf.local"
et faire apparaître le conteneur (notez que j'ai créé un fichier .local, de sorte que certains paramètres ne sont plus écrasés).
Le message d'erreur que je reçois est le suivant :
jalpine_morpheus | escript : exception error : no function clause matching
jalpine_morpheus | lists:unzip([[ws,ws],
jalpine_morpheus | {["log", "console", "file"], "./log/console.log"},
apparemment, cela est lié au fait que les seiches s'étouffent avec des lignes qui ne contiennent qu'un espace :
https://github.com/basho/cuttlefish/issues/222
en appuyant sur Alt + P dans nano activera l'affichage des espaces - ce qui est utile pour déboguer ce problème particulier.
La section problématique dans ma configuration ressemble à ceci :
ici il y a deux onglets ( ?) là où il ne devrait rien y avoir.
La suppression de la ligne problématique permettra à VerneMQ de redémarrer.
Autres lectures
Cela pourrait également être utile :
http://www.steves-internet-guide.com/mqtt-protocol-messages-overview/
Changelog de VerneMQ :
https://github.com/vernemq/vernemq/blob/fe514561cbeebb2ac4f7c98a87c64d766587c1d7/changelog.md
NB : dans la version 1.8, un nouveau plugin intéressant est le plugin vmq_pulse, qui va pousser les informations du cluster vers un backend pulse via HTTP(S).
Présentation de quelques scripts Lua supplémentaires pour la diversité VerneMQ.