Soteria
Introduction
Soteria is responsible for Authentication and Authorization of every request sent to EMQ.
The following configuration in HOCON
format, configure EMQ to use HTTP Service for Authentication and Authorization.
{
mechanism = password_based
backend = http
enable = true
method = post
url = "http://127.0.0.1:8080/v2/auth"
body {
username = "${username}"
password = "${password}"
token = "${username}"
clientid = "${clientid}"
}
headers {
"Content-Type" = "application/json"
"X-Request-Source" = "EMQX"
}
}
{
type = http
enable = true
method = post
url = "http://127.0.0.1:32333/v2/acl"
body {
username = "${username}"
topic = "${topic}"
action = "${action}"
}
headers {
"Content-Type" = "application/json"
"X-Request-Source" = "EMQX"
}
}
We are using the Authentication HTTP Service
and Authorization HTTP Service
plugins of EMQ for forwarding these requests to Soteria and doing Authentication and Authorization.
EMQ has caching mechanism, but it sends requests almost for each Publish message to Soteria.
PS: On Subscribe we have only one message from client that need authorization and other messages are coming from server.
Architecture
Support Vendors
Soteria supports having multiple vendors at the same time.
Means you can use single cluster for multiple companies at the same time and validate their tokens
and control accesses.
Vendor Configuration
company: "<<company_name>>"
driver_salt: ""
passenger_salt: ""
passenger_hash_length: 15
driver_hash_length: 15
allowed_access_types: ["pub", "sub"]
keys:
iss-0: "key-value"
iss-1: "key-value"
iss_entity_map:
0: "entity-0"
1: "entity-1"
default: "default-entity"
iss_peer_map:
0: "peer-0"
1: "peer-1"
default: "default-peer"
jwt:
iss_name: "iss"
sub_name: "sub"
signing_method: "RS512"
topics:
- topic1
- topic2
- ...
HashID Manager
driver_salt
,passenger_salt
, passenger_hash_length
, driver_hash_length
are used for HashIDManager.
This component only works for passenger and driver issuers.
Keys
The following is a mapping that associates vendors (companies) with the keys used for opening JWT tokens.
If symmetrical keys are utilized, it is important to use their base64 representation.
It should also be noted that Soteria only requires public keys in cases where asymmetrical keys are employed.
IssEntityMap & IssPeerMap
These two configuration map iss to entity and peer respectively.
Note: default case is required
iss_entity_map:
0: "driver"
1: "passenger"
default: "none"
iss_peer_map:
0: "passenger"
1: "driver"
default: "none"
In the example above, we have two maps for entity & peer maps. As it's clear for entity structure 0 and 1 is mapped to driver and passenger, respectively. Vice Versa, for peer structure it can be seen that 1 and 0 is mapped to driver and passenger. We have also the default key for both two cases.
In the topic example, we have an accesses section in which 0 is mapped to 2 and 1 is mapped to -1 which can be interpreted as a map from IssEntity's Keys to Access Types. In the other words this structure means:
- Driver has a Pub access on topic
- Passenger has a None access on topic (No Access)
JWT
This is the JWT configuration. iss_name
and sub_name
are the name of issuer
and subject in the JWT token's payload respectively.
signing_method
is the method that is used to sign the JWT token.
Here are list of different signing methods
- ES384
- RS512 *
- PS512
- RS384 *
- HS256 *
- HS384 *
- RS256 *
- PS384
- ES256
- ES512
- EdDSA
- HS512 *
- PS256
Note: only the methods with
*
are supported for now.
Topic Configuration
type: "<<Name>>"
template: "<<regex template>>"
hash_type: 0|1
accesses:
iss-0: "<<access>>"
iss-1: "<<access>>"
Template
Topic template is a string consist of Variables and Functions
and regular expressions.
Variables and Function are replaced first, and then the whole template will compile as a regular expression.
The end result will be compared against the requested topic.
Example
This is template topic given in vendor:topics[#]:template
.
- type: driver_location
template: ^{{.company}}/driver/{{.sub}}/location$
accesses:
0: "2"
1: "-1"
^{{.company}}/driver/{{HashID .hashType .sub (IssToSnappID .iss)}}/location/[a-zA-Z0-9-_]+$
After parsing the template we get something like this
// company=snapp
// hashType=0
// sub=D96ZbvJakLp4PYd
// iss=0
^snapp/driver/D96ZbvJakLp4PYd/location/[a-zA-Z0-9-_]+$
Now if the requested topic match the created topic it is considered as a valid topic for that particular user.
requested_topic: snapp/driver/D96ZbvJakLp4PYd/location/23fw49vxd
created_topic_regex: ^snapp/driver/D96ZbvJakLp4PYd/location/[a-zA-Z0-9-_]+$
Available Variables
These are the variables available to use in the topic templates.
-
iss
issuer obtained from JWT token
-
sub
subject obtained from JWT token
-
hashType
Hash type field defined in topic template configuration
HashType |
Value |
HashID |
0 |
MD5 |
1 |
-
company
company field defined in vendor configuration
Available Functions
These are the function available to use in the topic templates.
IssToEntity(iss string) string
convert iss
obtained from JWT token to defined entity in issEntityMap
IssToPeer(iss string) string
convert iss
obtained from JWT token to define peer in issPeerMap
IssToSnappID(iss string) string
convert iss
obtained from JWT token to snappid.audience
HashID(hashType int, sub string, snappID snappid.audience)
generated hashID
for the given subject
base on the hashType
and snappid.audience
Note: snappid.audience
only is available for issuer 0 and 1 which are for driver and passenger respectively.
Accesses
List of all types of access on a topic.
Access |
Value |
Subscribe |
1 |
Publish |
2 |
Subscribe & Publish |
3 |
None |
-1 |
Suggested Issuers
Use any value for issuer but if you have an entity called Driver
or Passenger
,
we recommend use the following issuers for them.
Issuer |
Value |
Driver |
0 |
Passenger |
1 |