# 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