From d712f571411def4236f5e32642cde0af93923c79 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 1 May 2013 21:03:37 -0400 Subject: [PATCH] refactored user authentication (passport-local, instead of my own half-baked implementation) --- package.json | 4 ++- public/templates/login.tpl | 35 ++++--------------- src/user.js | 53 +++++++++++++++++++++++++++++ src/webserver.js | 70 ++++++++++++++++++++++++++------------ src/websockets.js | 5 +-- 5 files changed, 114 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index a496ed42f6..645c519fe6 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,9 @@ "cookie": "0.0.6", "connect-redis": "1.4.5", "path": "0.4.9", - "crypto": "0.0.3" + "crypto": "0.0.3", + "passport": "0.1.16", + "passport-local": "0.1.6" }, "devDependencies": {}, "optionalDependencies": {}, diff --git a/public/templates/login.tpl b/public/templates/login.tpl index e9a96e7862..c430b90f17 100644 --- a/public/templates/login.tpl +++ b/public/templates/login.tpl @@ -4,33 +4,10 @@ Failed Login Attempt

-
-
-   +
+
+
+   +
Forgot Password? - - \ No newline at end of file + \ No newline at end of file diff --git a/src/user.js b/src/user.js index a743a39abe..6be93a4e99 100644 --- a/src/user.js +++ b/src/user.js @@ -76,6 +76,51 @@ var config = require('../config.js'), }); }; + User.loginViaLocal = function(username, password, next) { + if (!username || !password) { + return next({ + status: 'error', + message: 'invalid-user' + }); + } else { + RDB.get('username:' + username + ':uid', function(uid) { + if (uid == null) { + return next({ + status: 'error', + message: 'invalid-user' + }); + } + + RDB.get('uid:' + uid + ':password', function(user_password) { + if (password == user_password) { + // Start, replace, or extend a session + // RDB.get('sess:' + user.sessionID, function(session) { + // if (session !== user.sessionID) { + // RDB.set('sess:' + user.sessionID + ':uid', uid, 60*60*24*14); // Login valid for two weeks + // RDB.set('uid:' + uid + ':session', user.sessionID, 60*60*24*14); + // } else { + // RDB.expire('sess:' + user.sessionID + ':uid', 60*60*24*14); // Defer expiration to two weeks from now + // RDB.expire('uid:' + uid + ':session', 60*60*24*14); + // } + // }); + + next({ + status: "ok", + user: { + uid: uid + } + }); + } else { + next({ + status: 'error', + message: 'invalid-password' + }); + } + }); + }); + } + } + User.logout = function(sessionID, callback) { User.get_uid_by_session(sessionID, function(uid) { if (uid) { @@ -157,6 +202,14 @@ var config = require('../config.js'), RDB.get('sess:' + session + ':uid', callback); }; + User.session_ping = function(sessionID, uid) { + // Start, replace, or extend a session + RDB.get('sess:' + sessionID, function(session) { + RDB.set('sess:' + sessionID + ':uid', uid, 60*60*24*14); // Login valid for two weeks + RDB.set('uid:' + uid + ':session', sessionID, 60*60*24*14); + }); + } + User.reset = { validate: function(code, callback) { if (typeof callback !== 'function') callback = undefined; diff --git a/src/webserver.js b/src/webserver.js index e895b72200..13f626c67e 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -5,7 +5,26 @@ var express = require('express'), path = require('path'), config = require('../config.js'), redis = require('redis'), - redisServer = redis.createClient(config.redis.port, config.redis.host, config.redis.options); + redisServer = redis.createClient(config.redis.port, config.redis.host, config.redis.options), + passport = require('passport'), + passportLocal = require('passport-local').Strategy; + +passport.use(new passportLocal(function(user, password, next) { + global.modules.user.loginViaLocal(user, password, function(login) { + if (login.status === 'ok') next(null, login.user); + else next(null, false, login); + }); +})); + +passport.serializeUser(function(user, done) { + done(null, user.uid); +}); + +passport.deserializeUser(function(uid, done) { + done(null, { + uid: uid + }); +}); (function(app) { var templates = global.templates; @@ -32,26 +51,34 @@ var express = require('express'), secret: config.secret, key: 'express.sid' })); + app.use(passport.initialize()); + app.use(passport.session()); app.use(function(req, res, next) { // Don't bother with session handling for API requests if (/^\/api\//.test(req.url)) return next(); - if (req.session.uid === undefined) { - console.log('info: [Auth] First load, retrieving uid...'); - global.modules.user.get_uid_by_session(req.sessionID, function(uid) { - if (uid !== null) { - req.session.uid = uid; - console.log('info: [Auth] uid ' + req.session.uid + ' found. Welcome back.'); - } else { - req.session.uid = 0; - console.log('info: [Auth] No login session found.'); - } - }); - } else { - // console.log('SESSION: ' + req.sessionID); - // console.log('info: [Auth] Ping from uid ' + req.session.uid); + if (req.user && req.user.uid) { + console.log('** YOU ARE LOGGED IN AS UID: ' + req.user.uid + ' ***'); + global.modules.user.session_ping(req.sessionID, req.user.uid); } + // if (req.session.uid === undefined) { + // console.log('info: [Auth] First load, retrieving uid...'); + + // global.modules.user.get_uid_by_session(req.sessionID, function(uid) { + // if (uid !== null) { + // req.session.uid = uid; + // console.log('info: [Auth] uid ' + req.session.uid + ' found. Welcome back.'); + // } else { + // req.session.uid = 0; + // console.log('info: [Auth] No login session found.'); + // } + // }); + // } else { + // // console.log('SESSION: ' + req.sessionID); + // // console.log('info: [Auth] Ping from uid ' + req.session.uid); + // } + // (Re-)register the session as active global.modules.user.active.register(req.sessionID); @@ -100,16 +127,17 @@ var express = require('express'), res.send(templates['header'] + templates['login'] + templates['footer']); }); + app.post('/login', passport.authenticate('local', { + successRedirect: '/', + failureRedirect: '/login' + })); + app.get('/logout', function(req, res) { console.log('info: [Auth] Session ' + res.sessionID + ' logout (uid: ' + global.uid + ')'); global.modules.user.logout(req.sessionID, function(logout) { - if (logout === true) { - delete(req.session.uid); - req.session.destroy(); - } + req.logout(); + res.send(templates['header'] + templates['logout'] + templates['footer']); }); - - res.send(templates['header'] + templates['logout'] + templates['footer']); }); app.get('/reset/:code', function(req, res) { diff --git a/src/websockets.js b/src/websockets.js index ba6786fc80..a83fea5785 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -1,6 +1,7 @@ var SocketIO = require('socket.io').listen(global.server), cookie = require('cookie'), - connect = require('connect'); + connect = require('connect'), + config = require('../config.js'); (function(io) { var modules = null, @@ -16,7 +17,7 @@ var SocketIO = require('socket.io').listen(global.server), io.set('authorization', function(handshakeData, accept) { if (handshakeData.headers.cookie) { handshakeData.cookie = cookie.parse(handshakeData.headers.cookie); - handshakeData.sessionID = connect.utils.parseSignedCookie(handshakeData.cookie['express.sid'], 'nodebb'); + handshakeData.sessionID = connect.utils.parseSignedCookie(handshakeData.cookie['express.sid'], config.secret); if (handshakeData.cookie['express.sid'] == handshakeData.sessionID) { return accept('Cookie is invalid.', false);