Skip to content
Snippets Groups Projects
Commit 1d140c79 authored by Quentin CHEVALIER's avatar Quentin CHEVALIER
Browse files

Requêtes mieux foutues et stables, TOL en deux parties

parent 33e74925
No related branches found
No related tags found
No related merge requests found
{ {
"connexion": {
"dn": "uid=quentin.chevalier,ou=eleves,dc=frankiz,dc=net",
"passwd": "Ie42fds'eaJm1"
},
"ldap": { "ldap": {
"server": "ldap://frankiz.eleves.polytechnique.fr:389", "server": "ldap://frankiz.eleves.polytechnique.fr:389",
"searchBase": "ou=eleves,dc=frankiz,dc=net", "searchBase": "ou=eleves,dc=frankiz,dc=net",
"searchFilter": "(uid={{username}})" "searchFilter": "(uid={{username}})"
}, },
"ldap_data_gl": { "dn_groups":"ou=groups,dc=frankiz,dc=net",
"searchBase": "ou=groups,dc=frankiz,dc=net", "dn_users": "ou=eleves,dc=frankiz,dc=net",
"searchFilter":"(restrictedMemberUid=${id})" "filter_lm":"(brMemberOf=${id})",
}, "filter_al":"(brMemberOf=${id})",
"ldap_data_ml": { "filter_lg":"(restrictedMemberUid=${id})",
"searchBase": "ou=eleves,dc=frankiz,dc=net", "filter_st": "(uid=${id})",
"searchFilter": "(brMemberOf=${id})" "attributes_id": ["uid"],
}, "attributes_all": ["jpegPhoto","givenName", "sn", "brBirthdate", "brPromo","telephoneNumber","mail","brRoom","brIP"],
"ldap_data_tol": { "search_attributes_tol": ["givenName", "sn", "displayName", "country", "brMemberOf", "brPromo", "brMemberOf", "brMemberOf", "brMemberOf", "telephoneNumber","mail","brRoom","brIP"],
"searchBase": "ou=eleves,dc=frankiz,dc=net",
"searchFilterAttributes": ["givenName", "sn", "brPromo","telephoneNumber","mail","brRoom","brIP","brMemberOf","brMemberOf","brMemberOf","brMemberOf","brMemberOf","brMemberOf"],
"searchAttributes": ["jpegPhoto","givenName", "sn", "brBirthdate", "brPromo","telephoneNumber","mail","brRoom","brIP"]
},
"sessionSecret":"change this" "sessionSecret":"change this"
} }
\ No newline at end of file
/** /**
* @file Ce fichier gère les requêtes LDAP de type données ; liste des groupe d'un individu="", liste des membres d'un groupe... A ne pas confondre avec ldap_auth qui lui gère l'authentification. * @file Ce fichier gère les requêtes LDAP de type données ; liste des groupe d'un individu, liste des membres d'un groupe... A ne pas confondre avec ldap_auth qui lui gère l'authentification. Il est à lire conjointement avec config.json qui détaille les pats et champs spécifique à un LDAP.
* @author hawkspar * @author hawkspar
*/ */
/* Ne pas hésiter à repasser en synthaxe ES5... Plus simple pour tester en solo avec node directement /* Ne pas hésiter à repasser en synthaxe ES5... Plus simple pour tester en solo avec node directement */
import ldap from 'ldapjs'; import ldap from 'ldapjs';
import fs from 'fs'; import fs from 'fs';
import ldapEscape from 'ldap-escape'; */ import ldapEscape from 'ldap-escape';
var ldap = require('ldapjs'); /*var ldap = require('ldapjs');
var fs = require('fs'); var fs = require('fs');
var ldapEscape = require('ldap-escape'); var ldapEscape = require('ldap-escape');*/
// Important ; permet de vérifier que l'utilisateur reste connecté. // Important ; permet de vérifier que l'utilisateur reste connecté.
var ensureLoggedin = require('connect-ensure-login').ensureLoggedIn; var ensureLoggedin = require('connect-ensure-login').ensureLoggedIn;
...@@ -19,94 +19,201 @@ var ensureLoggedin = require('connect-ensure-login').ensureLoggedIn; ...@@ -19,94 +19,201 @@ var ensureLoggedin = require('connect-ensure-login').ensureLoggedIn;
let config = JSON.parse(fs.readFileSync('../../config.json', 'utf8')); let config = JSON.parse(fs.readFileSync('../../config.json', 'utf8'));
// Connection au serveur LDAP avec des temps de timeout arbitraires // Connection au serveur LDAP avec des temps de timeout arbitraires
var client = ldap.createClient({ url: config.ldap.server, timeout: 10000, idleTimeout: 10000}); var client = ldap.createClient({ url: config.ldap.server});
/** /**
* @summary Fonction qui interroge le LDAP et retrouve les groupes dont un individu est membre. * @summary Fonction qui interroge le LDAP selon un protocole bien précis et renvoit les valeurs trouvées.
* @desc Cette fonction utilise une Promise pour être asynchrone ; elle renvoit la promesse d'une réponse puis traite la demande. Il faut l'appeler suivant un schéma listGroups(uid).then((res) => { truc avec res });. Aucun bind n'est nécessaire donc pas d'identifiant ou de mot de passe à passer. Cette fonction fait une demande au LDAP qu'elle filtre selon un schéma prédéfini dans config.json et à chaque résultat (event SearchEntry) le met dans une liste, et renvoit la liste à l'issue (event end). * @desc Cette fonction utilise une Promise pour être asynchrone ; elle renvoit la promesse d'une réponse puis traite la demande avec ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode search). Il faut l'appeler suivant un schéma requeteLDAP(dic).then((res) => { truc avec res });. Cette fonction fait une demande au LDAP qu'elle filtre selon un schéma prédéfini dans `dic` et à chaque résultat (event SearchEntry) le met dans une liste, et renvoit la liste à l'issue (event end).
* @arg {int} uid - Identifiant de l'individu à interroger * @arg {string} base - DN de l'emplacement de la requête
* @return {string} Liste des uid de groupes (noms flat des groupes) où l'id fourni est membre * @arg {string} filter - Filtre logique de la recherche (format RFC2254)
* @arg {{}} filter_dic - Dictionnaire qui associe les faux champs dans filter aux vraies valeurs pertinentes de la recherche
* @arg {string[]} attributes - Liste des attributs qui figureront dans le résultat final
* @return {string[]} Résultats de la recherche
*/ */
function listGroups(uid) { function requeteLDAP(base, filter, filter_dic, attributes) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var groupsList=[]; // A terme mettre id du type qui se connecte (permet de pas avoir trop de demandes trop rapides)
client.bind(config.connexion.dn, config.connexion.passwd, (err, res) => {});
client.search(config.ldap_data_gl.searchBase, {scope: "sub", attributes: "uid", filter: ldapEscape.filter(config.ldap_data_gl.searchFilter, {id: uid})}, function(err, res) {
var vals=[];
// Interrogation LDAP selon configuration du dic
client.search(base, {
"scope": "sub",
"filter": ldapEscape.filter(filter, filter_dic),
"attributes": attributes
}, function(err, res) {
// Gestion erreur
if (err) { if (err) {
reject(err); reject(err);
} else { } else {
res.on('searchEntry', function(entry) { groupsList.push(entry.object.uid); }); // Dès que la recherche renvoit une entrée, on stocke les attributs qui nous intéresse
res.on('end', function(res) { resolve(groupsList); }); res.on('searchEntry', function(entry) {
attributes.forEach((element) => {
eval("vals.push(entry.object."+element+")");
console.log(vals);
});
});
// Si la recherche est finie on se déconnecte et on renvoit la liste
res.on('end', function(res) {
client.bind("", "", (err, res) => {});
resolve(vals);
});
} }
}); });
}); });
} }
/**
* @summary Fonction qui interroge le LDAP et retrouve les groupes dont un individu est membre.
* @desc Cette fonction utilise requeteLDAP avec un dictionnaire prédéfini dans config.json.
* @arg {int} uid - Identifiant de l'individu à interroger
* @return {string} Liste des uid de groupes (noms flat des groupes) où l'id fourni est membre
*/
function listGroups(uid) {
return new Promise(function(resolve, reject) {
resolve(requeteLDAP(config.dn_groups, config.filter_lg, { id : uid }, config.attributes_id));
});
}
/** /**
* @summary Fonction qui interroge le LDAP et retrouve la liste des membres d'un groupe. * @summary Fonction qui interroge le LDAP et retrouve la liste des membres d'un groupe.
* @desc Cette fonction utilise une Promise pour être asynchrone ; elle renvoit la promesse d'une réponse puis traite la demande. Il faut l'appeler suivant un schéma listMembers(uid).then((res) => { truc avec res });. Aucun bind n'est nécessaire donc pas d'identifiant ou de mot de passe à passer. Cette fonction fait une demande au LDAP qu'elle filtre selon un schéma prédéfini dans config.json et à chaque résultat (event SearchEntry) le met dans une liste, et renvoit la liste à l'issue (event end). * @desc Cette fonction utilise requeteLDAP avec un dictionnaire prédéfini dans config.json.
* @arg {int} gid - Identifiant du groupe à interroger * @arg {int} gid - Identifiant du groupe à interroger
* @return {string} Liste des uid des membres où l'id fournie est membre (noms flat des groupes) * @return {string} Liste des uid des membres où l'id fournie est membre (noms flat des groupes)
*/ */
function listMembers(gid) { function listMembers(gid) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var membersList=[]; resolve(requeteLDAP(config.dn_users, config.filter_lm, { id: gid }, config.attributes_id));
});
client.search(config.ldap_data_ml.searchBase="", {scope: "sub", attributes: "uid", filter: ldapEscape.filter(config.ldap_data_ml.searchFilter, {id: gid})}, function(err, res) { }
if (err) {
reject(err); /**
} else { * @summary Fonction qui interroge le LDAP et retrouve la liste des admins d'un groupe.
res.on('searchEntry', function(entry) { membersList.push(entry.object.uid); }); * @desc Cette fonction utilise requeteLDAP avec un dictionnaire prédéfini dans config.json.
res.on('end', function(res) { resolve(membersList); }); * @arg {int} gid - Identifiant du groupe à interroger
* @return {string} Liste des uid des membres où l'id fournie est membre (noms flat des groupes)
*/
function listAdmins(gid) {
//TBC
return new Promise(function(resolve, reject) {
resolve(requeteLDAP(gid, config.ldap_data_al));
});
}
/**
* @summary Fonction qui interroge le LDAP au sujet d'un uid particulier et qui renvoit toutes ses infos.
* @arg {string} uid - Identifiants de l'utilisateur
* @return {string[]} Informations recueillies ; même quand dans TOL voir config.json.
*/
function rens(uid) {
return new Promise(function(resolve, reject) {
resolve(requeteLDAP(config.dn_users, config.filter_st, { id: uid }, config.attributes_all));
});
}
/**
* @summary Fonction qui interroge le LDAP et retrouve juste les uid des paxs validant les critères de recherche. Première étape vers vrai TOL (Trombino On Line).
* @desc Accepte des champs exacts ou incomplets mais pas approximatifs et ne gère pas l'auto-complete. Cette fonction utilise une Promise pour être asynchrone ; elle renvoit la promesse d'une réponse puis traite la demande. Il faut l'appeler suivant un schéma TOL(uid).then((res) => { truc avec res });. Aucun bind n'est nécessaire donc pas d'identifiant ou de mot de passe à passer. Cette fonction fait une demande au LDAP qu'elle filtre selon un schéma généré à la volée à partir de config.json et à chaque résultat (event SearchEntry) le met dans une liste, et renvoit la liste à l'issue (event end). MEF Timeout pour des recherches trop vagues.
* @arg {string} c0 - Prénom
* @arg {string} c1 - Nom
* @arg {string} c2 - Surnom
* @arg {string} c3 - Nationalité
* @arg {string} c4 - Ecole ou université d'origine
* @arg {string} c5 - Promotion
* @arg {string} c6 - Groupe
* @arg {string} c7 - Cours
* @arg {string} c8 - Sport pratiqué
* @arg {string} c9 - Numéro de téléphone
* @arg {string} c10 - Adresse courriel
* @arg {string} c11 - Adresse physique
* @arg {string} c12 - Adresse ip
* @return {string[]} uids des profils qui "match" les critères proposés.
*/
function idTOL(c0="", c1="", c2="", c3="", c4="", c5="", c6="", c7="", c8="", c9="", c10="", c11="", c12="") {
return new Promise(function(resolve, reject) {
var filter="";
var filter_dic={};
// Iteration pour chaque champ, alourdissement du filtre selon des trucs prédéfini dans config.json encore
config.search_attributes_tol.forEach((element, index, list) => {
if (eval("c"+index) != '') { // Si il y a qque chose à chercher pour ce filtre
filter="(&"+filter+"(|("+element+"=${app_"+element+index+"})"+ // On cherche la valeur exacte
"(|("+element+"=*${app_"+element+index+"})"+ // La valeur finale avec des trucs avant ; wildcard *
"(|("+element+"=*${app_"+element+index+"}*)"+ // La valeur du milieu avec des trucs avant et après
"("+element+"=${app_"+element+index+"}*)))))"; // La valeur du début avec des trucs après
// Mise en relation de chaque valeur à la demande utilisateur dans un dico
filter_dic["app_"+element+index]=eval("c"+index);
} }
}); });
// Appel requeteLDAP avec filtre de l'espace
resolve(requeteLDAP(config.dn_users, filter, filter_dic, config.attributes_id));
}); });
} }
/** /**
* @summary Fonction qui interroge le LDAP et retrouve les paxs validant les critères de recherche. * @summary Fonction qui interroge le LDAP et retrouve les paxs validant les critères de recherche. Bien mais vite inutilisable car demande trop au LDAP.
* @desc Accepte des champs incomplets mais pas approximatifs et ne gère pas l'auto-complete. Cette fonction utilise une Promise pour être asynchrone ; elle renvoit la promesse d'une réponse puis traite la demande. Il faut l'appeler suivant un schéma TOL(uid).then((res) => { truc avec res });. Aucun bind n'est nécessaire donc pas d'identifiant ou de mot de passe à passer. Cette fonction fait une demande au LDAP qu'elle filtre selon un schéma généré à la volée à partir de config.json et à chaque résultat (event SearchEntry) le met dans une liste, et renvoit la liste à l'issue (event end). * @desc Accepte des champs incomplets mais pas approximatifs et ne gère pas l'auto-complete. Cette fonction utilise une Promise pour être asynchrone ; elle renvoit la promesse d'une réponse puis traite la demande. Il faut l'appeler suivant un schéma TOL(uid).then((res) => { truc avec res });. Aucun bind n'est nécessaire donc pas d'identifiant ou de mot de passe à passer. Cette fonction fait une demande au LDAP qu'elle filtre selon un schéma généré à la volée à partir de config.json et à chaque résultat (event SearchEntry) le met dans une liste, et renvoit la liste à l'issue (event end). MEF Timeout pour des recherches trop vagues.
* @arg {string} c0 - Prénom * @arg {string} c0 - Prénom
* @arg {string} c1 - Nom * @arg {string} c1 - Nom
* @arg {string} c2 - Surnom * @arg {string} c2 - Surnom
* @arg {string} c3 - Nationalité * @arg {string} c3 - Nationalité
* @arg {string} c4 - Ecole ou université d'origine * @arg {string} c4 - Ecole ou université d'origine
* @arg {int} c5 - Promotion * @arg {string} c5 - Promotion
* @arg {string} c6 - Groupe * @arg {string} c6 - Groupe
* @arg {string} c7 - Cours * @arg {string} c7 - Cours
* @arg {string} c8 - Sport pratiqué * @arg {string} c8 - Sport pratiqué
* @arg {int} c9 - Numéro de téléphone * @arg {string} c9 - Numéro de téléphone
* @arg {string} c10 - Adresse courriel * @arg {string} c10 - Adresse courriel
* @arg {string} c11 - Adresse physique * @arg {string} c11 - Adresse physique
* @arg {string} c12 - Adresse ip * @arg {string} c12 - Adresse ip
* @return {string[]} Informations recueillies ; plusieurs fois une liste sur le format ci-dessus pour tous les résultats correspondants plus une photo en byttestring et date de naissance. * @arg {int}
* @return {string[]} Informations recueillies ; voir config.json.
*/ */
function TOL(c0="", c1="", c2="", c3="", c4="", c5="", c6="", c7="", c8="", c9="", c10="", c11="", c12="") { function TOL(c0="", c1="", c2="", c3="", c4="", c5="", c6="", c7="", c8="", c9="", c10="", c11="", c12="") {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var candidatesList=[]; // Pas nécessaire mais bien
client.bind(config.connexion.dn, config.connexion.passwd, (err, res) => {});
var filter=""; var filter="";
var dic={}; var dic={};
// Iteration pour chaque champ, alourdissement du filtre selon des trucs prédéfini dans config.json encore
config.ldap_data_tol.searchFilterAttributes.forEach((element, index, list) => { config.ldap_data_tol.searchFilterAttributes.forEach((element, index, list) => {
if (eval("c"+index.toString()) != '') { if (eval("c"+index.toString()) != '') { // Si il y a qque chose à chercher pour ce filtre
filter="(&"+filter+"(|("+element+"=*${app_"+element+index+"})"+ filter="(&"+filter+"(|("+element+"=${app_"+element+index+"})"+ // On cherche la valeur exacte
"(|("+element+"=${app_"+element+index+"})"+ "(|("+element+"=*${app_"+element+index+"})"+ // La valeur finale avec des trucs avant ; wildcard *
"(|("+element+"=*${app_"+element+index+"}*)"+ "(|("+element+"=*${app_"+element+index+"}*)"+ // La valeur du milieu avec des trucs avant et après
"("+element+"=${app_"+element+index+"}*)))))"; "("+element+"=${app_"+element+index+"}*)))))"; // La valeur du début avec des trucs après
// Mise en relation de chaque valeur à la demande utilisateur dans un dico
dic["app_"+element+index]=eval("c"+index.toString()); dic["app_"+element+index]=eval("c"+index.toString());
} }
}); });
// Debug
//console.log(filter);
//console.log(dic);
client.search(config.ldap_data_tol.searchBase, {scope: "sub", attributes: config.ldap_data_tol.searchAttributes, filter: ldapEscape.filter(filter, dic)}, function(err, res) { var candidatesList=[];
// Interrogation LDAP et filtre de malade
client.search(config.ldap_data_tol.searchBase, {
scope: "sub",
attributes: config.ldap_data_tol.searchAttributes,
filter: ldapEscape.filter(filter, dic)
},
function(err, res) {
// Gestion erreur
if (err) { if (err) {
reject(err); reject(err);
} else { } else {
// Toujours gestion différenciée début et fin
res.on('searchEntry', function(entry) { res.on('searchEntry', function(entry) {
for (var i=0; i<config.ldap_data_tol.searchAttributes.length; i++) { // De nouveau, iteration sur les valeurs recherchées et entrée dans la liste
// Complicated, but hides searchAttributes config.ldap_data_tol.searchAttributes.forEach((element) => {
eval("candidatesList.push(entry.object."+config.ldap_data_tol.searchAttributes[i]+")"); eval("candidatesList.push(entry.object."+element+")");
} });
});
res.on('page', function(result, cb) {
resolve(candidatesList);
console.log("page ends");
}); });
res.on('end', function(res) { resolve(candidatesList); }); res.on('end', function(res) { resolve(candidatesList); });
} }
...@@ -114,11 +221,13 @@ function TOL(c0="", c1="", c2="", c3="", c4="", c5="", c6="", c7="", c8="", c9=" ...@@ -114,11 +221,13 @@ function TOL(c0="", c1="", c2="", c3="", c4="", c5="", c6="", c7="", c8="", c9="
}); });
} }
// Synthaxe d'utilisation //listMembers("drakkes").then((meList) => { console.log(meList); });
//listGroups("quentin.louis").then((meList) => { console.log(meList); }); //listGroups("agopia.1999").then((grList) => { console.log(grList); });
TOL("","","","","","","faerix","","","","","","").then((meList) => { console.log(meList); }); //rens("quentin.louis").then((profil) => { console.log(profil); });
//idTOL("","","","","","","bda","","","","","","").then((caList) => { console.log(caList); });
//TOL("","","","","","","faerix","","","","","","").then((caList) => { console.log(caList); });
/* Partage pour le reste du monde ; même remarque synthaxe /* Partage pour le reste du monde ; même remarque synthaxe que pour l'import */
export { listGroups, listMembers, TOL }; */ export { listGroups, listMembers, TOL };
module.exports ={ listGroups, listMembers, TOL }; /*module.exports ={ listGroups, listMembers, TOL };*/
\ No newline at end of file \ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment