MQTT 5.0: Connection close on non-authorized topic subscription attempt #12902
-
Describe the bugThe 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) RabbitMq logs report 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: Not an Erlang expert, but seems like the problem is somewhere in this part of the code Reproduction steps
Expected behaviorThe connection remains open, allowing further subscriptions to other allowed topics. Additional contextRabbitMQ 4.0.3 |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 9 replies
-
Thank you for providing details and a traffic capture. According to the stack trace, the code that handles a |
Beta Was this translation helpful? Give feedback.
-
@AntonSmolkov Where in the MQTT 5.0 spec do you read this?
In its current implementation, RabbitMQ closes the MQTT connection if an authorisation check fails. This is done intentionally and is in line with how RabbitMQ behaves with other protocols such as AMQP 1.0 and AMQP 0.9.1. Note that RabbitMQ complies with the following MQTT 5.0 requirement by sending the SUBACK packet before closing the connection as shown in your Wireshark capture above:
|
Beta Was this translation helpful? Give feedback.
-
There are no clear instructions in the section 3.8 Closing the connection is not great but that's how things were for the majority of post-authentication errors before MQTTv5, and MQTTv5 does not clarify many cases any way, so it's up to the implementation to decide what to do. Section @AntonSmolkov you are welcome to investigate how other MQTT servers and client libraries handle such scenarios. A "partial success" is the absolute worst scenario to handle, and most messaging protocols make it impossible to perform N operations at a time, some of which may fail. Needless to say, partial failures are not even discussed in the MQTTv5 spec as far as I can tell. So one more time we learn that MQTT is a poorly designed protocol as far as technical operations and error handling go. This was dead obvious in the MQTT < 5 days and is still true to some extent today. This is not something our team has the resources to try to address. Avoid features that can "partially succeed" and subscribe to N topics one by one so that your client knows exactly what to do on a retry. |
Beta Was this translation helpful? Give feedback.
-
I'm not interesting in spending any more time on this discussion as it is. MQTT before v5 had a catastrophically bad error handling story, this is widely known by now. The "partial success, partial failure" case is not explicitly mentioned the MQTTv5 spec, so it's up to each individual implementer to decide what should be done. We have decided to close the connection. It is not unreasonable, this is how MQTT largely been for over a decade before it's reached v5. How many clients handle If/when you have that data you can start another discussion with it and we will see if switching to |
Beta Was this translation helpful? Give feedback.
This is not a RabbitMQ's problem to solve.