Debugging von VerneMQ-Verbindungs-/Authentifizierungsproblemen bei dualer Authentifizierung mit Webhooks und vmq_diversity

TL;DR

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

enthält eine Anweisung, die die Authentifizierung/Autorisierung über alle anderen Kanäle blockiert, wenn Ihr Lua-Skript "false" zurückgibt:

Bild

führen wird:

Bild

anstatt andere Plugins auszuprobieren, wie Sie vielleicht angenommen haben!

Um dieses Problem zu vermeiden, genügt es nichts zurückschicken aus Ihrem Lua-Skript, wenn Sie die Nachricht nicht bearbeiten wollen!

Bild

Fehlersuche

VerneMQ hat ein eingebautes Trace-Tool, mit dem Sie sehen können, welche Probleme auftreten können. Zeigen Sie zunächst die Sitzungen an, um herauszufinden, mit welchen Daten sich Ihre Clients zu verbinden versuchen:

vmq-admin Sitzung anzeigen

Bild

Führen Sie dann einen Trace durch:

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

Beachten Sie, dass der Einhängepunkt standardmäßig "" ist (der Standard-Einhängepunkt für Verne) - wenn Sie keinen benutzerdefinierten Einhängepunkt auf den Listenern setzen (wie ich), können Sie dies weglassen.

Bild

Anfänglich meldet vmq-admin trace, dass keine Sitzungen für diesen Client gefunden wurden - wenn Ihr Client derzeit nicht verbunden ist.

Schließen Sie Ihren Client an, und es wird mehr ausgegeben.

Es ist auch hilfreich, die Ausführlichkeitsstufe im Logger auf Debug zu erhöhen (für vernemq.conf):

log.console.level = debug

Bild

econnrefused

In meinem speziellen Fall wurde mein Webhook-Endpunkt nicht ausgeführt. Nachdem ich ihn gestartet habe, erhalte ich jetzt (mehrere Versuche mit ähnlicher Ausgabe):

Bild

Wie Sie sehen können, wird der Client jetzt authentifiziert, aber nicht zur Veröffentlichung autorisiert. Der Client wird dann getrennt (gemäß MQTT 3.1.1 Spezifikation).

Und dies ist die Protokollausgabe:

Bild

Der Client wird über einen Webhook authentifiziert und versucht dann, sich über ein Lua-Skript zu autorisieren (MongoDB-Autorisierung).

Ich bin mir nicht sicher, warum auth_on_publish für den Client nicht auch über einen Webhook aufgerufen wird. Dieser Client sollte in jedem Fall vollständig über MongoDB authentifiziert werden.

Ich sehe auch nur Anträge für die Einschreibung:

Bild

Um anzuzeigen, welche Webhooks registriert sind, können Sie Folgendes ausführen

vmq-admin webhooks anzeigen

Bild

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

Alle Webhooks werden mit der Methode POST aufgerufen und müssen mit dem HTTP-Code 200 beantwortet werden, um als erfolgreich zu gelten.

Eine Anfrage an den Webhook-Server

So sieht eine Anfrage für den Webhook-Server aus:

Bild

Header übergeben werden, wobei der Header vernemq-hook auf auth_on_register in diesem Fall.

Der Nachrichtentext enthält verschiedene Informationen über den Client, der versucht, eine Verbindung herzustellen.

Nach der Verwendung von "next" als Antwort vom Webhook funktioniert die Veröffentlichung korrekt - der Client wird gegenüber der MongoDB authentifiziert, und anschließend wird die Veröffentlichung wie gewünscht autorisiert.

So sollte die Antwort des Webhooks aussehen, um die Authentifizierung an das nächste Plugin weiterzugeben:

{"Ergebnis": "next"}

Und so sieht die Spur jetzt aus:

Bild

Unten sehen Sie die Keepalives für den Client (PINGREQ, PINGRESP).

Ein Client funktioniert also jetzt. Weiter geht es mit dem nächsten Client - der über Webhooks authentifiziert und autorisiert werden sollte!

Webhook-Client

Bild

Wie Sie übrigens sehen können, wird der Mountpoint vom MongoDB-Lua-Skript von "piclient" auf einen anderen Mountpoint umgeschrieben.

Im Grunde genommen verwende ich den Mountpoint auf den Listenern, um anzugeben, welche Authentifizierungsmethode für diesen Client verwendet werden soll.

In Version 2 von VerneMQ, so wurde uns versprochen, wird es eine Trennung der Plugins pro Listener geben - dadurch können wir diese Überprüfungen vermeiden, die bei jeder Verbindung zusätzlichen Overhead verursachen.

Bild

Offenbar kann jeweils nur ein Trace ausgeführt werden. Versuchen Sie es erneut, nachdem Sie die andere Ablaufverfolgung abgeschaltet haben:

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

Bild

Bild

Bild

Bitte beachten Sie, dass die Meldung auth_on_publish debug durch eine zusätzliche Anweisung ausgegeben wird, die ich in das Lua-Skript eingefügt habe:

Bild

in auth_commons.lua

Verstehen, was das Lua-Skript zurückgeben soll

Was wir wollen, ist wahrscheinlich, dass das Lua-Skript zurückgibt, dass der nächste Hook aufgerufen werden soll.

"Falls das Plugin die Veröffentlichungsnachricht nicht validieren kann, ist es am besten, eine nächste da dies den nachfolgenden Plugins in der Kette erlauben würde, die Anfrage zu validieren."

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

Ich nahm an, dass die Rückkehr falsch würde das implizieren, aber offensichtlich nicht?

Werfen wir einen Blick in den Erlang-Quelltext von vernemq

https://github.com/vernemq/vernemq

Dies ist eine Testsuite für den auth_cache für vmq_diversity (wo die Lua-Skripte liegen):

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

Bild

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

Bild

Hinzufügen von zusätzlichem Debugging für die Nachricht in Lua:

function auth_on_publish(pub)
     print("***auth_on_publish debug*** (LUA)")
     for k,v in pairs(pub) do
         print(k .. " " .. v)
     Ende
     drucken(pub)
     return false
Ende

Bild

Beachten Sie, dass der Code fehlerhaft zu sein scheint (false kann offenbar nicht mit .. in Lua verkettet werden - OK.)

Auf jeden Fall haben wir in der Lua-Tabelle, die als "pub" übergeben wird, die folgenden Parameter:

  • client_id
  • mountpoint
  • Nutzlast
  • qos

jetzt könnten wir prüfen, ob der Einhängepunkt "jsclient" ist (der über Webhooks authentifiziert werden sollte), und vorerst true erzwingen:

function auth_on_publish(pub)
     print("***auth_on_publish debug*** (LUA)")
     if pub["mountpoint"] == "jsclient" then
         return true
     sonst
         return false
     Ende
Ende

So sieht eine Spur für diese künstliche Bedingung aus:

Bild

Zurück zu Erlang

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

Bild

wenn auth_on_publish für das vmq_diversity_plugin.erl aufgerufen wird, wird der Ergebniswert wie folgt erhalten:

  • wenn vmq_diversity_cache:match_publish_acl true zurückgibt, ist es "ok".
  • wenn er false zurückgibt, wird ein Fehler ausgegeben
  • wenn no_cache zurückgegeben wird, hängt das Ergebnis von der Funktion all_till_ok ab (die mit auth_on_publish aufgerufen wird)

wie Sie sehen können, sind hier die Werte, die an unser Lua-Skript weitergegeben werden, einschließlich des Einhängepunkts

conv_res wird das zurückgegebene Ergebnis ändern:

Bild

Wenn Sie mit Erlang nicht vertraut sind, empfehle ich Ihnen dringend, meinen vorherigen Artikel zu lesen, https://pi3g.com/2019/05/12/understanding-erlang-lua-luerl-for-vernemq-mongodb-auth_on_register-hook/

Wenn {error, lua_script_returned_false} in den Ergebnissen für einen beliebigen (_)-Namen und einen beliebigen Anderen nicht übereinstimmt, ist das Ergebnis grundsätzlich Andere - es werden einfach die Ergebnisse von all_till_ok an die aufrufende Funktion weitergegeben.

Für den Namen lua_script_returned_falsewird der Fehler not_authorized angezeigt.

Ich bin nicht ganz sicher, ob diese vmq_plugin_helper.erl ist, wo die Hauptsteuerungslogik (der Weitergabe auf nächste) ist:

Bild

in jedem Fall wird wahrscheinlich "next" zurückgegeben.

Hier wird in vmq_diversity_plugin.erl all_till_ok definiert:

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

Bild

Wie Sie sehen können, wird der Rückgabewert auf "ok" gesetzt, wenn das Skript "true" zurückgibt.

Wenn das Skript "false" zurückgibt, wird der bereits erwähnte Fehler zurückgegeben und die Ausführung gestoppt -> nicht autorisiert.

Bild

Das bedeutet, dass, wenn Sie in den Lua-Skripten false zurückgeben, keine anderen Plugins aufgerufen werden!

alternativ können auch Modifikatoren zurückgegeben werden.

Der Trick ist nichts zurückzugeben, für den Fall, dass Sie die Anfrage nicht bearbeiten wollen:

function auth_on_publish(pub)
     print("***auth_on_publish debug*** (LUA)")
     if pub["mountpoint"] == "jsclient" then
         print("*** jsclient erkannt ***")
         print("gibt nichts zurück")
         - return true
    sonst
         print("+++ anderer Client entdeckt +++")
         return false
     Ende
Ende

Beachten Sie, dass - (zwei Bindestriche) in Lua ein Kommentar ist.

Bild

In diesem Fall wird der auth_on_publish-Hook über Webhooks aufgerufen:

Bild

Bild

Bild

Bonus

Fehler beim Erzeugen der Konfiguration mit Sepia:

Dies kann weiter getestet werden, indem der Befehl in docker-compose.yml auf gesetzt wird:

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

und das Hochfahren des Containers (beachten Sie, dass ich eine .local-Datei erstellt habe, damit bestimmte Einstellungen nicht mehr überschrieben werden).

Die Fehlermeldung, die ich erhalte, lautet:

jalpine_morpheus | escript: Ausnahmefehler: keine passende Funktionsklausel
jalpine_morpheus | lists:unzip([[ws,ws],
jalpine_morpheus | {["log", "console", "file"],"./log/console.log"},

Dies hängt offenbar damit zusammen, dass Tintenfische an Zeilen ersticken, die nur ein Leerzeichen enthalten:

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

drücken. Alt + P in nano aktiviert die Anzeige von Leerzeichen - gut für die Fehlersuche bei diesem speziellen Problem.

Der problematische Abschnitt in meiner Konfiguration sieht wie folgt aus:

Bild

Hier gibt es zwei Registerkarten (?), wo keine sein sollten.

Wenn Sie die problematische Zeile entfernen, kann VerneMQ wieder starten.

Weitere Lektüre

Dies könnte ebenfalls hilfreich sein:

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

Änderungsliste von VerneMQ:

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

NB: in Version 1.8 ist ein interessantes neues Plugin das vmq_pulse Plugin, das Cluster-Informationen über HTTP(S) an ein pulse Backend sendet.

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

Zeigt einige zusätzliche Lua-Skripte für die VerneMQ-Vielfalt.