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:
führen wird:
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!
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
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.
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
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):
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:
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:
Um anzuzeigen, welche Webhooks registriert sind, können Sie Folgendes ausführen
vmq-admin webhooks anzeigen
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:
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:
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
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.
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
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:
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):
vmq-admin trace client client-id=my_clientid -mountpoint=jsclient
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
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:
Zurück zu Erlang
https://github.com/vernemq/vernemq/blob/master/apps/vmq_diversity/src/vmq_diversity_plugin.erl
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:
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:
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
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.
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.
In diesem Fall wird der auth_on_publish-Hook über Webhooks aufgerufen:
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:
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.
Zeigt einige zusätzliche Lua-Skripte für die VerneMQ-Vielfalt.