# Security

## Authentification Symfony

### Fonctionnement de base

L'authentification se fait via une requête POST envoyée à l'adresse `/login_check` avec le body suivant : 

    {
        "username": "login",
        "password": "password"
    }

En cas de succès, la requête renvoie un token qui servira ensuite à l'utilisateur à s'identifier.

Les requêtes suivantes devront posséder les headers suivants : 

* `x-accessid` : l'id de l'utilisateur (ou Access)
* `authorization` : une chaine de caractères de la forme "BEARER XXXXX", où XXXXX est le token retourné par la requête de login

### Connexion Switch

Certains utilisateurs (admins, familles) peuvent prendre le rôle d'un autre utilisateur via la connexion switch.

Pour ce faire, un nouveau header doit être ajouté aux requêtes : 

* `x-switch-user`: l'id de l'utilisateur dont on veut prendre le rôle



## Roles et Modules

Les droits d'un utilisateur sont conditionnés à différents critères, dont : 

* Les **modules** que possède l'organisation à laquelle il est appartient
* Les **rôles** de cet utilisateur au sein de cette organisation

On peut obtenir la liste des modules de l'organisation et des rôles de l'utilisateur actif en son sein au moyen de la 
requête : `/api/my_profile`


### Modules

Les modules d'une organisation dépendent du produit acheté par celle-ci et des éventuels modules complémentaires. Ces deux 
informations sont stoquées dans la table `Settings`.

Le fichier `config/opentalent/products.yaml` définit :

- L'appartenance des _modules_ aux _products_
- L'appartenance des _entities_ aux _modules_

De plus, le fichier `config/opentalent/modulesbyconditions.yaml` complète cette configuration en définissant des modules
présentant des conditions particulières (appartenance à la CMF en particulier)

A chaque requête effectuée, la classe `\App\Security\Voter\ModuleVoter` vérifie si la ressource demandée appartient à un
module possédé par l'organisation de l'utilisateur. Si ce n'est pas le cas, une erreur `AccessDeniedHttpException` est levée.


## Différentes méthodes de sécurisation

### Les annotations Api-Platform

La sécurité des ApiResources peut être définie de manière globale pour la ressource, ou pour chaque opération (Get, 
GetCollection, Put, Post, Delete) via les annotations.

Exemple : 

    #[ApiResource(
        operations: [
            new Get(
                security: '(is_granted("ROLE_ORGANIZATION_VIEW") or is_granted("ROLE_ORGANIZATION")) and object.getOrganization().getId() == user.getOrganization().getId()'
            ),
            new Put(
                security: 'is_granted("ROLE_ORGANIZATION") and object.getOrganization().getId() == user.getOrganization().getId()'
            )
        ],
    )]

Dans certains cas plus complexes (ex: Access), cette configuration peut être déplacée dans un fichier de configuration
situé dans le répertoire `~/config/api_platform/` et portant le nom de la ressource.

> Voir plus : https://api-platform.com/docs/core/security/


### Voters

Les voters permettent de contrôler l'accès à certaines ressources, selon le type d'opération.

Ils implémentent essentiellement deux méthodes : `supports` et `voteOnAttribute` qui prennent en paramètres la ressource 
et le type d'opération. `supports` retourne `true` si le voter doit s'appliquer dans ce cas. Si oui, `voteOnAttribute`
est appelée et retourne `true` si l'opération est autorisée.

> TODO: quand faut-il retourner false et quand faut-il lever une AccessDeniedHttpException ?

Pour qu'un Voter soit appelé, il faut configurer la sécurité de la ressource via son annotation et utiliser la méthode 
`is_granted` combinée à une des constantes : 

Exemple : 

    #[ApiResource(
        operations: [
            new Get(security: "is_granted('READ', object)"),
            new Put(security: "is_granted('EDIT', object)"),
            new Post(security: "is_granted('CREATE', object)"),
            new Delete(security: "is_granted('DELETE', object)"),
        ]
    )]
    class File

    

Les voters custom sont enregistrés dans le répertoire `src/Security/Voter`.

> Voir plus : https://symfony.com/doc/current/security/voters.html


### Extensions Doctrine

Le framework Api-Platform propose un système d'extensions doctrine pour ajouter des filtres automatiques aux opérations
réalisées sur des ressources voulues.

Concrètement, l'extension ajoutera une condition au `WHERE` de la requête SQL.

Une extension implémente trois méthodes : 

* `applyToCollection`
* `applyToItem`
* `addWhere`

Les deux premières permettent de tester si l'extension doit s'appliquer à la ressource.

La dernière ajoute la condition en question.

> Voir : https://api-platform.com/docs/core/extensions/


### Quand utiliser les annotations, un Voter ou une Extension Doctrine ?

Si la sécurité doit pouvoir s'appliquer à une collection et filtrer le résultat de celle-ci (exemple: les notifications 
d'un utilisateur) : on utilisera une _Extension Doctrine_

Sinon, si les conditions d'accès peuvent s'écrire facilement avec l'expression language des annotations
api-platform, on utilisera les _annotations Api-platform_.

Si aucune des conditions précédentes n'est remplie, on utilisera un _Voter Symfony_.


## Internal Requests

Certaines routes de la forme `/internal/...` permettent d'accepter des requêtes sans que le client ne
soit authentifié (cf `config/packages/security.yaml`), en se basant sur un contrôle de l'IP et un token. 

> Voir: https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/doc/internal_requests.md



## Cas particuliers 

### Les Fichiers

Le client est autorisé à consulter l'enregistrement si l'une de ces conditions est vraie :

* pas de date de disponibilité ou date de disponibilité antérieure à Now
* date de disponibilité postérieure à Now, mais utilisateur a le rôle ROLE_BILLACCOUNTING et le fichier est de type BILL (facture)
* visibilité est 'EVERYBODY' 
* requête interne
* est connecté et fait partie des AccessPersons du fichier
* est connecté et est le propriétaire du fichier
* est connecté et a le rôle ROLE_FILE et fichier appartient à l'utilisateur ou à son organisation
* est connecté et fichier a des accessRoles et user a un des roles présents dans accessRoles et fichier appartient à l'utilisateur ou à son organisation (deprecated)


Est autorisé à éditer si :

* pas de date de disponibilité ou date de disponibilité antérieure à Now
* date de disponibilité postérieure à Now, mais utilisateur a le rôle ROLE_BILLACCOUNTING et le fichier est de type BILL (facture)
* est connecté et a le rôle ROLE_FILE et fichier appartient à l'utilisateur ou à son organisation
* est connecté et est le propriétaire du fichier

Est autorisé à créer si :

* est connecté

Est autorisé à supprimer si :

* est connecté et est autorisé à éditer
