Skip to content

Commit

Permalink
NOISSUE - Update docs (absmach#683)
Browse files Browse the repository at this point in the history
* Add authorization section to the docs

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Slow down Bootstrap gif

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Use heading 4 instead of italic

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Replace gif with carousel

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
  • Loading branch information
dborovcanin authored and drasko committed Apr 4, 2019
1 parent 3f26efc commit b32b22b
Show file tree
Hide file tree
Showing 12 changed files with 332 additions and 94 deletions.
2 changes: 1 addition & 1 deletion coap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ MF_THINGS_URL=[Things service URL] MF_NATS_URL=[NATS instance URL] MF_COAP_ADAPT
## Usage
If CoAP adapter is running locally (on default 5683 port), a valid URL would be: `coap://localhost/channels/<channel_id>/messages?authorization=<thing_auth_key>`.
Since CoAP protocol does not support `Authorization` header (option) and options have limited size, in order to send CoAP messages, valid `authorization` value must be present in `Uri-Query` option.
Since CoAP protocol does not support `Authorization` header (option) and options have limited size, in order to send CoAP messages, valid `authorization` value (a valid Thing key) must be present in `Uri-Query` option.
85 changes: 85 additions & 0 deletions docs/authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
## Authentication using Mainflux keys
By default, Mainflux uses Mainflux keys for authentication. The Мainflux key is a secret key that's generated at the Thing creation. In order to authenticate, the Thing needs to send its key with the message. The way the key is passed depends on the protocol used to send a message and differs from adapter to adapter. For more details on how this key is passed around, please check out [messaging section](https://mainflux.readthedocs.io/en/latest/messaging).
This is the default Mainflux authentication mechanism and this method is used if the composition is started using the following command:

```bash
docker-compose -f docker/docker-compose.yml up
```

## Mutual authentication

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:

```bash
AUTH=x509 docker-compose -f docker/docker-compose.yml up -d
```

Mutual authentication includes client-side certificates. Certificates can be generated using the simple script provided [here](http://www.github.com/mainflux/mainflux/tree/master/docker/ssl/Makefile). In order to create a valid certificate, you need to create Mainflux thing using the process described in the [provisioning section](provisioning.md). After that, you need to fetch created thing key. Thing key will be used to create x.509 certificate for the corresponding thing. To create a certificate, execute the following commands:

```bash
cd docker/ssl
make ca
make server_cert
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 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.

Once you have created CA and server-side cert, you can spin the composition using:

```bash
AUTH=x509 docker-compose -f docker/docker-compose.yml up -d
```

Then, you can create user and provision things and channels. Now, in order to send a message from the specific thing to the channel, you need to connect thing to the channel and generate corresponding client certificate using aforementioned commands. To publish a message to the channel, thing should send following request:

### HTTPS
```bash
curl -s -S -i --cacert docker/ssl/certs/ca.crt --cert docker/ssl/certs/<thing_cert_name>.crt --key docker/ssl/certs/<thing_cert_key>.key --insecure -X POST -H "Content-Type: application/senml+json" 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}]'
```

### MQTTS

#### Publish
```bash
mosquitto_pub -u <thing_id> -P <thing_key> -t channels/<channel_id>/messages -h localhost --cafile docker/ssl/certs/ca.crt --cert docker/ssl/certs/<thing_cert_name>.crt --key docker/ssl/certs/<thing_cert_key>.key -m '[{"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}]'
```

#### Subscribe
```
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
```

### 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_.
232 changes: 231 additions & 1 deletion docs/bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,237 @@ Mainflux platform supports bootstrapping process, but some of the preconditions

> Bootstrapping and provisioning are two different procedures. Provisioning refers to entities management while bootstrapping is related to entity configuration.
![bootstrapping flow](img/bs_flow.gif)

<style>
.carousel {
margin-left: 15%;
margin-right: 15%;
}

ul.slides {
display: block;
position: relative;
height: 600px;
margin: 0;
padding: 0;
overflow: hidden;
list-style: none;
}

.slides * {
user-select: none;
-ms-user-select: none;
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-webkit-touch-callout: none;
}

ul.slides input {
display: none;
}

.slide-container {
display: block;
}

.slide-image {
display: block;
position: absolute;
width: 100%;
height: 100%;
top: 0;
opacity: 0;
transition: all .7s ease-in-out;
}

.slide-image img {
width: auto;
min-width: 100%;
height: 100%;
}

.carousel-controls {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 999;
font-size: 100px;
line-height: 600px;
color: #d2dade;
}

.carousel-controls label {
display: none;
position: absolute;
padding: 0 20px;
opacity: 0;
transition: opacity .2s;
cursor: pointer;
}

.slide-image:hover+.carousel-controls label {
opacity: 0.5;
}

.carousel-controls label:hover {
opacity: 1;
}

.carousel-controls .prev-slide {
width: 49%;
text-align: left;
left: 0;
}

.carousel-controls .next-slide {
width: 49%;
text-align: right;
right: 0;
}

.carousel-dots {
position: absolute;
left: 0;
right: 0;
bottom: 20px;
z-index: 999;
text-align: center;
}

.carousel-dots .carousel-dot {
display: inline-block;
width: 30px;
height: 30px;
border-radius: 50%;
background-color: #ecf0f2;
opacity: 0.5;
margin: 10px;
}

input:checked+.slide-container .slide-image {
opacity: 1;
transform: scale(1);
transition: opacity 1s ease-in-out;
}

input:checked+.slide-container .carousel-controls label {
display: block;
}

input#img-1:checked~.carousel-dots label#img-dot-1,
input#img-2:checked~.carousel-dots label#img-dot-2,
input#img-3:checked~.carousel-dots label#img-dot-3,
input#img-4:checked~.carousel-dots label#img-dot-4,
input#img-5:checked~.carousel-dots label#img-dot-5,
input#img-6:checked~.carousel-dots label#img-dot-6 {
opacity: 1;
}

input:checked+.slide-container .nav label {
display: block;
}
</style>
<div>
<div class="carousel">
<ul class="slides">
<input type="radio" name="radio-buttons" id="img-1" checked />
<li class="slide-container">
<div class="slide-image">
<img src="img/bootstrap/1.png">
</div>
<div class="carousel-controls">
<label for="img-3" class="prev-slide">
<span>&lsaquo;</span>
</label>
<label for="img-2" class="next-slide">
<span>&rsaquo;</span>
</label>
</div>
</li>
<input type="radio" name="radio-buttons" id="img-2" />
<li class="slide-container">
<div class="slide-image">
<img src="img/bootstrap/2.png">
</div>
<div class="carousel-controls">
<label for="img-1" class="prev-slide">
<span>&lsaquo;</span>
</label>
<label for="img-3" class="next-slide">
<span>&rsaquo;</span>
</label>
</div>
</li>
<input type="radio" name="radio-buttons" id="img-3" />
<li class="slide-container">
<div class="slide-image">
<img src="img/bootstrap/3.png">
</div>
<div class="carousel-controls">
<label for="img-2" class="prev-slide">
<span>&lsaquo;</span>
</label>
<label for="img-4" class="next-slide">
<span>&rsaquo;</span>
</label>
</div>
</li>
<input type="radio" name="radio-buttons" id="img-4" />
<li class="slide-container">
<div class="slide-image">
<img src="img/bootstrap/4.png">
</div>
<div class="carousel-controls">
<label for="img-3" class="prev-slide">
<span>&lsaquo;</span>
</label>
<label for="img-5" class="next-slide">
<span>&rsaquo;</span>
</label>
</div>
</li>
<input type="radio" name="radio-buttons" id="img-5" />
<li class="slide-container">
<div class="slide-image">
<img src="img/bootstrap/5.png">
</div>
<div class="carousel-controls">
<label for="img-4" class="prev-slide">
<span>&lsaquo;</span>
</label>
<label for="img-6" class="next-slide">
<span>&rsaquo;</span>
</label>
</div>
</li>
<input type="radio" name="radio-buttons" id="img-6" />
<li class="slide-container">
<div class="slide-image">
<img src="img/bootstrap/6.png">
</div>
<div class="carousel-controls">
<label for="img-5" class="prev-slide">
<span>&lsaquo;</span>
</label>
<label for="img-1" class="next-slide">
<span>&rsaquo;</span>
</label>
</div>
</li>
<div class="carousel-dots">
<label for="img-1" class="carousel-dot" id="img-dot-1"></label>
<label for="img-2" class="carousel-dot" id="img-dot-2"></label>
<label for="img-3" class="carousel-dot" id="img-dot-3"></label>
<label for="img-4" class="carousel-dot" id="img-dot-4"></label>
<label for="img-5" class="carousel-dot" id="img-dot-5"></label>
<label for="img-6" class="carousel-dot" id="img-dot-6"></label>
</div>
</ul>
</div>
</div>


### Configuration

Expand Down
Binary file added docs/img/bootstrap/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/bootstrap/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/bootstrap/3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/bootstrap/4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/bootstrap/5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/bootstrap/6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/img/bs_flow.gif
Binary file not shown.
Loading

0 comments on commit b32b22b

Please sign in to comment.