使用mongodb作为外部authz的数据源时的filter定义问题

运行环境:docker,FROM emqx:5.8.3
配置了acl 授权链中第一个授权源为mongodb,当在filter中单独定义通过用户名、clientid、ipaddress时都可以完成授权,但是当前端应用想动态配置acl规则的时候,想要实现如下的过滤条件的时候,似乎不支持这样的写法?
{
$or: [
{ username: ${username} },
{ clientid: ${clientid} },
{ ipaddress: ${peerhost} },
]
}
因为前端应用定义规则的时候不确定是用哪个字段来做过滤,想三种都支持的话想要用or条件来组装过滤条件,是否不支持这样的特性?

应该是支持的,这个是 mongo 的写法
打开 debug 上传一下日志看看

authorization块的配置如下:

authorization {
deny_action = ignore
no_match = deny
cache = { enable = true }
sources = [
{
type = mongodb
mongo_type = rs
servers = “xxxx”
replica_set_name = “rs-xxxx”
database = “mqtt”
collection = “mqtt_acl”
username = “xxxxx”
password = “xxxxxx”

  filter {
    $or: [
      { username: "${username}" },
      { clientid: "${clientid}" },
      { ipaddress: "${peerhost}" }
    ]
  }
},
{
  type = file
  enable = true
  # This file is immutable to EMQX.
  # Once new rules are created from dashboard UI or HTTP API,
  # the file 'data/authz/acl.conf' is used instead of this one
  path = "etc/acl.conf"
}

]
}

emqx容器内日志如下:
[error]: {scan_error,#{line => 107,reason => “illegal characters "$o"”,file => “/opt/emqx/etc/emqx.conf”}}

ERROR: call_hocon_failed: -s emqx_conf_schema -c /opt/emqx/etc/emqx.conf multi_get node.data_dir node.name node.cookie node.db_backend cluster.proto_dist node.dist_net_ticktime
[error]: {scan_error,#{line => 107,reason => “illegal characters "$o"”,file => “/opt/emqx/etc/emqx.conf”}}

ERROR: call_hocon_failed: -s emqx_conf_schema -c /opt/emqx/etc/emqx.conf multi_get node.data_dir node.name node.cookie node.db_backend cluster.proto_dist node.dist_net_ticktime
[error]: {scan_error,#{line => 107,reason => “illegal characters "$o"”,file => “/opt/emqx/etc/emqx.conf”}}

ERROR: call_hocon_failed: -s emqx_conf_schema -c /opt/emqx/etc/emqx.conf multi_get node.data_dir node.name node.cookie node.db_backend cluster.proto_dist node.dist_net_ticktime
[error]: {scan_error,#{line => 107,reason => “illegal characters "$o"”,file => “/opt/emqx/etc/emqx.conf”}}

ERROR: call_hocon_failed: -s emqx_conf_schema -c /opt/emqx/etc/emqx.conf multi_get node.data_dir node.name node.cookie node.db_backend cluster.proto_dist node.dist_net_ticktime
[error]: {scan_error,#{line => 107,reason => “illegal characters "$o"”,file => “/opt/emqx/etc/emqx.conf”}}

ERROR: call_hocon_failed: -s emqx_conf_schema -c /opt/emqx/etc/emqx.conf multi_get node.data_dir node.name node.cookie node.db_backend cluster.proto_dist node.dist_net_ticktime

$or这一行提示非法字符

你用 dashboard 去编辑吧,你没设置对格式。得用引号和反引号把格式搞对。

尝试在dashboard中的访问控制-> 客户端授权->MongoDB数据源 设置->查询 Filter文本框中输入以下查询语句:
{
$or:[
{“clientid”:“${clientid}”},
{“ipaddress”:“${peerhost}”},
{“username”:“${username}”}
]
}
保存后,文本框中内容变成了
{}
开启debug级别日志后在console中未观测到相关报错。关于引号转义的话,请问需要参考文档中的哪一部分来写,感谢回复。

使用如下内容可以把配置保存进去了,给$or加了双引号,我再测试下有没有起作用
{“$or”:[{“clientid”:“${clientid}”},{“ipaddress”:“${peerhost}”},{“username”:“${username}”}]}

./bin/emqx_ctl conf show authentication > authn.conf
vim authn.conf
把filter改一下:

 filter {
      "$or": [
      { username: "${username}" },
      { clientid: "${clientid}" },
      { ipaddress: "${peerhost}" }
    ]
    }

注意$or的双引号
./bin/emqx_ctl conf load --replace authn.conf

Dashboard 编辑保存后为空的是个 bug,得修。感谢反馈.(其实你把正确的带"" 的filter填 在 dashboard 那里,他也能正常。就是不正确的,他会直接变成空。

嗯 是的,还有发现一个问题,就是如果acl配置了一条deny的publish的规则,在mqttx客户端里面如果直接往match这条规则的topic里publish的话在界面上显示能发出去,emqx后台显示not_authorized,所以实际上是mqttx客户端并没有把publish时候未授权的信息提示给用户

关于mongodb数据源的authZ文档filter部分,也没有把完整的map写上去?
WX20241225-145127

你用了这个后功能正常了么?

正常的,我还在做测试,完整测试后我再把结论贴在后面

1 个赞

当我使用用完整的mongodb findOne方法

db.collection.findOne(query, projection, options)

时,尝试修改成如下配置:

filter {"$or":[{"username":"${username}"},{"clientid":"${clientid}"},{"ipaddress":"${peerhost}"}]},{},{sort:{"auditing.last_modified_date":-1}}

启动容器报错:
[error]: {parse_error,#{line => 106,reason => “syntax error before: ‘{’”,file => “/opt/emqx/etc/emqx.conf”}}

emqx.conf中的filter是否最终只是当成db.collection.findOne的query参数,这个时候如果查出来多条记录,想要通过排序精确控制是哪条规则的时候需要怎么达成这样的目标

能的,你的是语法错误,把试试把字符串都用引号引起来

filter {"$or":[{"username":"${username}"},{"clientid":"${clientid}"},{"ipaddress":"${peerhost}"}]},{},{"sort":{"auditing.last_modified_date":-1}}

sort也用引号引起来也试过了,甚至-1也当字符串引起来也试过了,我在mongosh里面测试是可以的,不清楚在emqx.conf下要符合什么其他特殊语法

所以我上面提了一个问题:
emqx.conf 中的filter是否最终只是当成db.collection.findOne的query参数,这个时候如果查出来多条记录,想要通过排序精确控制是哪条规则的时候需要怎么达成这样的目标

意思是filter中的内容是否是整体传给了mongodb里

db.collection.findOne( <query>, <projection>, <options> )

的第一个参数,query,如果是这样的话,后面的projection和options是没有入口传给filter的,也就是说filter里是不支持排序这样的操作。

以下是mongodb的findOne方法的文档

试试:

{"$or":[{"username":"${username}"},{"clientid":"${clientid}"},{"ipaddress":"${peerhost}"}],"$sort":{"auditing.last_modified_date":-1}}

中间参数projection不用了吗,只是在sort前加$和引号包裹起来试过不行"$sort",我完全用你的试试