Skip to content

Commit 691a301

Browse files
TeddyRoncinCopilot
andcommitted
Refactor permissions (#35)
Checkez le README, si ce n'est pas clair dites-le moi :) --------- Co-authored-by: Copilot <[email protected]>
1 parent fb29296 commit 691a301

File tree

96 files changed

+2535
-1063
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+2535
-1063
lines changed

.env.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ LDAP_PWD=
1919

2020
ANNAL_UPLOAD_DIR=uploads/exams/
2121
CAS_URL=https://cas.utt.fr/cas
22+
CAS_SERVICE=http://localhost:8080
2223

2324
# The URL of the old database. It is only used to migrate the data from the old database to the new one.
2425
OLD_DATABASE_URL="mysql://dev:dev@localhost:3306/etuutt_old"
2526

27+
ETUUTT_WEBSITE_APPLICATION_ID=52ce644d-183f-49e9-bd21-d2d4f37e2196
28+
2629
TIMETABLE_URL="monedt.utt.fr"

.env.test.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@ FAKER_SEED=42
1515

1616
ANNAL_UPLOAD_DIR=uploads/exams/
1717
CAS_URL=https://cas.utt.fr/cas
18+
CAS_SERVICE=https://etu.utt.fr/login
1819
LDAP_URL=ldap://localhost:3002
1920
LDAP_USER=
2021
LDAP_PWD=
2122

23+
ETUUTT_WEBSITE_APPLICATION_ID=52ce644d-183f-49e9-bd21-d2d4f37e2196
24+
2225
# Can be changed to localhost for testing
2326
TIMETABLE_URL="monedt.utt.fr"
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Permissions
2+
3+
Cette page traite à la fois des permissions des utilisateurs, et de celles des applications utilisant l'API.
4+
5+
Tous les termes spécifiques aux permissions seront en _italique_, et leur définition peut être retrouvée dans la partie [terminologie](#terminologie).
6+
7+
## Terminologie
8+
9+
### Permission
10+
11+
Une _permission_ est une autorisation de réaliser une action ou d'accéder à des données. Dès que quelque chose ne devrait pas être accessible / faisable avec n'importe quelle _clé API_ (si vous lisez la documentation pour la première fois, _clé API_ ~ utilisateur), une _permission_ pour faire cette dite chose doit exister.
12+
13+
Les _permissions_ sont divisées en 2 catégories : les _user permissions_ et les _API permissions_.
14+
15+
**Exemples :** La permission permettant de voir les commentaires des UEs, la permission permettant de modifier les permissions des autres, ...
16+
17+
### User permission
18+
19+
Une _user permission_ est un type de _permission_. Ces _permissions_ sont les _permissions_ liées à un utilisateur.
20+
21+
Elles ont la particularité de pouvoir s'appliquer à un utilisateur mais pas à un autre.
22+
23+
**Exemples :** accéder aux données privées des utilisateurs, modifier les données d'un utilisateur, ...
24+
25+
### API permission
26+
27+
Une _API permission_ est un type de _permission_. Ces _permissions_ sont les _permissions_ globales, qui portent sur toute l'API.
28+
29+
**Exemples :** modérer les commentaires, modérer les annales, etc...
30+
31+
### Application
32+
33+
Une application est un logiciel ayant besoin d'un accès à l'API de EtuUTT. Chaque application est reliée à un utilisateur, qui est l'administrateur de celle-ci.
34+
35+
**Exemples :** le front de EtuUTT, l'application mobile EtuUTT, le site de l'intégration, ...
36+
37+
### Clé API (ou api key)
38+
39+
Une _clé API_ (ou _api key_) est une relation entre un utilisateur et une _application_. Un utilisateur ne peut avoir qu'une _clé API_ par _application_.
40+
41+
```{note}
42+
Une _clé API_ **n'est pas** un token, c'est plutôt un objet qui servira à générer un token et authentifier les requêtes.
43+
44+
Un utilisateur n'a pas nécessairement les mêmes droits sur les différentes _applications_. Il est tout de même important de noter que rien ne l'empêchera d'utiliser une _clé API_ sur un logiciel qui ne devrait pas utiliser cette _clé API_. Il est donc important **d'avoir confiance** en l'utilisateur si on lui donne des permissions sur une application. S'il a une permission sur une _application_, il peut simuler des requêtes venant de cette _application_ alors même qu'il n'utilise pas le logiciel censé l'utiliser.
45+
```
46+
47+
**Exemple :** prenons l'exemple de l'intégration : ils auront :
48+
* Une _clé API_ pour se connecter au front de EtuUTT avec l'utilisateur `[email protected]` (reliée à l'_application_ `EtuUTT-front`)
49+
* Une _clé API_ pour le back de leur site web (reliée à l'_application_ `Integration-website`)
50+
* Une _clé API_ par utilisateur de leur application mobile (logiciel qui n'utiliserait pas le backend de leur site web), avec uniquement les droits de base (_clés API_ reliées à l'_application_ `Integration-app`). Chaque _clé API_ a des permissions différentes, ce qui signifie qu'on peut donner des droits à un utilisateur en particulier sur l'_application_ de l'intégration. Chaque utilisateur peut aussi accorder des droits différents à l'_application_.
51+
52+
### Bearer token
53+
54+
Le _bearer token_ est une chaîne de caractère encodant une certaine _clé API_, en utilisant le standard JWT.
55+
56+
### Soft grant
57+
58+
Un _soft grant_ ne peut se faire que sur des _user permissions_ (ça n'aurait pas de sens sur des _api permissions_).
59+
60+
Les _soft grant_ ne donnent pas la permission à la _clé API_ sur tous les utilisateurs. Chaque utilisateur doit explicitement donner son consentement pour que la _clé API_ puisse exercer sa _permission_ sur son profile (accéder à des informations personnelles par exemple).
61+
62+
Une _clé API_ peut demander un _soft grant_ de n'importe quelle _user permission_. Tant qu'elle n'aura reçu le consentement de personne, elle n'aura aucun droit supplémentaire.
63+
64+
**Exemple :** Guillaume, grand rageux qu'il est, décide de développer une application, qui permet d'avoir une interface bien plus agréable que celle de EtuUTT. Il a aussi une API (en Rust, on se respecte), qui s'occupe de faire l'interface entre l'API EtuUTT et son application. Guillaume pourra donner la _permission_ à sa _clé API_ de voir le détail des utilisateurs. Cependant, ce sera un _soft grant_, ce qui signifie qu'il n'aura au début accès aux détails d'aucun utilisateur. Teddy va alors être curieux du projet, et se connecter à son application. Pendant l'authentification avec EtuUTT, il devra donner son consentement pour que Guillaume puisse récupérer ses informations personnelles. À partir de ce moment là, Guillaume pourra utiliser sa permission sur Teddy, mais **uniquement** sur Teddy. (Ah, au fait, Teddy a pas aimé l'application et a revoke son consentement 😔)
65+
66+
### Hard grant
67+
68+
Un _hard grant_ peut se faire sur n'importe quel type de _permission_ (_user permissions_ et _API permissions_).
69+
70+
Un _hard grant_ ne nécessite le consentement de personne, et s'applique sur tous les utilisateurs. Seuls des administrateurs peuvent effectuer un _hard grant_.
71+
72+
Une _API permissions_ est nécessairement _hard granted_ (aucun sens de les _soft grant_).
73+
74+
**Exemple :** Guillaume rêve de pouvoir. Et finalement, il a amélioré son application (Teddy est revenu sur son choix). Son code est devenu propriété de l'UNG (merci Guillaume). Nous pouvons donc donner la _permission_ pour voir les informations personnelles des utilisateurs à l'_application_. Un administrateur va alors _hard grant_ la _permission_ à l'_application_ de Guillaume. Les utilisateurs n'ont pas besoin de donner leur consentement, Guillaume aspire toutes leurs données 😈.
75+
76+
```{warning}
77+
Attention cependant à bien respecter le RGPD en faisant un _hard grant_ d'une _user permission_ ! \
78+
À ce jour, nous ne pensons qu'à 2 _applications_ qui devraient en avoir besoin : le site de EtuUTT, et son application.
79+
```
80+
81+
## Tables
82+
83+
Faisons un tour d'horizon des tables :
84+
- `ApiApplication` : représente une _application_.
85+
- `ApiKey` : représente une _clé API_. L'`ApiKey` contient un token, qui sera signé pour créer le _Bearer token_.
86+
- `User` : représente un utilisateur (rien de particulier à signaler ici, la table ressemble à ce dont vous pouvez vous attendre d'une table utilisateur)
87+
- `ApiKeyPermission` : Une _permission_ spécifique donnée à une certaine _clé API_. Cette _permission_ peut soit être _soft granted_ soit être _hard granted_.
88+
- `ApiGrantedPermission` : Cette table contient les permissions données par les utilisateurs aux différentes clé API.
89+
- `Permission` : une _enum_ listant l'entièreté des _permissions_ prises en charge par l'API. Les _API permissions_ commencent par `API_`, et les _user permissions_ commencent par `USER_`.
90+
91+
## Authentification des requêtes
92+
93+
On va traiter l'authentification des requêtes avant la connexion, le _flow_ me paraît plus logique dans ce sens là 🙂
94+
95+
Pour authentifier les requêtes, on utilise un _bearer token_ (token JWT), passé dans le _header_ `Authorization`, sous le format `Bearer {token}`. Quand on décode le token, on obtient un objet contenant un champ `token`. Ce champ permet de trouver une `ApiKey` unique. À partir de cette `ApiKey`, il est ainsi possible d'obtenir l'utilisateur authentifié, et les routes ou informations auxquelles l'utilisateur a le droit d'accéder.
96+
97+
## Connexion
98+
99+
On fera la différence entre un utilisateur et une _application_. Cependant, un utilisateur utilisateur qui se connecte n'est rien d'autre que l'_application_ du site web de EtuUTT qui essaie de se connecter en tant que cet utilisateur. La différence entre ces deux méthodes n'est donc pas le résultat final : les tokens que l'on obtient sont de même nature. La différence est dans la façon de les obtenir.
100+
101+
On va aussi faire la différence entre une connexion "utilisateur" au site de EtuUTT et une connexion "utilisateur" à une autre _application_.
102+
103+
La méthode de connexion "utilisateur" permettra de générer un _bearer token_ temporaire, avec une connexion classique (décentralisée ou nom d'utilisateur / mot de passe). C'est l'_application_ EtuUTT qui demandera à authentifier l'utilisateur, avec les informations fournies.
104+
105+
La méthode de connexion "application" permettra de générer un _bearer token_ avec une durée de vie possiblement infinie (en fonction de ce que veut l'utilisateur). C'est l'utilisateur connecté à l'_application_ EtuUTT qui demandera la génération d'un _bearer token_ pour notre _application_.
106+
107+
### Pour un utilisateur - connexion au site EtuUTT
108+
109+
Pour connecter un utilisateur au site EtuUTT, on passe par le CAS de l'UTT, avec la route `POST /auth/signin`, puis l'API nous renvoit un token pour authentifier nos requêtes, voir la partie (Authentification des requêtes)[#authentification-des-requetes]
110+
111+
### Pour un utilisateur - connexion à une autre _application_
112+
113+
Pour connecter un utilisateur à une autre _application_, cette application devra tout d'abord le rediriger vers `https://etu.utt.fr/auth/login?application=application_id`
114+
115+
L'utilisateur sera alors invité à se connecter. S'il n'a pas encore de _clé API_ pour cette application, il lui sera demandé s'il veut réellement en créer une.
116+
117+
L'utilisateur sera ensuite redirigé vers l'URL de redirection de l'_application_, avec un paramètre GET `token`. Ce token devra être envoyé à l'API sur la route `POST /auth/login/validate`, avec le client secret de l'_application_ pour confirmer la source de la requête. Cette route renvoie enfin un `bearer token`, qui peut être utilisé pour authentifier les requêtes.
118+
119+
### Pour une application
120+
121+
Pour une _application_, on génère un token pour la _clé API_ reliant l'_application_ et l'utilisateur à qui appartient cette _application_, puis on retourne le _bearer token_ associé. Il faut aussi bien sauvegarder la date de dernière mise à jour (`tokenUpdatedAt`), et utiliser cette date pour toujours retourner la même version du token (champ `iat` dans l'objet à encoder avec JWT).
122+
123+
L'utilisateur peut renouveler les token de ses `ApiKey`. Le token sera alors modifié, pour empêcher l'accès avec l'ancien token.
124+
125+
## Grant
126+
127+
### Soft grant
128+
129+
N'importe quelle application peut demander à un utilisateur de lui _soft grant_ une _permission_.
130+
131+
Pour permettre à un utilisateur de faire ce _soft grant_, l'_application_ doit rediriger l'utilisateur vers une route sur le front{sup}`route à déterminer`, en lui passant en paramètre l'id de l'_application_ et les _permissions_ nécessaires à _l'application_{sup}`noms des arguments à déterminer`.
132+
133+
L'utilisateur sera alors invité à se connecter, à accepter ou refuser les différentes _permissions_, et sera redirigé vers l'_application_{sup}`sur quelle url ?`, avec en paramètre les _permissions_ acceptées{sup}`format à déterminer`.

docs/doc_developers/api/scripts.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Scripts
2+
3+
Les scripts peuvent être trouvés dans le dossier `scripts`.
4+
5+
Voici les différents scripts que vous pouvez utiliser :
6+
7+
| Commande | Description |
8+
|-----------------------------|----------------------------------------------------------------------------------|
9+
| `pnpm script:deps:graph` | Construit un arbre de dépendance des différents modules |
10+
| `pnpm seed:base` | Seed la DB avec les semestres, les branches, filières, ... (environnement "dev") |
11+
| `pnpm seed:base:prod` | Seed la DB avec les UEs, les branches, filières, ... (environnement "prod") |
12+
| `pnpm seed:ue:aliases` | Seed la DB avec les alias d'UE (environnement "dev") |
13+
| `pnpm seed:ue:aliases:prod` | Seed la DB avec les alias d'UE (environnement "prod") |
14+
| `pnpm seed:ue` | Seed la DB avec les UEs (environnement "dev") |
15+
| `pnpm seed:ue:prod` | Seed la DB avec les UEs (environnement "prod") |
16+
17+
Il est aussi possible de seed la DB avec des données dummy avec le script `prisma/seed/seed.ts` : `pnpm db:seed`

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
"seed:ue:aliases": "env-cmd -f .env.dev -- ts-node scripts/seed/aliases.ts",
3333
"seed:base:prod": "node scripts/seed/base.js",
3434
"seed:ue:prod": "node scripts/seed/ue.js",
35-
"seed:ue:aliases:prod": "node scripts/seed/aliases.js"
35+
"seed:ue:aliases:prod": "node scripts/seed/aliases.js",
36+
"script:deps:graph": "ts-node scripts/dependency_graph.ts"
3637
},
3738
"dependencies": {
3839
"@fast-csv/parse": "^5.0.0",
@@ -85,6 +86,7 @@
8586
"jest": "29.5.0",
8687
"ldap-server-mock": "^6.0.1",
8788
"mysql": "^2.18.1",
89+
"nestjs-spelunker": "^1.3.2",
8890
"nock": "^13.5.4",
8991
"pactum": "^3.7.0",
9092
"prettier": "^2.8.8",

0 commit comments

Comments
 (0)