From 79d4a3104c2a76d22c9c2006828fa458f514238c Mon Sep 17 00:00:00 2001
From: ManifoldFR <wilson.jallet@gmail.com>
Date: Tue, 1 May 2018 18:15:05 +0200
Subject: [PATCH] refactor passport config to auth.js file

---
 ldap_config.json  |  2 +-
 package-lock.json | 99 +++++++++++++++++++++++++++++++++++++++++++++++
 package.json      |  1 +
 src/auth.js       | 71 +++++++++++++++++++++++++++++++++
 src/server.js     | 86 +++-------------------------------------
 5 files changed, 178 insertions(+), 81 deletions(-)
 create mode 100644 src/auth.js

diff --git a/ldap_config.json b/ldap_config.json
index f19e61a..752a1d8 100644
--- a/ldap_config.json
+++ b/ldap_config.json
@@ -71,5 +71,5 @@
 	"sa": {
 		"attributs": "memberUid"
 	},
-	"sessionSecret":"change this"
+	"sessionSecret":"ozyNMHdT,WFTu|t"
 }
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 5a7f9c6..0cb39e4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1515,6 +1515,11 @@
       "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==",
       "dev": true
     },
+    "base64url": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz",
+      "integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs="
+    },
     "basic-auth": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz",
@@ -1721,6 +1726,11 @@
         "isarray": "^1.0.0"
       }
     },
+    "buffer-equal-constant-time": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+      "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
+    },
     "buffer-writer": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.1.tgz",
@@ -2757,6 +2767,15 @@
         "stream-shift": "^1.0.0"
       }
     },
+    "ecdsa-sig-formatter": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz",
+      "integrity": "sha1-S8kmJ07Dtau1AW5+HWCSGsJisqE=",
+      "requires": {
+        "base64url": "^2.0.0",
+        "safe-buffer": "^5.0.1"
+      }
+    },
     "editions": {
       "version": "1.3.4",
       "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz",
@@ -5642,6 +5661,30 @@
       "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
       "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
     },
+    "jsonwebtoken": {
+      "version": "8.2.1",
+      "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.2.1.tgz",
+      "integrity": "sha512-l8rUBr0fqYYwPc8/ZGrue7GiW7vWdZtZqelxo4Sd5lMvuEeCK8/wS54sEo6tJhdZ6hqfutsj6COgC0d1XdbHGw==",
+      "requires": {
+        "jws": "^3.1.4",
+        "lodash.includes": "^4.3.0",
+        "lodash.isboolean": "^3.0.3",
+        "lodash.isinteger": "^4.0.4",
+        "lodash.isnumber": "^3.0.3",
+        "lodash.isplainobject": "^4.0.6",
+        "lodash.isstring": "^4.0.1",
+        "lodash.once": "^4.0.0",
+        "ms": "^2.1.1",
+        "xtend": "^4.0.1"
+      },
+      "dependencies": {
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+        }
+      }
+    },
     "jstransformer": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz",
@@ -5651,6 +5694,27 @@
         "promise": "^7.0.1"
       }
     },
+    "jwa": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz",
+      "integrity": "sha1-oFUs4CIHQs1S4VN3SjKQXDDnVuU=",
+      "requires": {
+        "base64url": "2.0.0",
+        "buffer-equal-constant-time": "1.0.1",
+        "ecdsa-sig-formatter": "1.0.9",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "jws": {
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz",
+      "integrity": "sha1-+ei5M46KhHJ31kRLFGT2GIDgUKI=",
+      "requires": {
+        "base64url": "^2.0.0",
+        "jwa": "^1.1.4",
+        "safe-buffer": "^5.0.1"
+      }
+    },
     "keyv": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz",
@@ -6198,6 +6262,41 @@
       "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.7.tgz",
       "integrity": "sha512-jzqTi3vk4J5Dxq43cNjB0ekfCjPLHixoY2Sc0WHTo+0r928taLqe/VCt02vY5uQBvg0rdXgL3xWkK4X0MCmZcw=="
     },
+    "lodash.includes": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+      "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
+    },
+    "lodash.isboolean": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+      "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
+    },
+    "lodash.isinteger": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+      "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
+    },
+    "lodash.isnumber": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+      "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
+    },
+    "lodash.isplainobject": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+      "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
+    },
+    "lodash.isstring": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+      "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
+    },
+    "lodash.once": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+      "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
+    },
     "log-symbols": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
diff --git a/package.json b/package.json
index e668864..21127a9 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
     "graphql": "^0.13.2",
     "graphql-tools": "^2.24.0",
     "graphql-voyager": "^1.0.0-rc.15",
+    "jsonwebtoken": "^8.2.1",
     "knex": "^0.14.6",
     "ldap-escape": "^1.1.5",
     "ldapjs": "^1.0.2",
diff --git a/src/auth.js b/src/auth.js
new file mode 100644
index 0000000..1198261
--- /dev/null
+++ b/src/auth.js
@@ -0,0 +1,71 @@
+import passport from 'passport';
+import LdapStrategy from 'passport-ldapauth';
+import fs from 'fs';
+import path from 'path';
+
+/**
+ * @description Configuration de l'authentification
+ * @author guillaume.wang
+ *
+ * on a besoin d'authentification pour 2 trucs :
+ * - l'acces a l'interface admin (admin_view) du back, definie dans admin_router.js
+ * - le contexte graphQL
+ * 
+ * serializeUser et deserializeUser: passport s'attend a ce qu'on ait besoin d'avoir req.user disponible partout dans notre code
+ * En gros l'idee de passport c'est: serializeUser permet d'obtenir une cle identifiant chaque user
+ * et deserializeUser prend cette cle, fait une requete vers une BDD de users et met dans l'objet JS req.user toutes les infos issues de la BDD
+ * Cette repartition permet de ne stocker dans la session (i.e. en memoire sur le serveur) que la cle des utilisateurs connectes et de ne "charger en memoire" toutes les infos de la BDD que lorsque necessaire
+ * cf https://stackoverflow.com/questions/27637609/understanding-passport-serialize-deserialize#27637668
+ * et http://toon.io/understanding-passportjs-authentication-flow/
+ * 
+ * Mais en fait dans notre cas c'est graphql qui communique avec la BDD, donc on s'en fiche! On peut se contenter de dire a serializeUser et deserializeUser de ne s'occuper que du champ uid)
+ */
+const configPath = path.resolve('./', 'ldap_config.json');
+const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
+
+passport.use(new LdapStrategy({
+    server: {
+        url: config.ldap.server,
+        //bindDn: '.............',
+        //bindCredentials: '..........',
+        searchBase: config.ldap.searchBase,
+        searchFilter: config.ldap.searchFilter,
+        //searchAttributes: ['givenName', 'sn'],
+        //tlsOptions: '..........',
+    },
+
+    //usernameField: 'username', // Field name where the username is found, defaults to username
+    //passwordField: 'password', // Field name where the pas    sword is found, defaults to password
+
+    // LdapStrategy has a default verify callback ! j'ai perdu plein de temps pour rien :'(
+    // cf. https://github.com/vesse/passport-ldapauth/blob/master/lib/passport-ldapauth/strategy.js, line 195 (` var verify = function() { ... } `)
+    /*
+    function (user, done) {
+        // "verify callback", called after each passport.authenticate(...),
+        // unless missing credentials (in which case a 400 Error is returned)
+
+        // "The purpose of a verify callback is to find the user that possesses a set of credentials" (from passport doc)
+        // i.e. we query the database (in our case the LDAP) to get user's data
+        console.log("Entering passport's verify callback");
+
+        if (user){
+            //if user exists
+            console.log("Successfully authenticated " + user.uid);
+        }
+    }
+    */
+})
+);
+
+
+//toujours bon a savoir pour faire des tests:
+//The result of the serializeUser method is attached to the session as req.session.passport.user
+passport.serializeUser(function (user, done) {
+    done(null, user.uid);
+});
+
+//The first argument of deserializeUser corresponds to the key of the user object that was given to the done function in serializeUser
+//The fetched object is attached to the request object as req.user (available in all subsequent middleware)
+passport.deserializeUser(function (userUid, done) {
+    done(null, { uid: userUid });
+});
\ No newline at end of file
diff --git a/src/server.js b/src/server.js
index 512ea4c..dba035f 100644
--- a/src/server.js
+++ b/src/server.js
@@ -11,14 +11,14 @@ import { express as graphqlVoyager } from 'graphql-voyager/middleware';
 import graphqlHTTP from 'express-graphql'; // new name of 'graphql-server-express'. cf npmjs.com
 import flash from 'connect-flash';
 import { ensureLoggedIn } from 'connect-ensure-login';
+import './auth';
 import passport from 'passport';
-import LdapStrategy from 'passport-ldapauth';
-import fs from 'fs';
 import session from 'express-session';
 import bodyParser from 'body-parser';
 import favicon from 'serve-favicon';
 import morgan from 'morgan';
 import path from 'path';
+import fs from 'fs';
 import cors from 'cors';
 
 const server = express();
@@ -30,59 +30,8 @@ server.use(bodyParser.urlencoded({ //parses bodies of media type "application/x-
     extended: true //use qs library (quoi que ca veuille dire o.O)
 }));
 
-/**
- * @description Configuration de l'authentification
- * @author guillaume.wang
- *
- * on a besoin d'authentification pour 2 trucs :
- * - l'acces a l'interface admin (admin_view) du back, definie dans admin_router.js
- * - le contexte graphQL
- * 
- * serializeUser et deserializeUser: passport s'attend a ce qu'on ait besoin d'avoir req.user disponible partout dans notre code
- * En gros l'idee de passport c'est: serializeUser permet d'obtenir une cle identifiant chaque user
- * et deserializeUser prend cette cle, fait une requete vers une BDD de users et met dans l'objet JS req.user toutes les infos issues de la BDD
- * Cette repartition permet de ne stocker dans la session (i.e. en memoire sur le serveur) que la cle des utilisateurs connectes et de ne "charger en memoire" toutes les infos de la BDD que lorsque necessaire
- * cf https://stackoverflow.com/questions/27637609/understanding-passport-serialize-deserialize#27637668
- * et http://toon.io/understanding-passportjs-authentication-flow/
- * 
- * Mais en fait dans notre cas c'est graphql qui communique avec la BDD, donc on s'en fiche! On peut se contenter de dire a serializeUser et deserializeUser de ne s'occuper que du champ uid)
- */
-let configPath = path.resolve('./', 'ldap_config.json');
-let config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
-
-passport.use(new LdapStrategy({
-    server: {
-        url: config.ldap.server,
-        //bindDn: '.............',
-        //bindCredentials: '..........',
-        searchBase: config.ldap.searchBase,
-        searchFilter: config.ldap.searchFilter,
-        //searchAttributes: ['givenName', 'sn'],
-        //tlsOptions: '..........',
-    },
-
-    //usernameField: 'username', // Field name where the username is found, defaults to username
-    //passwordField: 'password', // Field name where the pas    sword is found, defaults to password
-    
-    // LdapStrategy has a default verify callback ! j'ai perdu plein de temps pour rien :'(
-    // cf. https://github.com/vesse/passport-ldapauth/blob/master/lib/passport-ldapauth/strategy.js, line 195 (` var verify = function() { ... } `)
-    /*
-    function (user, done) {
-        // "verify callback", called after each passport.authenticate(...),
-        // unless missing credentials (in which case a 400 Error is returned)
-
-        // "The purpose of a verify callback is to find the user that possesses a set of credentials" (from passport doc)
-        // i.e. we query the database (in our case the LDAP) to get user's data
-        console.log("Entering passport's verify callback");
-
-        if (user){
-            //if user exists
-            console.log("Successfully authenticated " + user.uid);
-        }
-    }
-    */
-})
-);
+const configPath = path.resolve('./', 'ldap_config.json');
+const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
 
 // Définit les paramètres de stockage des sessions.
 server.use(session({
@@ -93,17 +42,7 @@ server.use(session({
 server.use(passport.initialize());
 server.use(passport.session());
 
-//toujours bon a savoir pour faire des tests:
-//The result of the serializeUser method is attached to the session as req.session.passport.user
-passport.serializeUser(function (user, done) {
-    done(null, user.uid);
-});
-
-//The first argument of deserializeUser corresponds to the key of the user object that was given to the done function in serializeUser
-//The fetched object is attached to the request object as req.user (available in all subsequent middleware)
-passport.deserializeUser(function (userUid, done) {
-    done(null, { uid: userUid });
-});
+
 /* fin de Configuration de l'authentification */
 
 // cache le fait que l'application tourne sous Express dans le header HTTP.
@@ -134,19 +73,6 @@ const corsOptions = {
 };
 server.use(cors(corsOptions));
 
-/*
-server.use('/graphql', bodyParser.json(), graphqlHTTP(async (req, res, params) => ({
-    schema: schema,
-    graphiql: true,
-    context: {
-        user: {
-            uid: req.user ? req.user.uid : defaultUser.dn.split("=")[1].split(",")[0],
-            password: "mythe"
-        }
-    }
-})));
-*/
-
 server.use('/graphql', 
     bodyParser.json(), // parse incoming HTTP request (req) as a JSON
     graphqlHTTP(async (req, res, params) => {
@@ -154,7 +80,7 @@ server.use('/graphql',
         let uid;
         let password;
 
-        if(req.isAuthenticated) {
+        if(req.isAuthenticated()) {
             try {
                 uid = req.user.uid;
                 password = "mythe";
-- 
GitLab