Skip to content
Snippets Groups Projects
config_passport.js 5.71 KiB
Newer Older
Guillaume WANG's avatar
Guillaume WANG committed
 * @file Configuration de passport pour utiliser l'authentification LDAP
Guillaume WANG's avatar
Guillaume WANG committed
 * @author kadabra
Guillaume WANG's avatar
Guillaume WANG committed
 * http://toon.io/on-passportjs-specific-use-cases/#howtosplituppassportjsconfigurationbetweenmultiplefiles
 * 
 * On utilise passport avec la strategie 'ldapauth' pour transmettre une tentative d'authentification au LDAP.
 * Dans cette partie "requete au LDAP", passport a un role de client (du LDAP).
 * 
 * passport joue aussi un role de serveur de l'utilisateur, en retransmettant la decision du LDAP (credentials valides ou invalides).
 * On utilise passport avec sessions, ce qui signifie qu'en plus passport est un serveur "intelligent"
 * càd qu'il peut authentifier lui-même un utilisateur, identifié par un cookie, qui a déjà été authentifié par le LDAP.
 * Ceci évite d'avoir à demander une authentif LDAP à chaque requête, et surtout évite à l'utilisateur d'avoir à envoyer son mdp LDAP à chaque requête
 * 
 * Ceci est réalisé en gardant "en mémoire" (appelée session storage) une table de correspondance entre des cookies et des sessions
 * Ainsi une requête est authentifiée dès lors qu'elle comporte un cookie correspondant à une "entrée" dans le session storage
 * L'existence de sessions permet aussi de garder trace d'informations spécfiques à chaque utilisateur, 
 * au lieu de juste "il s'agit d'un utilisateur, on ne sait pas lequel, qui s'était authentifié au LDAP à un moment"
 * Typiquement dans une session on stocke l'identifiant de l'utilisateur (bien sûr) (mais ça peut aussi être pratique d'y mettre d'autres trucs)
 * 
 * La façon dont ce mécanisme est réalisé par passport peut paraître assez compliqué, ces deux liens en donnent une bonne explication
 * https://stackoverflow.com/questions/27637609/understanding-passport-serialize-deserialize#27637668
 * http://toon.io/understanding-passportjs-authentication-flow/
 * 
 * En gros l'idée est la suivante
 *   serializeUser spécifie comment créer une clé identifiant un user, qui sera stockée dans la session
 *   deserializeUser fait une requête vers une BDD de users en utilisant cette clé, et met dans l'objet JS req.user toutes les infos issues de la BDD
 * Cette répartition permet de ne stocker dans la session (i.e. en mémoire sur le serveur) que la clé des utilisateurs connectés et de ne "charger en mémoire" des infos de la BDD que lorsque nécessaire
 * 
 * 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)
 * (on pourrait penser que passer par deserializeUser permettrait de réduire le nombre d'interactions avec la BDD, mais en fait non car deserializeUser est appelé *a chaque requete*)
Guillaume WANG's avatar
Guillaume WANG committed
 */
import passport from 'passport';
import LdapStrategy from 'passport-ldapauth';
Olivér FACKLAM's avatar
Olivér FACKLAM committed
import { ldapConfig } from './ldap/internal/config';
console.log("Configuring passportjs... " + ldapConfig.server + " " + ldapConfig.dn.user);

// specifies options for 'ldapauth' strategy, to customize the behaviour of subsequent passport.authenticate('ldapauth') calls
passport.use(new LdapStrategy({
    server: {
        url: ldapConfig.server,
        //bindDn: '.............',
        //bindCredentials: '..........',
        searchBase: ldapConfig.dn.user, // this field cannot be left empty.
        searchFilter: '(uid={{username}})', // this field cannot be left empty.
        searchAttributes: ['uid', 'urlPhoto'], // only fetch the uid, no need for any other field
        tlsOptions: ldapConfig.tlsOptions,
        //https://www.npmjs.com/package/passport-ldapauth for more
    //usernameField: 'username', // Field name where the username is found, defaults to username
    //passwordField: 'password', // Field name where the password is found, defaults to password
Guillaume WANG's avatar
Guillaume WANG committed
    // no verify callback is needed, as we leave the authentication layer as simple as possible
    // we leave this, commented out, as a template for future use
    /*
    function (user, done) {
Guillaume WANG's avatar
Guillaume WANG committed
        // "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)
Guillaume WANG's avatar
Guillaume WANG committed
        // 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);
        }
    }
    */
Guillaume WANG's avatar
Guillaume WANG committed
/**
 * @desc passport.serializeUser(function(user, done) {...})
 * > LdapStrategy is only invoked on the route which uses the passport.authenticate middleware.
 * > Only during this authentication passport.serializeUser is invoked allowing us the specify what user information should be stored in the session
 * 
 * toujours bon a savoir pour faire des tests
 * after using expressSession(), the serialised user object [previously stored into session store by passport.authenticate] can be found at req.session.passport.user
 */
passport.serializeUser(function (user, done) {
Guillaume WANG's avatar
Guillaume WANG committed
    console.log(`passport.serializeUser(): serializing user ${user.uid}`); // DEBUG
    done(null, user.uid);
});

Guillaume WANG's avatar
Guillaume WANG committed
/**
 * @desc passport.deserializeUser(function(user, done) {...})
 * > passport.deserializeUser is invoked on every request by passport.session. 
 * > It enables us to load additional user information on every request.
 * > 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
    done(null, { uid: userUid });
Guillaume WANG's avatar
Guillaume WANG committed
});