Droits par rôle
Une fois qu'on sait qui appelle (Authentification), reste à savoir ce qu'il a le droit de faire. Toutes ces décisions sont prises à un seul endroit : lib/timemanager/authorization.ex.
Les trois rôles
| Rôle | En une phrase |
|---|---|
Employé (employee) | pointe, voit ses heures, demande des corrections |
Manager (manager) | en plus, gère ses équipes : les heures, absences et semaines de ses membres |
General Manager (general_manager) | en plus, gère les comptes et voit toutes les équipes, comme s'il en était le manager |
« Ses gens », pour un manager, ce sont les membres des équipes qu'il manage (Teams.manages?/2).
Le principe : une seule fonction, refus par défaut
Un contrôleur ne réécrit jamais une règle. Il pose la question :
Authorization.authorize(current_user, :edit_working_times, user_id)
# => :ok ou {:error, :forbidden} (réponse 403)Chaque règle est une clause de la fonction privée allowed?/3. La dernière clause refuse tout :
defp allowed?(_current_user, _action, _subject), do: falseUne action oubliée est donc refusée, jamais permise par erreur. C'est le principe du refus par défaut.
L'ordre des clauses compte
Elixir essaie les clauses de haut en bas et prend la première qui correspond. Exemple :
defp allowed?(%User{id: id}, :edit_working_times, id), do: false # 1. soi-même : non
defp allowed?(%User{role: "general_manager"}, :edit_working_times, _), do: true # 2. le GM : ouiPour le General Manager qui veut modifier ses propres heures, la clause 1 correspond d'abord : refusé. Inverser les deux lignes lui donnerait ce droit. Toucher à l'ordre de ce fichier demande donc de relancer authorization_test.exs.
Le tableau complet
Action (authorize) | Employé | Manager | General Manager |
|---|---|---|---|
:view_data_of voir les heures, pointages, tableau de bord | les siennes | les siennes + ses gens | tout le monde |
:clock pointer, prendre une pause | soi | soi | soi |
:edit_working_times modifier des heures, absences, valider une semaine | ✗ | ses gens, jamais soi | tout le monde, jamais soi |
:request_correction demander une correction | soi | soi | soi |
:review_correction accepter ou refuser une demande | ✗ | celles de ses gens, jamais la sienne | toutes, la sienne comprise |
:reopen_week rouvrir une semaine validée | ✗ | celles qu'il a validées | toutes |
:list_users lister les comptes | ✗ | les comptes actifs | tous |
:invite_user inviter une personne | ✗ | ✗ | ✓ |
:change_role promouvoir, retirer les droits | ✗ | ✗ | les autres, jamais soi |
:delete_account supprimer un compte | le sien | le sien | les autres, jamais le sien |
:update_profile nom, langue, thème | le sien | le sien | le sien |
:update_email changer d'e-mail | ✗ | ✗ | le sien (en deux temps) |
:change_password changer de mot de passe | le sien | le sien | le sien |
:export_data « Mes données » | les siennes | les siennes | les siennes |
:view_team, :view_team_averages, :manage_team | ✗ | les équipes qu'il manage | toutes |
:create_team créer une équipe | ✗ | dont il est le manager | pour n'importe quel manager |
:assign_team_manager changer le manager d'une équipe | ✗ | ✗ | ✓ |
Les règles qui protègent les employés
Le sujet demande de protéger les employés contre un usage non éthique de l'application. Plusieurs règles servent exactement à ça :
| Règle | Ce qu'elle empêche |
|---|---|
Personne ne pointe pour un autre (:clock, soi seulement) | un manager qui « arrange » une arrivée |
Personne ne modifie ses propres heures (:edit_working_times, jamais soi) | un manager ou le GM qui s'ajoute des heures ; l'employé passe par une demande de correction, motivée et examinée |
| Toute modification est journalisée | une heure changée en silence : la personne la voit dans « Mes modifications » et reçoit une notification |
« Mes données » à la personne seule (:export_data) | même le GM ne peut pas télécharger le dossier complet de quelqu'un |
| Un manager ne voit que ses gens | la surveillance de personnes qui ne sont pas dans ses équipes |
Le General Manager examine ses propres demandes
Personne n'est au-dessus de lui : ses demandes de correction ne pourraient être examinées par personne d'autre. Il les examine donc lui-même, mais il ne modifie toujours jamais ses heures directement : sa correction passe par une demande, motivée et journalisée comme les autres.
Ce que les listes renvoient
Certaines routes n'ont pas besoin de authorize : elles ne renvoient que ce que l'appelant a le droit de voir.
| Route | Contenu |
|---|---|
GET /api/teams | les équipes qu'on manage (manager), toutes (GM), une liste vide (employé) |
GET /api/corrections | ses propres demandes, plus celles qu'on peut examiner |
GET /api/notifications | les siennes, toujours |
Les mêmes règles côté web
Le site web cache les pages et les boutons interdits (meta.roles dans son routeur, canViewDataOf dans utils/permissions.js), pour le confort : on ne propose pas une action qui serait refusée. Mais seule l'API décide : un bouton affiché par erreur donnerait un 403, jamais une action interdite.