Allow to configure whether client should be disconnected on unauthorized publish
Opened this issue · 0 comments
Problem or use case
When clients send PUBLISH and server defines that that publish is unauthorized, it might sometimes be inconvenient to disconnect the client.
Looking at specifications, in 3.1.1 (from line 835):
If a Server implementation does not authorize a PUBLISH to be performed by a Client; it has no way of informing that Client. It MUST either make a positive acknowledgement, according to the normal QoS rules, or close the Network Connection [MQTT-3.3.5-2].
Note that there are technically two possibilities given here "make a positive acknowledgement" or "close the Network Connection". I read this in the way that it is possible that server would not authorize PUBLISH (and therefore not forward it to other clients), however it would still make a positive acknowledgement.
In MQTT 5 there is more interesting mention, though (from line 3492):
Acknowledgment packets PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK with a Reason Code of 0x80 or greater indicate that the received packet, identified by a Packet Identifier, was in error. There are no consequences for other Sessions or other Packets flowing on the same Session.
The CONNACK and DISCONNECT packets allow a Reason Code of 0x80 or greater to indicate that the Network Connection will be closed. If a Reason Code of 0x80 or greater is specified, then the Network Connection MUST be closed whether or not the CONNACK or DISCONNECT is sent [MQTT-4.13.2-1]. Sending of one of these Reason Codes does not have consequence for any other Session.
The way I read this, it is clear that CONNACK and DISCONNECT with 0x87 (unauthorized) must result in closed network connection, however for PUBACK earlier it is said "There are no consequences for other Sessions or other Packets flowing on the same Session.". I suspect maybe the bit "must result in closed network connection" was mistakenly attributed to PUBACK as well. I believe since that paragraph starts with "The CONNACK and DISCONNECT packets...", this only is applied to establishing of connection process.
Hence it would appear that by automatically disconnecting, HiveMQ actually does not behave according to at least MQTT spec version 5.
Relevant HiveMQ documentation: https://docs.hivemq.com/hivemq/latest/extensions/authorization.html#publish
When a Publish is denied by calling any of the failAuthorization methods, then the following MQTT behaviour can be expected:
MQTT 3.1.1, All QoS levels
Connection is closed by the broker.
MQTT 5...
connection is closed
This last bit is repeated for all three QoS
Preferred solution or suggestions
Allow for PublishAuthorizer to pass to output a boolean indicating whether connection is going to be closed or not.
The relevant method is PublishAuthorizerOutput#failAuthorization ( https://github.com/hivemq/hivemq-extension-sdk/blob/c485b05d4e70a373a1e30fafbe7c1fb3657c8ff1/src/main/java/com/hivemq/extension/sdk/api/auth/parameter/PublishAuthorizerOutput.java#L107-L126 ), that I'd like to have an overloads with boolean disconnect
.
If disconnect
was set to false, then for MQTT 3 server should respond with positive ack, as if publish was authorized and passed, however clients should not receive it from their subscriptions.
For MQTT 5 server should respond with PUBACK/PUBREC (depending on QoS) with 0x87 NOT_AUTHORIZED (or specified reason code), but not send DISCONNECT and not close connection.