From ec12c7742212d025ed7380dfc6869e6bf22fff01 Mon Sep 17 00:00:00 2001
From: Oliver Facklam <oliver.facklam.lfgeb@gmail.com>
Date: Mon, 14 Jan 2019 23:21:34 +0100
Subject: [PATCH] Tentative. ATTENTION DANGER INJECTION

Ne fonctionne tjrs pas
---
 src/config_passport.js      |  6 ++---
 src/ldap/export/group.ts    | 16 ++++++-------
 src/ldap/export/user.ts     | 46 ++++++++++++++++++------------------
 src/ldap/internal/basics.ts | 47 ++++++++++++++++++++++---------------
 src/ldap/internal/tools.ts  | 18 ++++++++------
 5 files changed, 73 insertions(+), 60 deletions(-)

diff --git a/src/config_passport.js b/src/config_passport.js
index 33a86aa..ea19c80 100644
--- a/src/config_passport.js
+++ b/src/config_passport.js
@@ -40,8 +40,8 @@ passport.use(new LdapStrategy({
         url: ldapConfig.server,
         //bindDn: '.............',
         //bindCredentials: '..........',
-        //  searchBase: ldapConfig.searchBase, TODO: this cannot be left empty.
-        //  searchFilter: ldapConfig.searchFilter, TODO: this cannot be left empty.
+        searchBase: "ou=eleves,dc=frankiz,dc=net",//ldapConfig.searchBase, TODO: this cannot be left empty.
+        searchFilter: "(uid={{username}})"//ldapConfig.searchFilter, TODO: this cannot be left empty.
         //searchAttributes: ['givenName', 'sn'],
         //tlsOptions: '..........',
     },
@@ -85,6 +85,6 @@ passport.serializeUser(function (user, done) {
  * > This user object is attached to the request as req.user making it accessible in our request handling. (available in all subsequent middleware)
  */
 passport.deserializeUser(function (userUid, done) {
-    // console.log(`passport.deserializeUser(): deserializing user ${userUid}`); // DEBUG
+    console.log(`passport.deserializeUser(): deserializing user ${userUid}`); // DEBUG
     done(null, { uid: userUid });
 });
diff --git a/src/ldap/export/group.ts b/src/ldap/export/group.ts
index 7f9f11f..2c2bb8a 100644
--- a/src/ldap/export/group.ts
+++ b/src/ldap/export/group.ts
@@ -16,13 +16,13 @@ import {Tools} from '../internal/tools';
  * @var {string[]} admins - Liste des admins du groupe ; supposée être une sous-liste de la précédente
  * @var {string} description - Description du groupe (facultatif)
  */
-export interface groupData {
-    "gid": string,
-	"name": string,
-	"type": string,
-    "members": string[],
-    "admins": string[],
-    "description"?: string
+export class groupData {
+    "gid": string;
+	"name": string;
+	"type": string;
+    "members": string[];
+    "admins": string[];
+    "description"?: string;
 }
 
 //------------------------------------------------------------------------------------------------------------------------
@@ -49,7 +49,7 @@ export class Group {
      */
     static async peek(gid: string) : Promise<groupData> {
         try {
-            return Tools.peek<groupData>("gr", gid);
+            return Tools.peek<groupData>("gr", gid, groupData);
         }
         catch(err) {
             throw "Erreur lors d'une recherche d'informations sur un groupe.";
diff --git a/src/ldap/export/user.ts b/src/ldap/export/user.ts
index b50f668..8eb37d2 100644
--- a/src/ldap/export/user.ts
+++ b/src/ldap/export/user.ts
@@ -33,28 +33,28 @@ import {Group} from './group';
  * @var {string[]} admins - Liste des gid dont l'utilisateur est admin ; supposé sous-liste de groups
  * TBA @var {string[]} likes - Liste des gid dont l'utilisateur est sympathisant
  */
-export interface userData {
-    uid?: string,
-    groups?: string[],
-    groupsIsAdmin?: string[],
-    password?: string,
-    givenName?: string,
-    lastName?: string,
-    nickname?: string,
-    promotion?: string,
-    photo?: string,
-    birthdate?: string,
-    nationality?: string,
-    phone?: string,
-    address?: string,
-    mail?: string,
-    ips?: string[],
-    directory?: string,
-    login?: string,
-    readPerm?: string,
-    writePerm?: string,
-    forlifes?: string[],
-    sport?: string
+export class userData {
+    uid?: string;
+    groups?: string[];
+    groupsIsAdmin?: string[];
+    password?: string;
+    givenName?: string;
+    lastName?: string;
+    nickname?: string;
+    promotion?: string;
+    photo?: string;
+    birthdate?: string;
+    nationality?: string;
+    phone?: string;
+    address?: string;
+    mail?: string;
+    ips?: string[];
+    directory?: string;
+    login?: string;
+    readPerm?: string;
+    writePerm?: string;
+    forlifes?: string[];
+    sport?: string;
     //"likes"?: string[]
 }
 
@@ -82,7 +82,7 @@ export class User {
      */
     static async peek(uid: string) : Promise<userData> {
         try { 
-            return Tools.peek<userData>("us", uid);
+            return Tools.peek<userData>("us", uid, userData);
         }
         catch(err) {
             throw "Error while peeking a user.";
diff --git a/src/ldap/internal/basics.ts b/src/ldap/internal/basics.ts
index b96736d..c14dbb9 100644
--- a/src/ldap/internal/basics.ts
+++ b/src/ldap/internal/basics.ts
@@ -98,30 +98,38 @@ export class Basics {
      * @static
      * @async
      */
-    static search(domain: 'gr'|'us', attributes: string[], id: string, filter: string, handler : (entry: any) => void) : void {
+    static search(domain: 'gr'|'us', attributes: string[], id: string, filter: string, handler : (entry: any) => void) : Promise<void> {
         Basics.adminBind();
         let dn ="";
-        if (id != null)     { dn+=ldapConfig.key_id+'='+id+','; }
+        if (id != null)     { dn+=ldapConfig.key_id+'='+ ldapEscape.dn("${txt}", { txt: id}) +','; }
         if (domain == "gr") { dn+=ldapConfig.dn_groups; }
         else                { dn+=ldapConfig.dn_users; }
         // Interrogation LDAP selon filter
-        client.search(ldapEscape.dn("${txt}", { txt: dn}), {            // Must be escaped in case of a malignious false id
-            "scope": "sub",
-            "filter": ldapEscape.filter("${txt}", { txt: filter}),      // Must be escaped in case of a malignious search arg
-            "attributes": attributes
-        }, (err, res) => {
-            // Gestion erreur ; pb car pas simple true / autre en sortie
-            if (err) {
-                throw "Erreur lors de la recherche sur le LDAP.";
-            } else {
-                // Dès que la recherche renvoit une entrée, on stocke les attributs qui nous intéresse
-                res.on('searchEntry', entry => { handler(entry); });
-                // Si la recherche renvoie une erreur, on renvoit
-                res.on('error', resErr => { throw resErr; });
-                // Quand la recherche est finie on se déconnecte
-                res.on('end', _ => { Basics.unbind(); });
-            }
+        console.log(dn);
+        //filter = ldapEscape.filter("${txt}", { txt: filter });
+        console.log(filter);
+
+        let promise = new Promise<void>(function(resolve, reject) {
+            client.search(dn, {            // Must be escaped in case of a malignious false id
+                "scope": "sub",
+                "filter": filter,      // Must be escaped in case of a malignious search arg
+                "attributes": attributes
+            }, (err, res) => {
+                // Gestion erreur ; pb car pas simple true / autre en sortie
+                if (err) {
+                    throw "Erreur lors de la recherche sur le LDAP.";
+                } else {
+                    // Dès que la recherche renvoit une entrée, on stocke les attributs qui nous intéresse
+                    res.on('searchEntry', entry => { handler(entry); });
+                    // Si la recherche renvoie une erreur, on renvoit
+                    res.on('error', resErr => { throw resErr; });
+                    // Quand la recherche est finie on se déconnecte
+                    res.on('end', _ => { Basics.unbind(); resolve(); });
+                }
+            });
         });
+
+        return promise;
     }
     
     /**
@@ -162,8 +170,9 @@ export class Basics {
      */
     static async searchMultiple(domain: 'gr'|'us', attributes: string[], id: string=null, filter: string="(objectClass=*)") : Promise<Array<dic>> {
         let vals=[];
-        Basics.search(domain, attributes, id, filter,  entry => {
+        await Basics.search(domain, attributes, id, filter,  entry => {
             // Cas plusieurs attributs donc résultat dictionnaire
+            console.log("Found entry!!");
             vals.push({});
             attributes.forEach(attribute => {
                 vals.slice(-1)[0][attribute]=entry.object[attribute];
diff --git a/src/ldap/internal/tools.ts b/src/ldap/internal/tools.ts
index cb79122..d22325a 100644
--- a/src/ldap/internal/tools.ts
+++ b/src/ldap/internal/tools.ts
@@ -32,19 +32,23 @@ export class Tools {
      * @static
      * @async
      */
-    static async peek<T>(domain: 'us'|'gr', id: string) : Promise<T> {
-        if (domain='gr') {
+    static async peek<T>(domain: 'us'|'gr', id: string, type: new () => T) : Promise<T> {
+        if (domain=='gr') {
             var dirtyKeys = ldapConfig.group;
         }
         else {
             var dirtyKeys = ldapConfig.user;
         }
-        let cleanData : T;
-        let dirtyData = await Basics.searchMultiple(domain, dirtyKeys.values(), id)[0];
+        let cleanData : T = new type();
+        let attr = Object.keys(dirtyKeys).map(key => dirtyKeys[key]);
+        //console.log(attr);
+        let dirtyData = await Basics.searchMultiple(domain, attr, id);
+        //console.log(dirtyData[0]);
         // Rename output
-        for (let uncleanKey in dirtyData) {
-            for (let cleanKey in cleanData) {
-                if (uncleanKey=dirtyKeys[cleanKey]) { cleanData[cleanKey] = dirtyData[uncleanKey]; }
+        for (let uncleanKey in dirtyData[0]) {
+            for (let cleanKey of Object.keys(cleanData)) {
+                //console.log(cleanKey);
+                if (uncleanKey==dirtyKeys[cleanKey]) { cleanData[cleanKey] = dirtyData[uncleanKey]; }
             }
         }
         return cleanData;
-- 
GitLab