From 97f73c68caf039d549df859cefaec12b6320522a Mon Sep 17 00:00:00 2001 From: hawkspar <quentin.chevalier@polytechnique.edu> Date: Sat, 2 Mar 2019 19:27:10 +0100 Subject: [PATCH] split add & rem into subfunctions --- src/ldap/internal/basics.ts | 8 +- src/ldap/internal/config.ts | 5 - src/ldap/internal/tools.ts | 256 +++++++++++++++++++++--------------- 3 files changed, 157 insertions(+), 112 deletions(-) diff --git a/src/ldap/internal/basics.ts b/src/ldap/internal/basics.ts index c738443..089d74b 100644 --- a/src/ldap/internal/basics.ts +++ b/src/ldap/internal/basics.ts @@ -255,4 +255,10 @@ export class Basics { }); return true; } -} \ No newline at end of file +} + +// Bind +Basics.unbind(); +Basics.adminBind(); + +console.log("Binding with LDAP client completed successfully, looking good !"); \ No newline at end of file diff --git a/src/ldap/internal/config.ts b/src/ldap/internal/config.ts index 14a3d4f..3b00495 100644 --- a/src/ldap/internal/config.ts +++ b/src/ldap/internal/config.ts @@ -13,7 +13,6 @@ import fs from 'fs'; import path from 'path'; import colors from 'colors'; import dotenv from 'dotenv'; -import { Basics } from './basics'; // Chargement de l'environnement let path_env = path.resolve(__dirname, '..', '..', '..', './.env'); @@ -37,10 +36,6 @@ let path_credentials = path.resolve(__dirname, '..', '..', '..', 'ldap_credentia console.log(colors.green("Loading LDAP credentials from "+path_credentials)); export const credentialsLdapConfig = JSON.parse(fs.readFileSync(path_credentials).toString()); -// Bind -Basics.unbind(); -Basics.adminBind(); - // Data formats and useful constants export const categories = ["admins","speakers","members","followers"]; diff --git a/src/ldap/internal/tools.ts b/src/ldap/internal/tools.ts index 967523d..cb5b6b6 100644 --- a/src/ldap/internal/tools.ts +++ b/src/ldap/internal/tools.ts @@ -157,14 +157,16 @@ export class Tools { * @async * @static */ - static async addIfNotPresent(id1: string, domain1: "group"|"user", id2: string, domain2: "group"|"user", category: string): Promise<boolean> { + static async addIfAbsent(id1: string, domain1: "group"|"user", id2: string, domain2: "group"|"user", category: string): Promise<boolean> { try { // Vérifie que l'utilisateur est pas déjà membre pour groupes let l = await Tools.get(id1, domain1, category); - var catName = ldapConfig[domain2][category]; + var catName = ldapConfig[domain1][category]; if (!l.includes(id2)) { // Ajoute l'utilisateur dans la catégorie concernée - if (!await Basics.change(domain2, id2, "add", catName)) throw "Erreur lors de la modification dans l'arbre "+domain2+" pour ajouter une entrée dans la catégorie voulue."; + if (domain2 == "group") var id = ldapConfig[domain2].gid; + else var id = ldapConfig[domain2].uid; + if (!await Basics.change(domain1, id1, "add", {catName: id+"="+id2+","+ldapConfig.dn[domain2]})) throw "Erreur lors de la modification dans l'arbre "+domain2+" pour ajouter une entrée dans la catégorie voulue."; } } catch(err) { throw "Erreur pour obtenir une liste d'entrées d'une catégorie d'un "+domain1+"."; } @@ -183,16 +185,16 @@ export class Tools { * @async * @static */ - static async manageInclusions(uid: string, gid: string, category: string): Promise<boolean> { - var adm = ldapConfig.group.admins; + static async addIncluded(uid: string, gid: string, category: string): Promise<boolean> { var spk = ldapConfig.group.speakers; + var mem = ldapConfig.group.members; switch (category) { case "admins": // Admin => speaker - if (!Basics.change("user", uid, "add", { spk: ldapConfig.group.gid+"="+gid+","+ldapConfig.dn.group })) throw "Erreur à l'ajout d'un nouvel admin parmi les portes-paroles d'un groupe"; + if (!await Basics.change("user", uid, "add", { spk: ldapConfig.group.gid+"="+gid+","+ldapConfig.dn.group })) throw "Erreur à l'ajout d'un nouvel admin parmi les portes-paroles d'un groupe"; case "speakers": // Speaker & admin => member - if (!Basics.change("user", uid, "add", { mem: ldapConfig.group.gid+"="+gid+","+ldapConfig.dn.group })) throw "Erreur à l'ajout d'un nouvel admin ou porte-parole parmi les membres d'un groupe"; + if (!await Basics.change("user", uid, "add", { mem: ldapConfig.group.gid+"="+gid+","+ldapConfig.dn.group })) throw "Erreur à l'ajout d'un nouvel admin ou porte-parole parmi les membres d'un groupe"; case "members": case "followers": break; @@ -212,7 +214,7 @@ export class Tools { * @async * @static */ - static async DFS(uid: string, gid: string, direction: boolean): Promise<boolean> { + static async addDFS(uid: string, gid: string, direction: boolean): Promise<boolean> { // Cas récursif ascendant (admins) if (direction) { var rol = ldapConfig.group.admins; @@ -247,130 +249,172 @@ export class Tools { */ static async add(uid: string, gid: string, category: string): Promise<boolean> { // Gestion naïve - Tools.addIfNotPresent(uid, "user", gid, "group", category); - Tools.addIfNotPresent(gid, "group", uid, "user", category); + Tools.addIfAbsent(uid, "user", gid, "group", category); + Tools.addIfAbsent(gid, "group", uid, "user", category); // Gestion des droits par inclusion - Tools.manageInclusions(uid, gid, category); + Tools.addIncluded(uid, gid, category); // Gestion des droits récursive - if (category != "followers") Tools.DFS(uid, gid, false); - if (category == "admins") Tools.DFS(uid, gid, true); + if (category != "followers") Tools.addDFS(uid, gid, false); + if (category == "admins") Tools.addDFS(uid, gid, true); return true; } - + /** * @memberof LDAP - * @summary Fonction qui permet de supprimer un membre d'une catégorie existant d'un groupe. - * @desc Cette fonction fait essentiellement appel à d'autres fonctions de {@link Tools} passées en argument et {@link LDAP.change}. - * Elle essaie d'assurer les propriétés d'inclusion et de récursion du LDAP. Elle est sans effet pour un statut hérité. - * @arg {string} uid - Identifiant de l'ex-membre - * @arg {string} gid - Identifiant du groupe + * @summary Fonction intermédiaire naïve. + * @desc Cette fonction enlève un utilisateur d'un groupe pour un des deux arbres si cette entrée n'était pas déjà absente. + * Elle ne donne pas de précédence particulière à un administrateur strict, ou de protection à une administrateur hérité. + * @arg {string} id1 - uid/gid + * @arg {"group"|"user"} domain1 - Arbre concerné pour l'id1 + * @arg {string} id2 - gid/uid + * @arg {"group"|"user"} domain2 - Arbre concerné pour l'id2 * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower) * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async * @static */ - static async remove(uid: string, gid: string, category : string): Promise<boolean> { + static async remIfPresent(id1: string, domain1: "group"|"user", id2: string, domain2: "group"|"user", category: string): Promise<boolean> { try { - // Vérifie que l'utilisateur est pas déjà viré pour groupes - let lu = await Tools.get(gid, "group", category); - let catName = ldapConfig.group[category]; - // Statut strict - if (lu.includes(uid)) { - // Supprime tous les utilisateurs - if (!await Basics.change("group", gid, "del", catName)) throw "Erreur lors de la suppression de tous les membres d'une catégorie du groupe."; + let l = await Tools.get(id1, domain1, category); + var catName = ldapConfig[domain1][category]; + // Vérifie que l'identifiant est bien présent + if (l.includes(id2)) { + // Supprime tous les identifiants + if (!await Basics.change(domain1, id1, "del", catName)) throw "Erreur lors de la suppression de tous les "+category+" de l'identifiant "+id1+"."; // Les rajoute un par un, sauf pour le supprimé - lu.forEach(id => { - if (id!=uid) { - Tools.add(id, gid, category).then(res => { - if (!res) throw "Erreur lors du ré-ajout d'un autre membre d'une catégorie."; + l.forEach(id => { + if (id!=id2) { + if (domain2 == "group") var id_n = ldapConfig[domain2].gid; + else var id_n = ldapConfig[domain2].uid; + var catName = ldapConfig[domain1][category]; + Basics.change(domain1, id1, "add", {catName: id_n+'='+id+','+ldapConfig[domain2].dn}).then(res => { + if (!res) throw "Erreur lors du ré-ajout d'un autre "+domain1+" de la catégorie "+category+"."; }); } }); } - // Si hérité, appel sans effet - else return true; - } - catch(err) { - throw "Erreur pour obtenir une liste de membres d'une catégorie d'un groupe pour supprimer un membre de cette categorie du groupe."; } - try { - // Vérifie que l'utilisateur est pas déjà viré pour user - let lg = await Tools.get(uid, "user", category); - let catName = ldapConfig.user[category]; - if (lg.includes(gid)) { - // Supprime tous les groupes de la catégorie pour l'utilisateur - if (!await Basics.change("user", uid, "del", catName)) throw "Erreur lors de la suppression de tous les groupes d'un membre."; + catch(err) { throw "Erreur pour obtenir une liste d'entrées d'une catégorie d'un "+domain1+"."; } + return true; + } + + /** + * @memberof LDAP + * @summary Fonction intermédiaire. + * @desc Cette fonction gère les inclusions de droits. Elle ne rajoute pas un admin pour les admins, mais elle le rajoute en tant que speaker. + * Cette fonction agit uniquement sur l'arbre User. + * @arg {string} uid - uid de l'utilisateur à ajouter + * @arg {string} gid - gid du groupe concerné + * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower) + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon + * @async + * @static + */ + static async remIncluded(uid: string, gid: string, category: string): Promise<boolean> { + var spk = ldapConfig.group.speakers; + var mem = ldapConfig.group.members; + switch (category) { + case "admins": + // Admin => speaker + let l = await Tools.get(gid, "group", spk); + // Supprime tous les identifiants + if (!await Basics.change("group", gid, "del", spk)) throw "Erreur lors de la suppression de tous les portes-paroles de l'identifiant "+gid+"."; + // Les rajoute un par un, sauf pour le supprimé + l.forEach(id => { + if (id!=uid) { + let tmp = ldapConfig.user.uid; + Basics.change("group", gid, "add", {spk: tmp+'='+uid+','+ldapConfig.user.dn}).then(res => { + if (!res) throw "Erreur lors du ré-ajout d'un autre membre de la catégorie porte-parole."; + }); + } + }); + case "speakers": + // Speaker & admin => member + let lm = await Tools.get(gid, "group", mem); + // Supprime tous les identifiants + if (!await Basics.change("group", gid, "del", mem)) throw "Erreur lors de la suppression de tous les portes-paroles de l'identifiant "+gid+"."; // Les rajoute un par un, sauf pour le supprimé - lg.forEach(id => { - if (id!=gid) { - Tools.add(uid, id, category).then(res => { - if (!res) throw "Erreur lors du ré-ajout d'un autre groupe."; + l.forEach(id => { + if (id!=uid) { + let tmp = ldapConfig.user.uid; + Basics.change("group", gid, "add", {mem: tmp+'='+uid+','+ldapConfig.user.dn}).then(res => { + if (!res) throw "Erreur lors du ré-ajout d'un autre membre de la catégorie membre."; }); } }); - } + case "members": + case "followers": + break; } - catch(err) { - throw "Erreur pour obtenir une liste de groupes d'une categorie d'un membre pour supprimer un groupe de cette category pour le membre."; + return true; + } + + /** + * @memberof LDAP + * @summary Fonction intermédiaire de récursion. + * @desc Cette fonction gère les droits par récursion par une classique Depth First Search. + * Cette fonction agit uniquement sur l'arbre User. TBM + * @arg {string} uid - uid de l'utilisateur à ajouter + * @arg {string} gid - gid du groupe concerné + * @arg {boolean} direction - direction de la recursion + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon + * @async + * @static + */ + static async remDFS(uid: string, gid: string, direction: boolean): Promise<boolean> { + // Cas récursif ascendant (admins) + if (direction) { + var rol = ldapConfig.group.admins; + var tov = ldapConfig.group.childs; } - - // Partie interne à l'X non propre à Sigma - // Seule catégorie non récursive - if (category != "followers") { - if (category in ["admins", "members"]) { - // Cas récursif descendant - let to_visit = [gid]; - let adm = ldapConfig.group.admins; - while (to_visit.length > 0) { - let cur_gid = to_visit.pop(); - // Si uid était un admin hérité - if (!(uid in await Tools.get(cur_gid, "group", "admins"))) { - let lg = await Tools.get(uid, "user", "admins"); - if (!await Basics.change("user", uid, "del", adm)) { - throw "Erreur lors de la suppression de tous les groupes d'un membre spé X."; - } - // Les rajoute un par un, sauf pour le supprimé - lg.forEach(id => { - if (id!=gid) Tools.add(uid, id, "admins").then(res => { - if (!res) throw "Erreur lors du ré-ajout d'un autre groupe spé X."; - }); - }); - to_visit.concat(await Basics.searchSingle("group", ldapConfig.group.childs, cur_gid)); - } - } - } - // Très violent ; virer un membre c'est aussi le virer de ses postes de porte-parole, d'admin et de groupes hérités - if (category == "members") { - let spk = ldapConfig.group.speakers; - let lg = await Tools.get(uid, "user", "speakers"); - if (!await Basics.change("user", uid, "del", spk)) throw "Erreur lors de la suppression de tous les groupes d'un membre spé X."; - // Les rajoute un par un, sauf pour le supprimé - lg.forEach(id => { - if (id!=gid) Tools.add(uid, id, "speakers").then(res => { - if (!res) throw "Erreur lors du ré-ajout d'un autre groupe spé X."; + // Cas récursif descendant (membres) + else { + var rol = ldapConfig.group.members; + var tov = ldapConfig.group.parents; + } + // Classic DFS + var to_visit = [gid]; + while (to_visit.length > 0) { + let cur_gid = to_visit.pop(); + let l = await Tools.get(gid, "group", rol); + // Supprime tous les identifiants + if (!await Basics.change("group", gid, "del", rol)) throw "Erreur lors de la suppression de tous les "+rol+" de l'identifiant "+gid+"."; + // Les rajoute un par un, sauf pour le supprimé + l.forEach(id => { + if (id!=uid) { + let tmp = ldapConfig.user.uid; + Basics.change("group", gid, "add", {rol: tmp+'='+uid+','+ldapConfig.user.dn}).then(res => { + if (!res) throw "Erreur lors du ré-ajout d'un autre membre de la catégorie "+rol+"."; }); - }); - // Cas récursif montant - let to_visit = [gid]; - let mem = ldapConfig.group.members; - while (to_visit.length > 0) { - let cur_gid = to_visit.pop(); - // Si uid était un membre hérité - if (!(uid in await Tools.get(cur_gid, "group", "admins")) - && !(uid in await Tools.get(cur_gid, "group", "speakers")) - && !(uid in await Tools.get(cur_gid, "group", "members"))) { - let lg = await Tools.get(uid, "user", "members"); - if (!await Basics.change("user", uid, "del", mem)) throw "Erreur lors de la suppression de tous les groupes d'un membre spé X."; - // Les rajoute un par un, sauf pour le supprimé - lg.forEach(id => { - if (id!=gid) Tools.add(uid, id, "admins").then(res => { - if (!res) throw "Erreur lors du ré-ajout d'un autre groupe spé X."; - }); - }); - to_visit.concat(await Basics.searchSingle("group", ldapConfig.group.parents, cur_gid)); - } } - } + }); + to_visit.concat(await Basics.searchSingle("group", tov, cur_gid)); + } + return true; + } + + /** + * @memberof LDAP + * @summary Fonction qui permet de supprimer un membre d'une catégorie existant d'un groupe. + * @desc Cette fonction fait essentiellement appel à d'autres fonctions de {@link Tools} passées en argument et {@link LDAP.change}. + * Elle essaie d'assurer les propriétés d'inclusion et de récursion du LDAP. Elle est sans effet pour un statut hérité. + * @arg {string} uid - Identifiant de l'ex-membre + * @arg {string} gid - Identifiant du groupe + * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower) + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon + * @async + * @static + */ + static async remove(uid: string, gid: string, category : string): Promise<boolean> { + // Invulnérabilité pour les admins hérités + if ((await Tools.get(gid, "group", category)).includes(uid)) { + Tools.remIfPresent(uid, "user", gid, "group", category); + Tools.remIfPresent(gid, "group", uid, "user", category); + // Gestion des droits par inclusion + Tools.remIncluded(uid, gid, category); + // Gestion des droits récursive + if (category != "followers") Tools.remDFS(uid, gid, false); + if (category == "admins") Tools.remDFS(uid, gid, true); } return true; } -- GitLab