Skip to content

Commit

Permalink
MF-28 - Remove WS and update Content Type (absmach#29)
Browse files Browse the repository at this point in the history
Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>
  • Loading branch information
manuio committed Apr 21, 2020
1 parent f7e4759 commit ab255b6
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 86 deletions.
20 changes: 10 additions & 10 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

Mainflux IoT platform is comprised of the following services:

| Service | Description |
|:--------------------------------------------------------------------------|:------------------------------------------------------------------------|
| [users](https://github.com/mainflux/mainflux/tree/master/users) | Manages platform's users and auth concerns |
| [things](https://github.com/mainflux/mainflux/tree/master/things) | Manages platform's things, channels and access policies |
| [http-adapter](https://github.com/mainflux/mainflux/tree/master/http) | Provides an HTTP interface for accessing communication channels |
| [ws-adapter](https://github.com/mainflux/mainflux/tree/master/ws) | Provides a WebSocket interface for accessing communication channels |
| [mqtt-adapter](https://github.com/mainflux/mainflux/tree/master/mqtt) | Provides an MQTT interface for accessing communication channels |
| [coap-adapter](https://github.com/mainflux/mainflux/tree/master/coap) | Provides a CoAP interface for accessing communication channels |
| [lora-adapter](https://github.com/mainflux/mainflux/tree/master/lora) | Provides a LoRa Server forwarder for accessing communication channels |
| [mainflux-cli](https://github.com/mainflux/mainflux/tree/master/cli) | Command line interface |
| Service | Description |
|:--------------------------------------------------------------------------|:---------------------------------------------------------------------------------|
| [users](https://github.com/mainflux/mainflux/tree/master/users) | Manages platform's users and auth concerns |
| [things](https://github.com/mainflux/mainflux/tree/master/things) | Manages platform's things, channels and access policies |
| [http-adapter](https://github.com/mainflux/mainflux/tree/master/http) | Provides an HTTP interface for accessing communication channels |
| [mqtt-adapter](https://github.com/mainflux/mainflux/tree/master/mqtt) | Provides an MQTT and MQTT over WS interface for accessing communication channels |
| [coap-adapter](https://github.com/mainflux/mainflux/tree/master/coap) | Provides a CoAP interface for accessing communication channels |
| [opcua-adapter](https://github.com/mainflux/mainflux/tree/master/opcua) | Provides an OPC-UA interface for accessing communication channels |
| [lora-adapter](https://github.com/mainflux/mainflux/tree/master/lora) | Provides a LoRa Server forwarder for accessing communication channels |
| [mainflux-cli](https://github.com/mainflux/mainflux/tree/master/cli) | Command line interface |

![arch](img/architecture.jpg)

Expand Down
33 changes: 2 additions & 31 deletions docs/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ docker-compose -f docker/docker-compose.yml up

## Mutual TLS Authentication with X.509 Certificates

In most of the cases, HTTPS, WSS, MQTTS or secure CoAP are secure enough. However, sometimes you might need an even more secure connection. Mainflux supports mutual TLS authentication (_mTLS_) based on [X.509 certificates](https://tools.ietf.org/html/rfc5280). By default, the TLS protocol only proves the identity of the server to the client using the X.509 certificate and the authentication of the client to the server is left to the application layer. TLS also offers client-to-server authentication using client-side X.509 authentication. This is called two-way or mutual authentication. Mainflux currently supports mTLS over HTTP, WS, and MQTT protocols. In order to run Docker composition with mTLS turned on, you can execute the following command from the project root:
In most of the cases, HTTPS, MQTTS or secure CoAP are secure enough. However, sometimes you might need an even more secure connection. Mainflux supports mutual TLS authentication (_mTLS_) based on [X.509 certificates](https://tools.ietf.org/html/rfc5280). By default, the TLS protocol only proves the identity of the server to the client using the X.509 certificate and the authentication of the client to the server is left to the application layer. TLS also offers client-to-server authentication using client-side X.509 authentication. This is called two-way or mutual authentication. Mainflux currently supports mTLS over HTTP, MQTT and MQTT over WS protocols. In order to run Docker composition with mTLS turned on, you can execute the following command from the project root:

```bash
AUTH=x509 docker-compose -f docker/docker-compose.yml up -d
Expand All @@ -25,7 +25,7 @@ make thing_cert KEY=<thing_key> CRT_FILE_NAME=<cert_name>
These commands use [OpenSSL](https://www.openssl.org/) tool, so please make sure that you have it installed and set up before running these commands.

- Command `make ca` will generate a self-signed certificate that will later be used as a CA to sign other generated certificates. CA will expire in 3 years.
- Command `make server_cert` will generate and sign (with previously created CA) server cert, which will expire after 1000 days. This cert is used as a Mainflux server-side certificate in usual TLS flow to establish HTTPS, WSS, or MQTTS connection.
- Command `make server_cert` will generate and sign (with previously created CA) server cert, which will expire after 1000 days. This cert is used as a Mainflux server-side certificate in usual TLS flow to establish HTTPS or MQTTS connection.
- Command `make thing_cert` will finally generate and sign a client-side certificate and private key for the thing.

In this example `<thing_key>` represents key of the thing, and `<cert_name>` represents the name of the certificate and key file which will be saved in `docker/ssl/certs` directory. Generated Certificate will expire after 2 years. The key must be stored in the x.509 certificate `CN` field. This script is created for testing purposes and is not meant to be used in production. We strongly recommend avoiding self-signed certificates and using a certificate management tool such as [Vault](https://www.vaultproject.io/) for the production.
Expand Down Expand Up @@ -54,32 +54,3 @@ mosquitto_pub -u <thing_id> -P <thing_key> -t channels/<channel_id>/messages -h
```
mosquitto_sub -u <thing_id> -P <thing_key> --cafile docker/ssl/certs/ca.crt --cert docker/ssl/certs/<thing_cert_name>.crt --key docker/ssl/certs/<thing_cert_key>.key -t channels/<channel_id>/messages -h localhost -p 8883
```

### WSS
```javascript
const WebSocket = require('ws');

// Do not verify self-signed certificates if you are using one.
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'

// Replace <channel_id> and <thing_key> with real values.
const ws = new WebSocket('wss://localhost/ws/channels/<channel_id>/messages?authorization=<thing_key>',
// This is ClientOptions object that contains client cert and client key in the form of string. You can easily load these strings from cert and key files.
{
cert: `-----BEGIN CERTIFICATE-----....`,
key: `-----BEGIN RSA PRIVATE KEY-----.....`
})

ws.on('open', () => {
ws.send('something')
})

ws.on('message', (data) => {
console.log(data)
})
ws.on('error', (e) => {
console.log(e)
})
```

As you can see, `Authorization` header does not have to be present in the HTTP request, since the key is present in the certificate. However, if you pass `Authorization` header, it _must be the same as the key in the cert_. In the case of MQTTS, `password` filed in CONNECT message _must match the key from the certificate_. In the case of WSS, `Authorization` header or `authorization` query parameter _must match cert key_.
47 changes: 3 additions & 44 deletions docs/messaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,49 +7,12 @@ of message publishing for each of the supported protocols.
To publish message over channel, thing should send following request:

```
curl -s -S -i --cacert docker/ssl/certs/ca.crt -X POST -H "Content-Type: application/senml+json" -H "Authorization: <thing_token>" https://localhost/http/channels/<channel_id>/messages -d '[{"bn":"some-base-name:","bt":1.276020076001e+09, "bu":"A","bver":5, "n":"voltage","u":"V","v":120.1}, {"n":"current","t":-5,"v":1.2}, {"n":"current","t":-4,"v":1.3}]'
curl -s -S -i --cacert docker/ssl/certs/ca.crt -X POST -H "Authorization: <thing_token>" https://localhost/http/channels/<channel_id>/messages -d '[{"bn":"some-base-name:","bt":1.276020076001e+09, "bu":"A","bver":5, "n":"voltage","u":"V","v":120.1}, {"n":"current","t":-5,"v":1.2}, {"n":"current","t":-4,"v":1.3}]'
```

Note that if you're going to use senml message format, you should always send
messages as an array.

## WebSocket

To publish and receive messages over channel using web socket, you should first
send handshake request to `/channels/<channel_id>/messages` path. Don't forget
to send `Authorization` header with thing authorization token. In order to pass
message content type to WS adapter you can use `Content-Type` header.

If you are not able to send custom headers in your handshake request, send them as
query parameter `authorization` and `content-type`. Then your path should look like
this `/channels/<channel_id>/messages?authorization=<thing_auth_key>&content-type=<content-type>`.

If you are using the docker environment prepend the url with `ws`. So for example
`/ws/channels/<channel_id>/messages?authorization=<thing_auth_key>&content-type=<content-type>`.

### Basic nodejs example

```javascript
const WebSocket = require('ws');

// do not verify self-signed certificates if you are using one
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'

// cbf02d60-72f2-4180-9f82-2c957db929d1 is an example of a thing_auth_key
const ws = new WebSocket('wss://localhost/ws/channels/1/messages?authorization=cbf02d60-72f2-4180-9f82-2c957db929d1&content-type=application%2Fsenml%2Bjson')

ws.on('open', () => {
ws.send('something')
})

ws.on('message', (data) => {
console.log(data)
})
ws.on('error', (e) => {
console.log(e)
})
```

## MQTT

To send and receive messages over MQTT you could use [Mosquitto tools](https://mosquitto.org),
Expand All @@ -67,11 +30,7 @@ To subscribe to channel, thing should call following command:
mosquitto_sub -u <thing_id> -P <thing_key> -t channels/<channel_id>/messages -h localhost
```

In order to pass content type as part of topic, one should append it to the end
of an existing topic. Content type value should always be prefixed with `/ct/`.
If you want to use standard topic such as `channels/<channel_id>/messages`
with SenML content type, you should use following topic `channels/<channel_id>/messages/ct/application_senml-json`. Characters like `/` and `+` in the content type will be
replaced with `_` and `-` respectively.
If you want to use standard topic such as `channels/<channel_id>/messages` with SenML content type (JSON or CBOR), you should use following topic `channels/<channel_id>/messages`.

If you are using TLS to secure MQTT connection, add `--cafile docker/ssl/certs/ca.crt`
to every command.
Expand All @@ -84,7 +43,7 @@ CoAP adapter implements CoAP protocol using underlying UDP and according to [RFC
coap://localhost/channels/<channel_id>/messages?authorization=<thing_auth_key>
```

To send a message, use `POST` request. When posting a message you can pass content type in `Content-Format` option.
To send a message, use `POST` request.
To subscribe, send `GET` request with Observe option set to 0. There are two ways to unsubscribe:
1) Send `GET` request with Observe option set to 1.
2) Forget the token and send `RST` message as a response to `CONF` message received by the server.
Expand Down
2 changes: 1 addition & 1 deletion docs/storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ In order to run these services, core services, as well as the network from the c

## Writers

Writers provide an implementation of various `message writers`. Message writers are services that consume Mainflux messages, transform them to `SenML` format, and store them in specific data store.
Writers provide an implementation of various `message writers`. Message writers are services that consume Mainflux messages, transform them to `SenML` format, and store them in specific data store. Supported message payload formats are SenML+CBOR and SenML+JSON. They are configurable over environment variables in each writer (`MF_CASSANDRA_WRITER_CONTENT_TYPE`, `MF_POSTGRES_WRITER_CONTENT_TYPE`, `MF_INFLUX_WRITER_CONTENT_TYPE` and `MF_MONGO_WRITER_CONTENT_TYPE`) and expect `application/senml+json` or `application/senml+cbor` formats.

Each writer can filter messages based on subjects list that is set in `subjects.toml` configuration file. If you want to listen on all subjects, just pass one element ["channels.>"], otherwise pass the list of subjects. Here is an example:

Expand Down

0 comments on commit ab255b6

Please sign in to comment.