调试VerneMQ的连接/认证问题,用webhooks和vmq_diversity进行双重认证

TL;DR

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

包括一条语句,如果你的Lua脚本返回 "false",它将阻止通过任何其他渠道的认证/授权。

形象

将导致。

形象

而不是像你想象的那样,去尝试其他的插件!

为了避免这个问题,只需 请勿退回任何东西 从你的Lua脚本中,如果你不想处理这个消息的话

形象

调试

VerneMQ有一个内置的跟踪工具,这将帮助你看到哪些问题可能发生。首先,显示会话,以便找出你的客户正在尝试连接哪些数据。

vmq-admin session show

形象

然后运行一个跟踪。

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

注意,mountpoint默认为""(Verne的默认mountpoint)--如果你没有在监听器上设置一个自定义的mountpoint(如我),那么你可以省略这个。

形象

最初vmq-admin追踪会报告说没有发现这个客户端的会话--如果你的客户端目前没有连接。

连接你的客户,就会有更多的输出。

将日志记录器的粗略程度提高到调试状态也很有帮助(对于vernemq.conf)。

log.console.level = debug

形象

拒绝的经济

在我的特定情况下,我的webhook端点没有运行。在启动它之后,我现在得到(多次尝试都有类似的输出)。

形象

正如你所看到的,客户端现在被认证了,但没有被授权发布。然后客户端被断开连接(根据MQTT 3.1.1规范)。

而这是日志输出。

形象

这里发生的情况是,客户端使用webhook进行认证,然后它试图使用Lua脚本(MongoDB授权)进行授权。

我不确定为什么客户端的auth_on_publish没有使用webhook来调用。在任何情况下,这个客户端都应该使用MongoDB进行完全认证。

我也只看到关于自动开启注册的请求。

形象

要显示哪些webhooks被注册,你可以运行

vmq-admin webhooks show

形象

见。 https://docs.vernemq.com/plugindevelopment/webhookplugins

所有webhooks都是用POST方法调用的,需要用HTTP代码200来回答才算成功。

对Webhook服务器的请求

下面是Webhook服务器的请求的样子。

形象

头信息被传递,头信息vernemq-hook被设置为 注册时的身份验证(auth_on_register 在这种情况下。

帖子正文将包括试图连接的客户的不同信息。

在使用 "next "作为webhook的回复后,发布工作正常进行--客户端对MongoDB进行了认证,之后发布被授权,如愿以偿。

下面是来自webhook的回答,应该是这样的,以便将认证传递给下一个插件。

{"结果"。"下一个"}

下面是现在的跟踪情况。

形象

在底部,你可以看到客户端的keepalives(PINGREQ, PINGRESP)。

所以,一个客户现在正在工作。继续下一个客户端--它应该使用webhooks进行认证和授权!

Webhook客户端

形象

正如你所看到的,通过MongoDB Lua脚本,mountpoint被从 "piclient "改写为不同的mountpoint。

基本上,我正在使用监听器上的mountpoint来指示这个客户端应该使用哪种认证方法。

在VerneMQ的第二版中,我们得到承诺,每个监听器的插件将被分离 - 因此我们可以避免这些检查,这些检查会增加每个连接的开销。

形象

显然,一次只能运行一个跟踪。在关闭另一个跟踪后再试。

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

形象

形象

形象

请注意,auth_on_publish debug这个信息是由我在Lua脚本中插入的一个额外语句打印的。

形象

在auth_commons.lua中

了解从Lua脚本返回的内容

我们想要的可能是从Lua脚本中返回下一个钩子应该被调用。

"如果插件不能验证发布信息,最好是返回 下一个 因为这将允许链中的后续插件验证该请求。"

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

我认为,返回 假的 将意味着,但显然不是?

让我们看看vernemq的Erlang源代码

https://github.com/vernemq/vernemq

这是vmq_diversity(Lua脚本所在)的auth_cache的测试套件。

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

形象

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

形象

为Lua中的信息增加了一些额外的调试。

函数 auth_on_publish(pub)
     print("***auth_on_publish debug***(LUA)")
     for k,v in pairs(pub) do
         print(k ... " " ... v)
     结束
     print(pub)
     返回错误
结束

形象

请注意,这段代码似乎有问题(假的显然不能在Lua中使用.连接--好的。)

在任何情况下,在作为 "pub "传入的Lua表中,我们有以下参数。

  • client_id
  • 挂载点
  • 有效载荷
  • 服务质量

现在我们可以检查挂载点是否为 "jsclient"(应该使用webhooks进行验证),目前强制为true。

函数 auth_on_publish(pub)
     print("***auth_on_publish debug***(LUA)")
     如果pub["mountpoint"] == "jsclient" 那么
         返回true
     否则
         返回错误
     结束
结束

下面是这种人工条件下的跟踪情况。

形象

返回到Erlang

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

形象

当调用vmq_diversity_plugin.erl的auth_on_publish时,将得到这样的结果值。

  • 如果vmq_diversity_cache:match_publish_acl将返回true,它将是 "ok"。
  • 如果它返回false,它将抛出一个错误
  • 如果它返回no_cache,结果将取决于all_till_ok函数(与auth_on_publish一起调用)。

正如你所看到的,这里是传递给我们的Lua脚本的值,包括装载点。

conv_res将修改返回的结果。

形象

如果你对Erlang不熟悉,我强烈建议你阅读我之前的文章。 https://pi3g.com/2019/05/12/understanding-erlang-lua-luerl-for-vernemq-mongodb-auth_on_register-hook/

基本上,如果{error, lua_script_returned_false}在结果中没有匹配,对于任何(_)名称和任何其他,结果将是其他--简单地把all_till_ok的结果传递给调用函数。

对于名字 lua_script_returned_false,错误将是not_authorized。

我不完全确定这个vmq_plugin_helper.erl是否是主要的控制逻辑(传递到下一个)。

形象

在任何情况下,可能 "next "都会被返回。

这里,在vmq_diversity_plugin.erl中定义了all_till_ok。

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

形象

正如你所看到的,如果脚本返回的是 "true",则返回值被设置为 "ok"。

如果从脚本中返回 "false",就会返回前面提到的错误,并停止执行-->未授权。

形象

这意味着,如果你在Lua脚本中返回false,就不会有其他插件被调用。

或者,可以返回修饰语。

诀窍是 不退任何东西。 以防你不想处理这个请求。

函数 auth_on_publish(pub)
     print("***auth_on_publish debug***(LUA)")
     如果pub["mountpoint"] == "jsclient" 那么
         print("*** jsclient detected ***")
         print("不返回任何东西")
         - 返回true
    否则
         print("++其他客户端检测到++")。
         返回错误
     结束
结束

注意,-(两个破折号)在Lua中是一个注释。

形象

在这种情况下,auth_on_publish钩子被使用webhooks调用。

形象

形象

形象

奖金

用墨鱼生成配置时发生错误。

这可以通过将docker-compose.yml中的命令设置为进一步调试。

命令。"vernemq config generate -l debug /vernemq/etc/vernemq.conf.local"

并把容器带起来(注意,我已经创建了一个.local文件,所以某些设置不会再被覆盖了)。

我得到的错误信息是。

jalpine_morpheus | escript: 异常错误:没有匹配的函数条款
jalpine_morpheus | lists:unzip([[ws,ws],
jalpine_morpheus | {["log", "console", "file"], "./log/console.log"},

显然,这与墨鱼被只包含一个空格的线条噎住有关。

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

迫切 Alt + P 在nano中会启用空白显示--对调试这个特殊问题很有帮助。

我的配置中的问题部分看起来是这样的。

形象

这里有两个标签(?),它们应该是没有的。

删除有问题的一行,将允许VerneMQ再次启动。

进一步阅读

这可能也是有帮助的。

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

VerneMQ的更新日志。

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

注意:在1.8版本中,一个有趣的新插件是vmq_pulse插件,它将通过HTTP(S)将集群信息推送到一个脉冲后端。

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

显示一些额外的Lua脚本,用于VerneMQ的多样性。