-
Type:
Improvement
-
Status:
Closed
-
Priority:
Major
-
Resolution:
Fixed
-
Affects Version/s:
5
-
-
-
-
Proposal:
Hide
Add an Identifier/Value pair of 15 (0xF) Auth Method. The data is a UTF-8 string which is the name of the authentication method. This is commonly a registered SASL mechanism, but it can be any string which is understood by both the Client and Server.
Add an identifier/Value pair of 47 (0x2F) Auth Data. This is added to the CONNECT, CONNACK, and AUTH packets. The type is BinaryData.
Add a new Control Packet: AUTH: Command=0xF, Flags=0x1 The variable header for AUTH consists of a Return code, and an Identifier/Value length, followed by 0 or more Identifier/Value pairs. There is no payload.
On CONNECT, the Client MAY include an AuthMethod Idendifier/Value pair with the name of an authentication method. If this is not specified, the Server does the authentication based only on information in the CONNECT packet (as it does in MQTTv3.1.1).
If the CONNECT packet has enough information for the Server to authenticate the Client, it sends a CONNACK with an Return code of 0. The Server MAY send an AuthMethod field in the CONNACK to indicate the authentication method is used. The Server MUST NOT send an AUTH token if it has not received an AuthMethod from the Client on the CONNECT packet.
If the AuthMethod specified on the CONNECT has the value "LIST", the Server MUST either return a comma separated list of authentication methods it supports in the AuthMethod field of a AUTH packet or close the connection. If the server returns the list it MUST offer at least one authentication method in this list. If it does not support any form of extended authentication, it should close the connection (it MAY send a CONNACK return and MUST close the connection).
If the Server does not support the authentication method selected by the client, it MAY send a Not authorized return code on CONNACK and MUST close the connection. If the Client does not accept any of the authentication methods returned by the server, it MAY send a DISCONNECT packet and MUST close the connection.
If the Server needs additional information to complete the Authorization, it sends a AUTH packet with a Return code of More Auth Needed and the AuthMethod selected by the client. The Sever MAY send the first piece of server authentication data as the AuthData field in the AUTH packet.
The Server and Client can continue to send AUTH packets to one another until the Server accepts the authentication by sending a CONNACK with a Return code of 0, or rejects the connection by sending a CONNACK with a non-zero return code. The Client MAY close the connection at any time and MAY send a DISCONNECT to the server informing it of the reason. These intermediate AUTH packets sent from the Server have a Return code of "More auth needed", and all AUTH packets sent by the Client have a Return code of 0.
If the Server receives an AUTH packet after it has sent a CONNACK, it MUST have a Return code of "Revalidate" set to indicate that this is a revalidate. The revalidate acts just like the CONNECT and starts an authentication. This ends with a AUTH sent from Server to Client with a Return code of other than "More auth needed". A zero Return code indicates that the revalidation is successful. The Server MAY close the connection if the revalidate fails.
The Client MUST NOT send an AUTH packet if it did not receive an AuthMethod id/value pair on the CONNACK.
The spec update consists of two parts, the mechanism which is the addition of the AuthMethod and AuthData id/value pairs and the new AUTH control packet. In addition there is a chapter 4 section describing the use and showing the sequence for a common challenge / response auth method such as SCRAM.
For instance, the exchange for SCRAM as an example of a simple challenge response is:
client to server: CONNECT AuthMethod="SCRAM-SHA-256" AuthData=client-first-data
server to client: AUTH rc="More auth" AuthMethod="SCRAM-SHA-256" AuthData=server-first-data
client to server AUTH rc=0 AuthMethod="SCRAM-SHA-256" AuthData=client-final-data
server to client CONNACK rc=0 AuthMethod="SCRAM-SHA-256" AuthData=server-final-data
An example of an Kerberos challenge:
client to server CONNECT AuthMethod="GS2-KRB5"
server to client AUTH rc="More auth" AuthMethod="GS2-KRB5"
client to server AUTH rc=0 AuthMethod="GS2-KRB5" AuthData=inital context token
server to client AUTH rc="More auth" AuthMethod="GS2-KRB5" AuthData=reply context token
client to server AUTH rc=0 AuthMethod="GS2-KRB5"
server to client CONNACK rc=0 AuthMethod="GS2-KRB5" AuthData=outcome of authentication
Show
Add an Identifier/Value pair of 15 (0xF) Auth Method. The data is a UTF-8 string which is the name of the authentication method. This is commonly a registered SASL mechanism, but it can be any string which is understood by both the Client and Server.
Add an identifier/Value pair of 47 (0x2F) Auth Data. This is added to the CONNECT, CONNACK, and AUTH packets. The type is BinaryData.
Add a new Control Packet: AUTH: Command=0xF, Flags=0x1 The variable header for AUTH consists of a Return code, and an Identifier/Value length, followed by 0 or more Identifier/Value pairs. There is no payload.
On CONNECT, the Client MAY include an AuthMethod Idendifier/Value pair with the name of an authentication method. If this is not specified, the Server does the authentication based only on information in the CONNECT packet (as it does in MQTTv3.1.1).
If the CONNECT packet has enough information for the Server to authenticate the Client, it sends a CONNACK with an Return code of 0. The Server MAY send an AuthMethod field in the CONNACK to indicate the authentication method is used. The Server MUST NOT send an AUTH token if it has not received an AuthMethod from the Client on the CONNECT packet.
If the AuthMethod specified on the CONNECT has the value "LIST", the Server MUST either return a comma separated list of authentication methods it supports in the AuthMethod field of a AUTH packet or close the connection. If the server returns the list it MUST offer at least one authentication method in this list. If it does not support any form of extended authentication, it should close the connection (it MAY send a CONNACK return and MUST close the connection).
If the Server does not support the authentication method selected by the client, it MAY send a Not authorized return code on CONNACK and MUST close the connection. If the Client does not accept any of the authentication methods returned by the server, it MAY send a DISCONNECT packet and MUST close the connection.
If the Server needs additional information to complete the Authorization, it sends a AUTH packet with a Return code of More Auth Needed and the AuthMethod selected by the client. The Sever MAY send the first piece of server authentication data as the AuthData field in the AUTH packet.
The Server and Client can continue to send AUTH packets to one another until the Server accepts the authentication by sending a CONNACK with a Return code of 0, or rejects the connection by sending a CONNACK with a non-zero return code. The Client MAY close the connection at any time and MAY send a DISCONNECT to the server informing it of the reason. These intermediate AUTH packets sent from the Server have a Return code of "More auth needed", and all AUTH packets sent by the Client have a Return code of 0.
If the Server receives an AUTH packet after it has sent a CONNACK, it MUST have a Return code of "Revalidate" set to indicate that this is a revalidate. The revalidate acts just like the CONNECT and starts an authentication. This ends with a AUTH sent from Server to Client with a Return code of other than "More auth needed". A zero Return code indicates that the revalidation is successful. The Server MAY close the connection if the revalidate fails.
The Client MUST NOT send an AUTH packet if it did not receive an AuthMethod id/value pair on the CONNACK.
The spec update consists of two parts, the mechanism which is the addition of the AuthMethod and AuthData id/value pairs and the new AUTH control packet. In addition there is a chapter 4 section describing the use and showing the sequence for a common challenge / response auth method such as SCRAM.
For instance, the exchange for SCRAM as an example of a simple challenge response is:
client to server: CONNECT AuthMethod="SCRAM-SHA-256" AuthData=client-first-data
server to client: AUTH rc="More auth" AuthMethod="SCRAM-SHA-256" AuthData=server-first-data
client to server AUTH rc=0 AuthMethod="SCRAM-SHA-256" AuthData=client-final-data
server to client CONNACK rc=0 AuthMethod="SCRAM-SHA-256" AuthData=server-final-data
An example of an Kerberos challenge:
client to server CONNECT AuthMethod="GS2-KRB5"
server to client AUTH rc="More auth" AuthMethod="GS2-KRB5"
client to server AUTH rc=0 AuthMethod="GS2-KRB5" AuthData=inital context token
server to client AUTH rc="More auth" AuthMethod="GS2-KRB5" AuthData=reply context token
client to server AUTH rc=0 AuthMethod="GS2-KRB5"
server to client CONNACK rc=0 AuthMethod="GS2-KRB5" AuthData=outcome of authentication
MQTT 3.1.1 permits two client authentication mechanisms:
1. Authentication by TLS (using a certificate/private key) prior to the CONNECT packet being sent
2. Authentication via a username and password (or similar token) provided by a client in the CONNECT packet.
The second mechanism also requires the use of TLS encryption in order for it to be secure.
There are three reasons why we might consider adding alternative mechanisms, for example one involving server-directed challenge response during the MQTT CONNECT exchange:
i) TLS might be considered too heavyweight for some particularly constrained devices.
ii) There are many deployments where people are ok with TLS, but don't want to provision devices with bespoke Certificates. Some of these might not have a need to encrypt the MQTT protocol, but with approach 2 you end up having to encrypt all MQTT packets just in order to protect the password field in the CONNECT
iii) The organization (or standard building on top of MQTT) might already have an alternative authentication protocol.
Notes:
1. The emphasis in this requirement is on composing with existing security mechanisms, rather than inventing new ones
2. Some of this could be achieved by publishing Committee Notes (e.g. OAuth 2.0) rather than changing the CONNECT protocol packet exchange
{"report":{"apdex":1,"isInitial":true,"journeyId":"fbacf78b-6067-47b8-a3a2-847bf2ce90f7","key":"jira.project.issue.view-issue","navigationType":0,"readyForUser":641.5999999046326,"redirectCount":0,"resourceLoadedEnd":1011.5,"resourceLoadedStart":172.40000009536743,"resourceTiming":[{"duration":33.59999990463257,"initiatorType":"link","name":"https://issues.oasis-open.org/s/3edeca31ab9ba77980aae0809fbe7121-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/0a4716d29b2d5b1bdcdb168b4efc119e/_/download/contextbatch/css/_super/batch.css","startTime":172.40000009536743,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":172.40000009536743,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":206,"responseStart":0,"secureConnectionStart":0},{"duration":33.90000009536743,"initiatorType":"link","name":"https://issues.oasis-open.org/s/7d2823769c2e7b66e860863fe879b7f8-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/9aebb1c0aaa4c36289529757ec9dbb54/_/download/contextbatch/css/project.issue.navigator,jira.view.issue,jira.global,atl.general,-_super/batch.css?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&richediton=true","startTime":172.7999997138977,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":172.7999997138977,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":206.69999980926514,"responseStart":0,"secureConnectionStart":0},{"duration":33.69999980926514,"initiatorType":"link","name":"https://issues.oasis-open.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/8.0.5/_/download/batch/com.atlassian.auiplugin:split_aui.pattern.label/com.atlassian.auiplugin:split_aui.pattern.label.css","startTime":173.09999990463257,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":173.09999990463257,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":206.7999997138977,"responseStart":0,"secureConnectionStart":0},{"duration":33.80000019073486,"initiatorType":"link","name":"https://issues.oasis-open.org/s/645acc233eb869f48a571293b8358a7d-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/1.0/_/download/batch/jira.webresources:global-static-adgs/jira.webresources:global-static-adgs.css","startTime":173.19999980926514,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":173.19999980926514,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":207,"responseStart":0,"secureConnectionStart":0},{"duration":33.59999990463257,"initiatorType":"link","name":"https://issues.oasis-open.org/s/a0dd6509771c1de0667aae5429c04cda-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/1.0/_/download/batch/jira.webresources:global-static/jira.webresources:global-static.css","startTime":173.40000009536743,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":173.40000009536743,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":207,"responseStart":0,"secureConnectionStart":0},{"duration":95.90000009536743,"initiatorType":"script","name":"https://issues.oasis-open.org/s/e5479157e7a0c08b005e6522f2f04104-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/0a4716d29b2d5b1bdcdb168b4efc119e/_/download/contextbatch/js/_super/batch.js?locale=en-US","startTime":173.69999980926514,"connectEnd":173.69999980926514,"connectStart":173.69999980926514,"domainLookupEnd":173.69999980926514,"domainLookupStart":173.69999980926514,"fetchStart":173.69999980926514,"redirectEnd":0,"redirectStart":0,"requestStart":173.69999980926514,"responseEnd":269.59999990463257,"responseStart":269.59999990463257,"secureConnectionStart":173.69999980926514},{"duration":127.90000009536743,"initiatorType":"script","name":"https://issues.oasis-open.org/s/83514d5d4e8543747b02042eafcdc99c-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/9aebb1c0aaa4c36289529757ec9dbb54/_/download/contextbatch/js/project.issue.navigator,jira.view.issue,jira.global,atl.general,-_super/batch.js?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&locale=en-US&richediton=true","startTime":174.19999980926514,"connectEnd":174.19999980926514,"connectStart":174.19999980926514,"domainLookupEnd":174.19999980926514,"domainLookupStart":174.19999980926514,"fetchStart":174.19999980926514,"redirectEnd":0,"redirectStart":0,"requestStart":174.19999980926514,"responseEnd":302.09999990463257,"responseStart":302.09999990463257,"secureConnectionStart":174.19999980926514},{"duration":130.19999980926514,"initiatorType":"script","name":"https://issues.oasis-open.org/s/70bb2263e59e7e1f04fbd137c80b895b-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/aae1242f5fc81cc6a5bb8bc963ccda29/_/download/contextbatch/js/atl.global,-_super/batch.js?locale=en-US","startTime":174.40000009536743,"connectEnd":174.40000009536743,"connectStart":174.40000009536743,"domainLookupEnd":174.40000009536743,"domainLookupStart":174.40000009536743,"fetchStart":174.40000009536743,"redirectEnd":0,"redirectStart":0,"requestStart":174.40000009536743,"responseEnd":304.59999990463257,"responseStart":304.5,"secureConnectionStart":174.40000009536743},{"duration":133,"initiatorType":"script","name":"https://issues.oasis-open.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/1.0/_/download/batch/jira.webresources:calendar-en/jira.webresources:calendar-en.js","startTime":174.69999980926514,"connectEnd":174.69999980926514,"connectStart":174.69999980926514,"domainLookupEnd":174.69999980926514,"domainLookupStart":174.69999980926514,"fetchStart":174.69999980926514,"redirectEnd":0,"redirectStart":0,"requestStart":174.69999980926514,"responseEnd":307.69999980926514,"responseStart":307.69999980926514,"secureConnectionStart":174.69999980926514},{"duration":135.60000038146973,"initiatorType":"script","name":"https://issues.oasis-open.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/1.0/_/download/batch/jira.webresources:calendar-localisation-moment/jira.webresources:calendar-localisation-moment.js","startTime":174.7999997138977,"connectEnd":174.7999997138977,"connectStart":174.7999997138977,"domainLookupEnd":174.7999997138977,"domainLookupStart":174.7999997138977,"fetchStart":174.7999997138977,"redirectEnd":0,"redirectStart":0,"requestStart":174.7999997138977,"responseEnd":310.40000009536743,"responseStart":310.40000009536743,"secureConnectionStart":174.7999997138977},{"duration":136.2999997138977,"initiatorType":"script","name":"https://issues.oasis-open.org/s/cda37faab827dbdf305de8efe8282062-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/8.0.5/_/download/batch/com.atlassian.auiplugin:split_aui.pattern.label/com.atlassian.auiplugin:split_aui.pattern.label.js?locale=en-US","startTime":175,"connectEnd":175,"connectStart":175,"domainLookupEnd":175,"domainLookupStart":175,"fetchStart":175,"redirectEnd":0,"redirectStart":0,"requestStart":175,"responseEnd":311.2999997138977,"responseStart":311.2999997138977,"secureConnectionStart":175},{"duration":137.5,"initiatorType":"link","name":"https://issues.oasis-open.org/s/07245784f53abc49bad9d9d4d36c577a-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/cadc4f20cc5c138dee060d42cf85f220/_/download/contextbatch/css/jira.global.look-and-feel,-_super/batch.css","startTime":175.19999980926514,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":175.19999980926514,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":312.69999980926514,"responseStart":0,"secureConnectionStart":0},{"duration":136.7000002861023,"initiatorType":"script","name":"https://issues.oasis-open.org/rest/api/1.0/shortcuts/803004/a29179d70fa8562374ee16707692af77/shortcuts.js?context=issuenavigation&context=issueaction","startTime":175.2999997138977,"connectEnd":175.2999997138977,"connectStart":175.2999997138977,"domainLookupEnd":175.2999997138977,"domainLookupStart":175.2999997138977,"fetchStart":175.2999997138977,"redirectEnd":0,"redirectStart":0,"requestStart":175.2999997138977,"responseEnd":312,"responseStart":312,"secureConnectionStart":175.2999997138977},{"duration":211.5,"initiatorType":"link","name":"https://issues.oasis-open.org/s/f77fd89aa211a76b20e9b0e63564383c-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/4a9288299d147101bf66484f4be48925/_/download/contextbatch/css/com.atlassian.jira.projects.sidebar.init,-_super,-jira.view.issue,-project.issue.navigator/batch.css?jira.create.linked.issue=true&richediton=true","startTime":223,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":223,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":434.5,"responseStart":0,"secureConnectionStart":0},{"duration":90.90000009536743,"initiatorType":"script","name":"https://issues.oasis-open.org/s/41525c48ddceeb9b11e54085268fc285-CDN/nu8zej/803004/aeedb5937bed650f2f0cc4ec9ceaa5d3/4a9288299d147101bf66484f4be48925/_/download/contextbatch/js/com.atlassian.jira.projects.sidebar.init,-_super,-jira.view.issue,-project.issue.navigator/batch.js?jira.create.linked.issue=true&locale=en-US&richediton=true","startTime":223.2999997138977,"connectEnd":223.2999997138977,"connectStart":223.2999997138977,"domainLookupEnd":223.2999997138977,"domainLookupStart":223.2999997138977,"fetchStart":223.2999997138977,"redirectEnd":0,"redirectStart":0,"requestStart":223.2999997138977,"responseEnd":314.19999980926514,"responseStart":314.19999980926514,"secureConnectionStart":223.2999997138977}],"threshold":1000,"fetchStart":0,"domainLookupStart":67,"domainLookupEnd":67,"connectStart":67,"connectEnd":115,"secureConnectionStart":91,"requestStart":115,"responseStart":164,"responseEnd":248,"domLoading":167,"domInteractive":1047,"domContentLoadedEventStart":1047,"domContentLoadedEventEnd":1096,"domComplete":1279,"loadEventStart":1279,"loadEventEnd":1283,"userAgent":"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)","marks":[],"measures":[],"correlationId":"b5bcaf0a248abf","effectiveType":"4g","downlink":10,"rtt":0,"serverDuration":105,"dbReadsTimeInMs":13,"dbConnsTimeInMs":15,"applicationHash":"4d4040e0714d65b7fffa4801569d014c0b16eaa9","experiments":[]}}
I like this proposal. It seems to cover all scenarios I think we should care about, and all the modern authentication mechanisms. Sending CONNACK as the final packet, whilst a 'breaking' change, ensures that a server only reveals details to an authenticated client. The only thing I'm not so sure about is "LIST". I worry that this could get us into some of the same problems as TLS ClientHello / ServerHello ciphersuite agreement over the years. I also think there might be a security issue of a downgrade attack if the LIST is offered to a client over a plaintext connection OR to an unauthenticated client. Of course, one can argue it is a broker's responsibility to only offer secure mechanisms, but the reality's no different to the TLS 1.0 / 1.1 / 1.2 issue on the internet today - if you want to support an older client, even during migration...
Also, just as a client can either use TLS or not, and won't swap to the other, I think the same is true for a connection mechanism. Either it has the credentials (and the user's / system administrator's approval) for SCAM-SHA-256, or it doesn't. So I think LIST in practice is probably unnecessary. It might be useful to supply it on CONNACK, though.
With this mechanism now in place, the opportunity exists to deprecate the user of username / password and call password 'initial client auth data' or the like. That might be a step too far, but an auth identifier can be:-
etc