rabbitmq / rabbitmq-server

Open source RabbitMQ: core server and tier 1 (built-in) plugins
https://www.rabbitmq.com/
Other
12.31k stars 3.92k forks source link

MQTT 5.0: Connection close on non-authorized topic subscription attempt #12742

Open AntonSmolkov opened 5 days ago

AntonSmolkov commented 5 days ago

Describe the bug

The broker closes the MQTT connection when attempting to subscribe to a topic that is not allowed at the topic permissions level.

For example, with the following C# code, the entire connection is closed shortly after line 2:

// GrantedQos0
await mqttClient.SubscribeAsync("allowed_topic", MqttQualityOfServiceLevel.AtMostOnce);
// NotAuthorized 
await mqttClient.SubscribeAsync("denied_topic", MqttQualityOfServiceLevel.AtMostOnce); 
// GrantedQos0 (not works with RabbitMQ)
await mqttClient.SubscribeAsync("allowed_topic_another", MqttQualityOfServiceLevel.AtMostOnce); 

Wireshark looks like this: (notice Reason Code column) image

RabbitMq logs report subscribe_error on connection:

rabbit-1  | 2024-11-16 12:45:34.588125+00:00 [debug] <0.989.0> User 'user1' authenticated successfully by backend rabbit_auth_backend_internal
rabbit-1  | 2024-11-16 12:45:34.588474+00:00 [info] <0.989.0> Accepted MQTT connection 127.0.0.1:58966 -> 127.0.0.1:1883 for client ID my-pod-name8
rabbit-1  | 2024-11-16 12:45:36.524394+00:00 [debug] <0.989.0> Received a SUBSCRIBE with subscription(s) [{mqtt_subscription,
rabbit-1  | 2024-11-16 12:45:36.524394+00:00 [debug] <0.989.0>                                             <<"allowed_topic">>,
rabbit-1  | 2024-11-16 12:45:36.524394+00:00 [debug] <0.989.0>                                             {mqtt_subscription_opts,0,false,
rabbit-1  | 2024-11-16 12:45:36.524394+00:00 [debug] <0.989.0>                                              false,0,undefined}}]
rabbit-1  | 2024-11-16 12:45:38.104373+00:00 [debug] <0.989.0> Received a SUBSCRIBE with subscription(s) [{mqtt_subscription,
rabbit-1  | 2024-11-16 12:45:38.104373+00:00 [debug] <0.989.0>                                             <<"denied_topic">>,
rabbit-1  | 2024-11-16 12:45:38.104373+00:00 [debug] <0.989.0>                                             {mqtt_subscription_opts,0,false,
rabbit-1  | 2024-11-16 12:45:38.104373+00:00 [debug] <0.989.0>                                              false,0,undefined}}]
rabbit-1  | 2024-11-16 12:45:38.105474+00:00 [error] <0.989.0> MQTT topic access refused: read access to topic 'denied_topic' in exchange 'amq.topic' in vhost 'mqtt' refused for user 'user1'
rabbit-1  | 2024-11-16 12:45:38.105653+00:00 [error] <0.989.0> Failed to add binding between exchange 'amq.topic' in vhost 'mqtt' and queue 'mqtt-subscription-my-pod-name8qos0' in vhost 'mqtt' for topic filter denied_topic: access_refused
rabbit-1  | 2024-11-16 12:45:38.105786+00:00 [error] <0.989.0> MQTT protocol error on connection 127.0.0.1:58966 -> 127.0.0.1:1883: subscribe_error

As far as i understand, this behavior doesn't complain to the MQTT5 standard.

For instance, the same code/approach, works fine with EMQX broker: image

Not an Erlang expert, but seems like the problem is somewhere in this part of the code

Reproduction steps

  1. Create user in the befault or any other auth backend
  2. Grant ACL permision .* .* .* to the user
  3. Grant ^allowed_topic.* read/write topic permission
  4. Create MQTT Connection, subscribe to allowed_topic (sucess)
  5. Subscribe to any other topic e.g. denied_topic
  6. Connection is closed

Expected behavior

The connection remains open, allowing further subscriptions to other allowed topics.

Additional context

RabbitMQ 4.0.3

michaelklishin commented 5 days ago

Thank you for providing details and a traffic capture. According to the stack trace, the code that handles a SUBSCRIBE frame does not expect errors related to insufficient permissions.