Login sequence
The login sequence needs to be performed every time a new client connects to the broker. It ensures that the client gets correct access rights assigned, and that devices get to be mounted in the correct location in the broker's node tree. Sometimes, authentication can be optional (such as when connecting over a local socket, or if a client certificate is used), but the login sequence is required anyway to introduce the client to the broker.
There are a few methods that can be called before the login sequence is
completed. All of them are called with a null
SHV path (which means it can be
left out in the requests's meta).
All the methods described here are not to be reported by
dir
and no other method can be called before the login sequence is completed.
To complete the login sequence, the client needs to send a successful :login
request.
:login
param
The param for a :login
request is a Map. It needs to contain the "login"
field if authentication is required and can optionally contain the "options"
field.
{
"login": {...},
"options": {...}
}
Some login types require the client to send additional requests before :login
.
The client can send any number of these requests. If the client chooses to send
these requests, it can ultimately choose a different login type than the one
associated with these requests. After a successful login, calling these methods
is disallowed.
Brokers do not have to support all login types (e.g. brokers that do not require any authentication).
"login":
The "login"
field is a Map. It must contain at least the "type"
field
which is a String that identifies the login type, and it can have only one of
these values:
"PLAIN"
for plain text password login (discouraged use)"SHA1"
for SHA1 login"TOKEN"
for token login
Other fields are specific to the login types which are defined in detail below.
"PLAIN"
login type
This login type uses a username/password combination, where the password is in plain text. This login type is highly discouraged in favor of the other login types.
These fields are required for the "login"
field when using this login type:
"user"
: String username"password"
: String password in plain text"type"
:"PLAIN"
"SHA1"
login type
This login type uses a username/password combination where the password is a
SHA1 hash. The client must send a :hello
request first.
=> <"id": 1, "method": "hello">i{}
Broker should respond with a Map containing a String "nonce"
field that
can be used to perform login. The nonce needs to be an ASCII string with a
length between 10 and 32 characters. The nonce must be the same for all
:hello
requests during the login phase.
<= <"id": 1>i{2: {"nonce": "vOLJaIZOVevrDdDq"}}
Some clients might send more
:hello
requests to discover if the broker is started and ready, especially on serial port.
The client hashes the user's password, adds the result as a suffix to the
nonce from :hello
, and hashes the result again. The complete password
deduction is: SHA1(nonce + SHA1(password))
. Supporting SHA1 login is highly
encouraged, as even low end CPUs should be able to calculate SHA1 hashes and
thus perform the SHA1 login.
These fields are required for the "login"
field when using this login type:
"user"
: String username"password"
: String password as an SHA1 hash in HEX format"type"
:"SHA1"
"TOKEN"
login type
This login type uses a token to authenticate.
SHV defines these standard token types (support is optional):
- session token: a token previously generated by the broker using the
"session"
field in the login options. This token can be used to implement persistent login (i.e. allowing user-facing clients to enter a password just once). The token should only be valid for a set amount of time. Every broker implementation defines it own rules for the expiration duration and the extension of it.
The format of a token is implementation defined. The broker can generate tokens in other implementation specific ways (e.g. OAuth2). It is the responsibility of the broker to differentiate multiple token types.
These fields are required for the "login"
field when using this login type:
"token"
: a String containing the token."type"
:"TOKEN"
"options":
The "options"
field is a Map of options for the broker. Broker will ignore
any unknown options. Different broker implementations can support different sets
of options, but they must support at least these options:
"device"
: a Map containing device-specific options. At least these options need to be supported:"deviceId"
: a String value that identifies the device. This should be used by the broker to automatically assign a mount point based on its internal rules."mountPoint"
: a String value that specifies the path where the broker should broker mount the device tree in its own tree. This should override any mount point assigned by the broker based on"deviceId"
, but it can be disregarded if the user doesn't have access rights for the specified mountpoint.
"idleWatchDogTimeOut"
: an Int value specifying the number of seconds without receiving a message before the broker considers the connection to be dead and disconnects it. The default timeout by the broker should be 180 seconds. By increasing this timeout you can reduce the amount of periodic dummy messages sent, but it is suggested to keep it in a reasonable range, because open but dead connections can unnecessarily consume resources on the broker.
Optionally, the broker can support these options:
"session"
: a Bool specifying whether the broker should create a persistent session token that the client can use to login with. The session token will be returned in the response for:login
.
Example :login
param
=> <"id":2, "method":"login">i{
1: {
"login":{
"password": "3d613ce0c3b59a36811e4acbad533ee771afa9f3",
"user": "iot",
"type": "SHA1"
},
"options": {
"device": {
"deviceId": "historyprovider",
},
"idleWatchDogTimeOut": 180
}
}
}
:login
response
The response to :login
can be:
- Null
- a String value with a session token, if it was requested in the
:login
options. If a session token was used to log in, it is implementation-defined, if the new session token is the same or different.
Note: some older broker implementation can respond with some other value for backward compatibility reasons. This value should be ignored by the client.
In case of a :login
error you can attempt the login again without needing to
disconnect or sending required login type specific methods again. Be aware that
broker should impose a delay of 60 seconds on subsequent login attempts for
security reasons.
After sending a successful :login
request you can send requests and receive
messages to which you have rights to as a logged user.
Example :login
response
<= <"id": 2>i{}
<= <"id": 2>i{2: "..."}}
Additional methods
The client can optionally send these requests before completing the login sequence.
:workflows
The :workflows
method is used to query the broker about supported login
workflows. The result is a List of values of the supported login workflows.
There are three standardized values:
"PLAIN"
- indicates that the broker supports plain text login"SHA1"
- indicates that the broker supports SHA1 login"TOKEN"
- indicates that the broker supports login via tokens
The broker can define its own implementation specific workflows. The format of a workflow value and its relationship with login types are implementation defined.
=> <"id": 1, "method": "workflows">i{}
<= <"id": 1>i{
2: ["PLAIN", "SHA1", "TOKEN", {
"type": "oauth2-azure",
// Implementation defined information
"clientId": "...",
"authorizeUrl": "...",
"tokenUrl": "...",
}]
}
:revokeToken
The :revokeToken
method is used to request the broker to invalidate a token
specified in the param as String. If the token is a session token, the
broker MUST deny further login attempts with this token. Otherwise, the
effect of this method is implementation specific.