daniouyea
9/3/2012 - 5:12 PM

Express resources with authentication middleware

Express resources with authentication middleware

var express       = require('express');
var passport      = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var bcrypt        = require('bcrypt');
var routes        = require('./routes');

exports.boot = function (app) {
  bootApplication(app);
};

function bootApplication (app) {
  // Serialize User
  passport.serializeUser(function (user, done) {
    done(null, user._id);
  });

  // Deserialize User by loading them from the database
  passport.deserializeUser(function (id, done) {
    User.find(id, function (error, user) {
      done(error, user);
    });
  });

  // Set up the local passport strategy
  passport.use(new LocalStrategy(function (username, password, done) {
    process.nextTick(function () {
      User.findOne({ screen_name: username }, null, null, function (error, user) {
        if (error) return done(error);
        if (!user || (user && !user.password)) return done(null, false, { message: 'Unknown user: ' + username });
        bcrypt.compare(password, user.password, function (error, result) {
          if (result === true) {
            return done(null, user);
          }
          return done(null, false, { message: 'Invalid password' });
        });
      });
    });
  }));

  // Ensure that a user is authenticated
  function ensureAuthenticated (req, res, next) {
    var path, method, hierarchy, controller, action;
    if (req.isAuthenticated()) {
      if (req.user.is_admin === true) {
        return next();
      } else {
        if (!req.user.permissions) {
          console.log('%s: User %s has no permissions.', Date(Date.now()), req.user.screen_name);
          return res.redirect('/login');
        }
        method = req.route.method;
        path = req.route.path.substring(1).replace(/[\*]+/g, '');
        hierarchy = path.split('/');
        if (hierarchy.length == 1) {
          hierarchy[1] = 'index';
        }
        controller = hierarchy[0];
        action = hierarchy[1];
        if (req.user.permissions[controller] && req.user.permissions[controller][action]) {
          return next();
        } else {
          res.render('401', { title: '401 - Unauthorized', user: req.user });
        }
      }
    } else {
      res.redirect('/login');
    }
  }

  // Configure the application server
  app.configure(function () {
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.session({ secret: 'keyboard_cat' }));
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(require('stylus').middleware({ src: __dirname + '/public' }));
    app.use(app.router);
    app.use(express.static(__dirname + '/public'));
    app.enable('case sensitive routing');

    // Configure development environment
    app.configure('development', function () {
      app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
    });

    // Configure the production environment
    app.configure('production', function () {
      app.use(express.logger());
      app.use(express.errorHandler());
    });

    // Set up special routes handling
    app.get('/', routes.index);
    app.get('/login', routes.get_login);
    app.post('/login', passport.authenticate('local', { failureRedirect: '/login', failureFlash: true }), routes.post_login);
    app.get('/login/password', routes.get_password);
    app.post('/login/password', routes.post_password);
    app.get('/login/recover/:id', routes.get_recover);
    app.post('/login/recover/:id', routes.post_recover);
    app.get('/logout', routes.logout);
    app.get('/img/:name.svgz', function (req, res, next) {
      res.setHeader('Content-Encoding', 'x-gzip');
      next();
    });

    app.set('menu', config.menu);

    // Create resources for each menu item
    for (i in config.menu) {
      var item = config.menu[i], subitem;
      app.all('/' + item.name + '*', ensureAuthenticated, function (req, res, next) {
        next();
      });
      app.resource(item.name, require('./controllers/' + item.name));
      if (item.submenu) {
        for (j in item.submenu) {
          subitem = item.submenu[j];
          app.all('/' + item.name + '/' + subitem.name + '*', ensureAuthenticated, function (req, res, next) {
            next();
          });
          app.resource(item.name + '/' + subitem.name, require('./controllers/' + item.name + '/' + subitem.name));
        }
      }
    }
  });
}
module.exports = {
  menu: {
    'wall':  { title: 'Wall', name: 'wall' },
    'logs':  { title: 'Logs', name: 'logs', submenu: {
      'system': { title: 'System', name: 'system' }
    } },
    'stats': { title: 'Stats', name: 'stats' },
    'admin': { title: 'Admin', name: 'admin', submenu: {
      'users': { title: 'Users', name: 'users' },
      'grants': { title: 'Grants', name: 'grants' }
    } }
  }
};