/** * @file Initialise et configure le serveur Express sur lequel tourne le back. * * La configuration inclut tout le _middleware_ définissant les API et les services * nécessaire utilisés, comme `express-session`, GraphiQL, GraphQL Voyager. * @author manifold */ import express from 'express'; import schema from './graphql/schema'; import { express as graphqlVoyager } from 'graphql-voyager/middleware'; import { graphqlExpress, graphiqlExpress } from 'apollo-server-express'; // new name of 'graphql-server-express'. cf npmjs.com import flash from 'connect-flash'; import { ensureLoggedIn } from 'connect-ensure-login'; 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 cors from 'cors'; const server = express(); // Parse incoming HTTP request bodies, available under the req.body property // cf www.npmjs.com/package/body-parser server.use(bodyParser.json()); //parses bodies of media type "application/json" server.use(bodyParser.urlencoded({ //parses bodies of media type "application/x-www-form-urlencoded" 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 * * 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 password is found, defaults to password passReqToCallback: true, // set verify callback to have req as the first argument function (req, user, done) { // "verify callback", called after each passport.authenticate(...) when the authentication succeeded if (user){ //if user exists } } }) ); // Définit les paramètres de stockage des sessions. server.use(session({ secret: config.sessionSecret, resave: true, saveUninitialized: false })); 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. server.disable('x-powered-by'); // setting up view engine for pug console.log("Running at",__dirname); let viewpath = path.resolve(__dirname,'views'); server.set('views', viewpath); server.set('view engine', 'pug'); // favicon: capital sigma symbol server.use(favicon(path.resolve('./','assets','favicon.ico'))); // specifies path to static assets server.use('/assets',express.static(path.resolve('./','assets'))); // Morgan is middleware for logging requests server.use(morgan('dev')); const defaultUser = require('./../ldap_connexion_config.json'); // Options de configuration pour le _middleware_ `cors`. // CORS = Cross Origin Resource Sharing const corsOptions = { origin: 'http://localhost:8888', // Configures the Access-Control-Allow-Origin CORS header. i.e. specifies that sigma-back wants to make resources accessible to this site (and this site only) credentials: true // Configures the Access-Control-Allow-Credentials CORS header. i.e. allows cookies to be included on cross-origin requests }; server.use(cors(corsOptions)); // Charge le middleware express pour GraphQL server.use('/graphql', bodyParser.json(), graphqlExpress(req => { // vary the options *on a per-request basis* // (options are passed by using req object as argument) let uid; let password; try { uid = req.user.uid; password = "mythe"; } catch (err) { uid = defaultUser.dn.split("=")[1].split(",")[0]; password = defaultUser.passwd; } // console.log("Accessing GraphQL as: ",uid); return { schema : schema, context: { user: { uid: uid, password: password } } // accessible in every single resolver as the third argument }; }) ); // GraphiQL est une console interactive pour faire des requêtes GraphQL à la BDD server.use('/graphiql', /*ensureLoggedIn('/login'),*/ graphiqlExpress({endpointURL: '/graphql'}) ); // GraphQL voyager affiche une représentation sous forme de graphe du schema GraphQL server.use('/voyager', /*ensureLoggedIn('/login'),*/ graphqlVoyager({ endpointUrl: '/graphql' }) ); // connect-flash is middleware for flashing messages // used in sigma-back's admin interface (admin_view) server.use(flash()); export default server;