/** * @file Ce fichier contient la classe de l'API du LDAP qui gère les opérations sur les groupes. Elle est destinée à être exportée pour être utilisée par les resolvers. * @author hawkspar */ import { ldapConfig, userData, categories } from '../internal/config'; import {Basics} from '../internal/basics'; import {Tools} from '../internal/tools'; import ldapEscape from 'ldap-escape'; //------------------------------------------------------------------------------------------------------------------------ // Classes à exporter TBT //------------------------------------------------------------------------------------------------------------------------ export {userData}; export class User { /** * @memberof LDAP * @class User * @classdesc Cette classe est une des deux classes exportables permettant de faire des opérations sur les utilisateurs. * @summary Constructeur vide. */ constructor() {} /** * @memberof LDAP * @summary Fonction qui renvoit les infos de base relatives à un utilisateur particulier. * @desc Cette fonction utilise {@link Tools.peek} avec l'interface {@link userData}. * @arg {string} uid - Identifiant de l'utilisateur, supposé valide. * @return {Promise(userData)} Informations recueillies au format {@link userData}. * @static * @async */ static async peek(uid: string) : Promise<userData> { try { let data : userData = await Tools.peek<userData>("user", uid, userData); // Reconstruction des groupes dont un utilisateur est membre for (let cat of categories) { let dn = ldapConfig.user.uid + "=" + ldapEscape.filter("${txt}", { txt: uid }) + "," + ldapConfig.dn.user; data[cat] = await Basics.searchSingle("group", ldapConfig.group.gid, null, ldapConfig.group[cat] + "=" + dn); } return data; } catch(err) { throw "Error while peeking a user."; } } /** * @memberof LDAP * @summary Fonction qui retrouve les uid des paxs validant les critères de recherche. Utiliser {@link User.peek} au cas par cas après pour obtenir les vraies infos. * @desc Cette fonction utilise {@link Tools.search}. * @arg {userData} data - Dictionnaire contenant les données nécessaires à la recherche. Les valeurs sont celles entrées par l'utilisateur et sont par hypothèse * comme des sous-parties compactes des valeurs renvoyées. Tous les champs ci-dessous peuvent être indifféremment des listes (par exemple pour chercher un membre * de plusieurs groupes) ou des éléments isolés. Si un champ n'est pas pertinent, le mettre à '' ou undefined. * @return {Promise(string[])} gids des profils qui "match" les critères proposés. * @static * @async */ static async search(data: userData) : Promise<string[]> { try { return Tools.search("user", data); } catch(err) { throw "Erreur lors de la recherche approximative d'un utilisateur."; } } /** * @memberof LDAP * @summary Fonction qui créé un nouvel utilisateur dans le LDAP. * @desc Appelle {@link LDAP.add} bien sûr, mais aussi {@link Tools.add} pour gérer les groupes du nouvel utilisateur. * @arg {userData} data - Dictionnaire des informations utilisateurs. Des erreurs peuvent apparaître si tous les champs ne sont pas remplis. * Cette application permet de rejoindre des groupes en masse pour toute catégorie, à la fois façon Sigma et CAS. * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async * @static */ static async create(data: userData): Promise<boolean> { // Calcul d'un dictionnaire d'ajout let vals = {}; // uid de base généré à partir de nom et prénom, plus potentiellement promo et un offset // MEF mélange de Promise et de fonction standard try { Tools.generateUid("user",data['givenName'],data['lastName'],data['birthdate']).then(id => { vals[ldapConfig.user.uid]=id; } ); } catch(err) { throw "Erreur lors de la génération d'un hruid pour un nouvel utilisateur."; } let uid : string = vals[ldapConfig.user.uid]; // Génère une erreur si un champ n'est pas rempli for (let key_att of ["givenName","lastName","nickname","gender","photo","phone","adress","mail","birthdate","nationality"]) { // Ecriture de toutes les valeurs uniques if (data[key_att] != undefined) vals[ldapConfig.user[key_att]]=data[key_att]; } // Appel à la fonction de base if (!await Basics.add("user", vals)) throw "Erreur de l'ajout de la feuille à l'arbre utilisateur."; // Certains champs nécessitent de petits calculs let vals3={}; // ldapConfiguration du mot de passe utilisateur // Le préfixe {CRYPT} signifie que le mdp est hashé dans OpenLDAP voir : https://www.openldap.org/doc/admin24/security.html vals3[ldapConfig.user['password']] = "{CRYPT}"+data['password']; // Ecriture d'un surnom s'il y a lieu if ((data['nickname']!=undefined) && (data['nickname']!='')) vals3[ldapConfig.user['nickname']]=data['nickname']; try { // Génération id aléatoire unique vals3[ldapConfig.user['id']]= await Tools.generateId(ldapConfig.user['id'], "user"); } catch(err) { throw "Erreur lors de la génération d'un id numérique pour un nouvel utilisateur."; } // Code root vals3[ldapConfig.user['cleanFullName']]=data['fullName'].replace(':', ';').toLowerCase().normalize('UFD'); // Inscription des valeurs calculées if (!await Basics.change("user", uid, "add", vals3)) throw "Erreur lors de l'ajout des valeurs calculées à la feuille du nouvel utilisateur."; ["posixAccount", "shadowAccount", "brUser"].forEach(cst => { let val3={}; vals3[ldapConfig.user['class']]=cst; Basics.change("user", uid, "add", vals3).then(res => { if (!res) throw "Erreur lors de l'ajout d'une valeur constante à la feuille du nouvel utilisateur."; }); }); function DFS(uid, gid, cat) { let to_visit = [gid]; let tmp = ldapConfig.user[cat]; while (to_visit.length > 0) { let cur_gid = to_visit.pop(); Basics.change("user", uid, "add", { tmp: cur_gid}); if (cat == "admins") var rel = "childs"; to_visit.concat(Basics.searchSingle("group", ldapConfig.group[rel], cur_gid)); } } // Ajout dans les groupes à la catégorie voulue for (let cat of categories) { for (let gid of data[cat]) Tools.add(uid, gid, cat).then(res => { if (!res) throw "Erreur de l'ajout d'un membre au nouveau groupe."; }); } return true; } //------------------------------------------------------------------------------------------------------------------------ // Fonctions de suppression TBT //------------------------------------------------------------------------------------------------------------------------ /** * @memberof LDAP * @summary Fonction qui supprime un utilisateur du LDAP. * @desc Cette fonction commence par gérer les groupes du membre puis le supprime entièrement. * Appelle {@link LDAP.clear} bien sûr, mais aussi {@link Tools.remove} pour gérer les groupes de l'utilisateur sortant. * @arg {string} uid - uid de la victime * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async * @static */ static async delete(uid: string): Promise<boolean> { try { // Gestion des groupes d'abord let profil = await User.peek(uid); for (let cat of categories) { profil[ldapConfig.user[cat]].forEach(async function (gid: string) { // Enlever de la liste des membres let lm = await Tools.get(gid, "group", cat); if (lm.includes(uid)) { // Supprime tous les membres if (!await Basics.change("group", gid, "del", ldapConfig.group[cat])) { throw "Erreur lors de la suppression de tous les membres du groupe."; } // Les rajoute un par un, sauf pour le supprimé lm.forEach(id => { if (id!=uid) { Tools.add(id, gid, cat).then(res => { if (!res) throw "Erreur lors du ré-ajout d'un autre membre"; }); } }); } }); } } catch(err) { throw "Erreur lors de l'obtention des informations de l'utilisateur à supprimer."; } // Elimination if (!Basics.clear("user", uid)) throw "Erreur lors de la suppression de l'utilisateur."; return true; } /** * @memberof LDAP * @summary Fonction qui édite un utilisateur existant dans le LDAP. * @desc Appelle simplement {@link Tools.edit}. Sans effet sur les groupes de l'utilisateur concerné. * @arg {userData} data - Dictionnaire des informations utilisateurs * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async * @static */ static async edit(data : userData) : Promise<boolean> { try { return Tools.edit("user",data); } catch(err) { throw "Erreur lors de la modification d'un utilisateur."; } } }