# Authentication

Articonf microservices get accessed via [HTTPS](https://en.wikipedia.org/wiki/HTTPS), this enables an encrypted and secure communication. To provide such a secure channel, [certificates](https://en.wikipedia.org/wiki/Public_key_certificate) are required. With these certificates, a client can verify the identity of the server.

The certificates get passed to the Flask application in the main.py file of each microservice. The argument itself is a [vector](https://datascienceplus.com/vectors-and-arrays-in-python/) with 2 entries: the certificate itself (a .crt file) and a key (a .key file), both passed as paths. This vector gets passed to app.run(..) via the named argument ssl_context. For further information on how a certificate is passed to a Flask app, look into this guide on [how to enable HTTPS communication in Flask](https://blog.miguelgrinberg.com/post/running-your-flask-application-over-https).

![ssl_context is used to pass the certificate to the Flask app](images/app_run_with_ssl.png)

## Resources

Articonf uses static resources, which are not present in the Git-repository due to security reasons. These files are located in a dedicated folder where the application will look for them. The files needed are:

| filename                      | purpose of the file                                                            |
|-------------------------------|--------------------------------------------------------------------------------|
| articonf1.crt                 | certificate for HTTPS communication (certificate)                              |
| articonf1.key                 | certificate for HTTPS communication (key)                                      |
| default_users.json            | list of default users who are already existing in articonf                     |
| jwt_secret.txt                | secret needed to sign the JWT tokens                                           |
| regular_user_credentials.json | credentials of the user used for internal authentication between microservices |

If Articonf runs on the server, the folder ```/srv/articonf``` is used for this purpose. If no other options are set, this location gets used per default.

## Running Articonf Locally

To enable the local mode, set the environment variable ```ARTICONF_LOCAL``` to ```1```. With this setting, the local swagger configuration is used to serve the routes. With this configuration, __no token validation will be performed__ for a better debugging experience, every token gets accepted.

To use a different resource directory than ```/srv/articonf```, the environment variable ```ARTICONF_RESOURCES_PATH``` is used. This variable can hold a path that points to a custom resource directory. For example, if the resource folder is located in the project root and called ```resources```, the content of the variable for the trace-retrieval microservice would be ```'../../../../resources'``` (note that there is no trailing slash in the path). 

The swagger-ui webinterface can accessed at [https://localhost:5000/api/ui](https://localhost:5000/api/ui) in local-mode. Chrome will report a security warning because the certificate is issued for ```articonf1.itec.aau.at``` and not for ```localhost```, so it is still safe to access the page.

## Authentication

![The can store an arbitrary amount of key-value pairs which are used in the backend](images/token_contents.png)

The token must be placed into the Authorization HTTP-Header. Note, that the keyword __Bearer__ must stay before the actual token. The meaning can be understood as “grant access to the bearer of the token”. Before the request gets executed at the server, the token is decoded and checked if it is still valid. If not, ```401 Unauthorized``` is returned. If the token is valid, the request gets processed.

![the token has to be placed in the "Authorization" HTTP header.](images/postman_request_with_token.png)

## JWT Tokens

A token has to have the following properties:
-	__Integrity:__ manipulated tokens must be detected to avoid forging of tokens by third parties
-	__User Authenticity:__ a token must be assignable to a user in the system 
-	__Server Authenticity:__ only the server must be able to issue tokens

Articonf uses the [JWT](https://jwt.io/) standard, because it provides all of these points and is implemented in a lot of different platforms which gives compatibility with other services. It allows to embed information as claims in the token which then can be decoded by anyone (no actual encryption of information happens). The token gets signed with a secret in order to provide Integrity and Server Authenticity. Each change in the payload of the token can then be detected as the signature cannot be reproduced.

## Roles

Currently, there are 2 roles in Articonf: User(u) and Administrator(a). The following matrix defines which role can access which request:

|                           | no authentication | User(u) | Administrator(a) |
|---------------------------|-------------------|---------|------------------|
| not sequred endpoint      | yes               | yes     | yes              |
| requires User(u)          | no                | yes     | yes              |
| requires Administrator(a) | no                | no      | yes              |

## Authentication Protocol for Third-Party Users

The first thing a client needs to do is authenticating itself on the server. This is done by passing username and password of a user to the rest-gateways endpoint 
```POST https://articonf1.itec.aau.at:30401/tokens```. If the credentials were correct, a JWT token is returned by the server, which can now be used to authenticate requests.

Each microservice keeps track of valid tokens. If it encounters a token that has not been checked, it forwards it to the rest-gateway (```POST https://articonf1.itec.aau.at/api/tokens/<TOKEN>```) which then checks the validity of the token (signature, timestamps) and returns this information to the requester. If the token was valid, the microservice adds it to its list of valid tokens, so future requests with the same token get processed without checking the token again.

![Authentication workflow.](images/authentication.png)

## Authentication Protocol Internally

There are scenarios where microservices must call each other. For this case, a helper class is implemented, which performs the necessary steps automatically. This class can be found at ```src/modules/security/token_manager.py```. The class is a singleton, so the ```getInstance()``` method gives access to the only available instance of ```TokenManager```, where the method ```getToken()``` can be used to retrieve a JWT token for internal requests. The roll of this user has regular User permissions.

```TokenManager``` uses the credentials stored in ```regular_user_credentials```.json to authenticate at the rest-gateway and caches the returned token, such that multiple requests to ```getToken()``` return the same one, which reduces traffic.