Proof Of Concept pour gestion des droits Sigma
Une implémentation la plus simple possible illustrant la gestion des droits de Sigma.
Elle illustre le framework d'autorisation décrit ici : https://gitlab.binets.fr/guillaume.wang/gestion-des-droits-sigma/. Elle lui sert autant de POC que de terrain d'expérimentation.
Le "vrai" projet Sigma
Ce dépôt est, à l'origine, un exemple extrêmement simplifié de backend pour Sigma, le successeur de Frankiz, un site étudiant permettant de gérer les groupes et les étudiants du plateau de Saclay. Le "vrai" projet se trouve ici : https://gitlab.binets.fr/br/sigma-backend
De la même façon que ce dernier, gdd-sigma-poc est destiné à servir d'API à un frontend au code entièrement séparé. Le dépôt pour le "vrai" serveur front se trouve ici : https://gitlab.binets.fr/br/sigma-frontend (on l'appellera indifféremment serveur front, front ou frontend...)
Simplifications
Contrairement au vrai projet, pour plus de concision et de simplicité,
- on simplifie la documentation, en particulier on suppose que le lecteur/reviewer connaît déjà un peu les outils utilisés (npm, nodejs, expressjs, webpack, knex...)
- on met toutes les données dans une BDD PostgreSQL, i.e. on ignore la contrainte du vrai Sigma de synchronisation avec un LDAP
- on n'implémente pas les métagroupes
- on n'implémente qu'un seul type de message
Les deux derniers points pourront éventuellement être inclus plus tard.
Documentation
Description formelle du framework de gestion des droits
Voir https://gitlab.binets.fr/guillaume.wang/gestion-des-droits-sigma/.
Mémos sur l'implémentation
Contrairement au vrai projet, les mémos ne sont pas intégrés à JSDoc, il faut les lire directement en tant que fichiers markdown. On peut les trouver ici (TODO)
Mémos des développeurs
Code JS : JSDoc
Les lignes qui suivent sont adaptées du README du vrai sigma-backend, au moment du fork. Elles ont pour but de permettre au lecteur de rapidement mettre en place et lancer un sigma-poc en local.
Installer les dépendances npm
On utilise un serveur node.js avec express.js. Ce serveur est configuré dans app.ts
puis lancé sur le port 3000 dans index.ts
.
Les dépendances npm s'installent avec npm install
. Cette commande a deux comportements possibles selon la valeur de la variable NODE_ENV
(vérifier avec la commande echo "$NODE_ENV"
):
- si
NODE_ENV
n'est pas configuré : on installe tout - si
NODE_ENV
==development
: on installe tout - si
NODE_ENV
==production
: on n'installe pas les dépendances développeur
Les dépendances principales utilisées sont :
- knex.js, qui permet de construire des requêtes SQL facilement,
- GraphQL, qui fournit une couche d'abstraction pour l'échange de données frontend-backend,
- ldap.js, qui permet d'interroger un serveur LDAP,
-
webpack, qui compile et optimise tout le code source javascript en un
bundle.js
, - ESLint et TSLint, pour le développement, outils de vérification syntaxique.
Et une dépendance non-npm, PostgreSQL (linux debian est supposé) :
sudo apt install postgresql
Configuration
L'API est conçue pour fonctionner dans plusieurs environnements. On peut donc la configurer via des fichiers ou des variables d'environnement. En deux mots :
-
jsdoc_config.json
,Dockerfile
,.dockerignore
,.gitignore
,.eslintignore
,webpack.config.js
: transparents -
ldap_config.json
: noms champs du LDAP -
.estlintrc.json
: ESLINT ou à quel point cancériser le développeur (outil qui enforce les "good practices" de code) -
.gitattributes
: terminaison de fichiers -
.gitlab-ci.yml
: pipeline gitlab -
package.json
etpackage-lock.json
: gestion des dépendances usuel -
tsconfig.json
: configure la compilation de fichiers Typescript en Javascript -
tslint.json
: configure tslint, utilisé plutôt que tsc dans le projet final -
.env
: définit les variables d'environnement et ports utilisés...
Certains de ces fichiers de configurations ont une version "distribution" en "_dist" qui permet de les partager (le reste du temps ils sont dans le .gitignore), quitte à les renommer et à les modifier en local.
Par exemple le .env_dist
permet d'avoir sur le git une version du document sans les mots de passe, mais permet à chaque dév d'avoir les mots de passe dans les variables d'environnement.
Configuration LDAP
L'API de Sigma nécessite de se connecter au LDAP Frankiz, à la fois pour obtenir des données et pour l'authentification des utilisateurs. Cela est fait à l'aide de la librairie ldapjs pour faire les requêtes au LDAP et passportJS pour l'authentification.
- La configuration LDAP de base se situe dans ldap_config.json.
- Les identifiants utilisés pour authentifier le serveur au LDAP sont dans .env. Ils prennent la forme suivante:
LDAP_DN=uid=sigma,ou=services,dc=frankiz,dc=net
LDAP_PASSWD=MDP
- Elle est importée dans l'application depuis src/ldap/internal/config.ts.
- Si la variable d'environnement
LDAP_URI
est définie, l'adresse où trouver le LDAP est remplacée.
Le LDAP de Frankiz est sous OpenLDAP, qui a l'avantage d'être largement utilisée, documentée sur Internet, compatible avec des lecteurs génériques comme JXplorer et gérant ses propres logs (voir ce blog).
Exemple
Si on développe en dehors du plâtal et qu'on ouvre un proxy SSH avec port forwarding du LDAP (ldap.eleves.polytechnique.fr:389) vers localhost:8389, on s'y connecte en définissant : LDAP_URI=ldap://localhost:8389
, soit en faisant export LDAP_URI=...
, soit en écrivant un fichier .env
. Le fichier config.ts
s'occupe du reste.
Variables d'environnement
Variable | Description | Défaut |
---|---|---|
NODE_ENV | Type de l'environnement pour node : development ou production
|
development |
TARGET_ENV | Config choisie pour la BDD et le LDAP : development , staging ou production
|
.env |
HOST | Adresse sur laquelle le serveur écoute des requêtes. | index.ts |
PORT | Port sur lequel le serveur écoute | .env |
FRONTEND_SERVER_URL | Adresse du frontend pour autoriser les CORS | .env |
LDAP_URI | URI vers le serveur LDAP. | ldap_config.json |
DB_HOST | Addresse de la base de données. | knexfile.js |
DB_USER | Utilisateur de la BDD | knexfile.js |
DB_PASSWD | Mot de passe de la BDD | knexfile.js |
DB_DATABASE | Base sur laquelle se connecter | knexfile.js |
Certaines variables doivent être définies dans un fichier .env
. On peut se contenter de recopier .env_dist avec cp .env_dist .env
.
Par ailleurs, on peut définir ces variables d'environnement, dans l'ordre décroissant de priorité :
- dans sa session de terminal (équivalent à
docker run -e KEY=value
) :export KEY=value
- au moment de lancer l'application (cela écrase la valeur dans la session, mais seulement pour cette commande) :
KEY=value npm start
- dans un fichier
.env
(plus faible niveau, n'écrase jamais une valeur déja existante) :KEY1=value1 KEY2=value2 ...
Setup de la BDD PostgreSQL
La BDD PostgreSQL est utilisée pour stocker permissions, écoles des utilisateurs, annonces et événements.
Créer un rôle PostgreSQL "sigma" :
sudo -u postgres -s
createuser sigma --login --createdb --pwprompt
# penser à répercuter le mot de passe choisi dans `.env`
Créer une base de données PostgreSQL "sigma_dev" :
createdb sigma_dev --username sigma --password --encoding UTF8
- Si vous n'arrivez pas à vous connecter (
createdb: could not connect to database template1: FATAL: Peer authentication failed for user
) : mettre à jour votre fichierpg_hba.conf
.-
sudo nano /etc/postgresql/<version>/main/pg_hba.conf
(en tant qu'utilisateur normal) - remplacer tous les
peer
parmd5
- redémarrer le serveur postgres :
sudo /etc/init.d/postgresql restart
-
- Si vous souhaitez utiliser d'autres noms que "sigma" et "sigma_dev" : ça ne pose pas de problème, il vous faudra simplement modifier .env.
- Sortir de l'utilisateur
postgres
avec CTRL + d
Exécuter les migrations et les seeds de knex :
# construire le schéma de la BDD, i.e. définir les tables et leur structure.
npm run migrate
# insérer des données de test dans la BDD
npm run seed
Voilà, vous avez une base de données à jour !
Démarrer le serveur
Dire à webpack de build le projet (build le bundle ../build/bundle.js
) :
npm run dev # en mode developpement
# ou
npm run build # en mode production
Lancer un serveur express/node :
npm run start # ou le raccourci: npm start
Comme indiqué dans src/index.js, ceci lance un serveur servant l'application express sur le port 3000.
Mode développement / staging / production
Deux variables d'environnement gerent le mode de déploiement de l'application : NODE_ENV
et TARGET_ENV
.
-
NODE_ENV
détermine dans quel mode sont configurés node et tous ses modules : en particulier, des queNODE_ENV === production
, de nombreux modules mettent en place des optimisations et lesdevDependencies
ne sont plus installés... Par convention,NODE_ENV
ne doit prendre que les valeursdevelopment
ouproduction
. -
TARGET_ENV
est une variable custom qui détermine dans notre code quelles configurations doivent etre chargées, en particulier en ce qui concerne le LDAP et la BDD.TARGET_ENV
peut prendre les trois valeursdevelopment
,staging
etproduction
.
Voici plus en détail les 3 contextes différents de déploiement :
- mode "développement" (quand on compile et fait tourner le serveur en local) :
- installer toutes les dépendances avec
npm i
- configurer l'environnement :
.env
avecTARGET_ENV=development
etLDAP_PASSWD="XXX"
avec XXX mot de passe obtenu des dévs précédents - setup la BDD
sigma_dev
et la populer avecnpm run migrate && npm run seed
- compiler le serveur :
npm run watch
- démarrer Nodemon :
npm run start
- installer toutes les dépendances avec
- mode "staging" (quand on lance l'application en mode dev sur un serveur pour des tests) :
- installer toutes les dépendances avec
npm i && npm i -g knex
(on a besoin de tout pour pouvoir compiler) - configurer l'environnement :
.env
avecTARGET_ENV=staging
etLDAP_PASSWD="XXX"
avec XXX mot de passe obtenu des dévs précédents - setup la BDD
sigma_staging
et la populer avecknex migrate:latest --env staging
- compiler le serveur en mode production :
npm run build
- démarrer le serveur :
npm run start_prod
- installer toutes les dépendances avec
- mode "production" (quand on lance l'application précompilée en
bundle.js
en prod) :-
définir NODE_ENV :
export NODE_ENV=production
dans la session terminal - installer seul les dépendances prod :
npm i
(les devDependencies ne sont plus installées) - configurer l'environnement :
.env
avecTARGET_ENV=production
etLDAP_PASSWD="XXX"
avec XXX mot de passe obtenu des dévs précédents - setup la BDD
sigma_prod
et la populer avecnpm run migrate
- lancer le serveur précompilé :
npm run start_prod
-
définir NODE_ENV :
Scripts
Les scripts sont des instructions en ligne de commande que l'on peut faire tourner avec la commande npm run
. Ce sont des raccourcis pour gagner du temps sur des opérations un peu longues. Ils sont définis dans package.json
.
npm run start
démarre le serveur buildé build/bundle.js
avec nodemon, un outil de dév qui le redémarre automatiquement après toute modification du bundle.
Donc, lancer npm run watch
dans un terminal et npm run start
dans un autre permet de rebuilder et relancer automatiquement le serveur, après toute modification du code source.
Panneau d'administration
Il est accessible par navigateur au path /adminview/admin ; n'importe quel path devrait rediriger dessus.
L'accès y est protégé par une page d'authentification, les identifiants à utiliser sont ceux de Frankiz. Le hruid (i.e. prenom.nom) de l'utilisateur doit de plus être sur une whitelist des hruid autorisés. Pour l'instant cette whitelist est configurée dans les variables d'environnement .env.
Ce panneau doit prendre de plus en plus d'importance au fur et à mesure que la base Sigma s'enrichit, et que l'on veut faire de plus en plus de choses avec des permissions de plus en plus fines.
Accès direct à la BDD
Le panneau d'administration sert (ou plutôt, servira à terme) à accéder directement à la BDD propre de sigma, grâce à une API REST. Autrement dit :
- on accède à la table
table_name
par une requête GET à adminview/db/table_name, - et aux colonnes
columns
de cette table par une requête GET à /adminview/db/table_name?columns=columns.
GraphQL Voyager
L'application Voyager, accessible à /adminview/voyager, permet de visualiser le « graphe » sous-jacent à la structure de l'API.
GraphQL Playground
== Attention, comme tout GraphQL Playground est géré directement par le package apollo-server-express, les requêtes dans le Playground ne sont pas soumises au mêmes règles de permission que dans adminview. (D'ailleurs, /graphql
n'est même pas un sous-path de /adminview
.) ==
Accéder via un navigateur à /graphql
renvoie l'application GraphQL Playground.
Il s'agit du même /graphql
que l'endpoint de l'API, mais le serveur est configuré de sorte à renvoyer Playground lorsqu'il détecte un accès via navigateur. Les requêtes dans le Playground sont cependant soumises au mêmes permissions que dans l'API GraphQL. GraphQL Playground est désactivé en production.
Tests
Sigma possède une suite de tests unitaires, déstinés à tester les resolvers graphql.
Pour executer les tests, il suffit d'utiliser la commande npm test
.
Les tests effectués sont tous les fichiers en *.test.ts
, actuellement resolvers.test.ts et ldap.test.ts. Les différentes requetes testées sont stockées sous forme de liste dans différents fichiers dans data/. Chaque élément contient une requête graphql, et les données qu'elle doit renvoyer. Quand les seed sont modifiées, il faudra modifier les resultats attendus également. Les tests peuvent être créés ou mis à jour en entrant la requête dans graphiql, et en copiant le resultat.
Documentation
La documentation détaillée du projet se trouve ici (fichier ./doc/index.html
).
Elle doit être préalablement compilée avec JSDoc, selon le fichier de config idoine (fichier ./jsdoc_config.json
à la racine du projet).
Le script pour faire tourner JSDoc et (ré)générer la documentation est : npm run doc
.
Les fichiers compilés se situent dans ./doc/
avec leurs fichiers image. Par nature de l'outil JSDoc il est facile de documenter en détail des fonctions .js mais plus compliqué de documenter un fichier.
A chaque execution JSDoc rajoute les commentaires placés dans chacun des fichiers dans la doc de façon structurée. Les notes en Markdown placés dans notes/ sont également rajoutées en tant que tutoriels (voir {@tutorial CONTRIBUTING}).