From ef495aa4b5a9840400210adffba67af62aceb7af Mon Sep 17 00:00:00 2001 From: Marten de Vries Date: Fri, 25 Dec 2015 21:58:40 +0100 Subject: [PATCH] (#268) - pouchdb-auth update Switches from a session db to a cookie based session system, making user document changes invalidate the session. --- lib/config-infrastructure.js | 1 + lib/routes/authentication.js | 80 +++++++++++++++++++----------------- lib/routes/session.js | 23 +++-------- package.json | 2 +- 4 files changed, 50 insertions(+), 56 deletions(-) diff --git a/lib/config-infrastructure.js b/lib/config-infrastructure.js index d2b1dd4..be541d4 100644 --- a/lib/config-infrastructure.js +++ b/lib/config-infrastructure.js @@ -126,6 +126,7 @@ CouchConfig.prototype._changed = function (section, key, prevVal, callback) { // run event handlers self.emit(section + "." + key); + self.emit(section); callback(null, prevVal); }); diff --git a/lib/routes/authentication.js b/lib/routes/authentication.js index 46f6196..2182901 100644 --- a/lib/routes/authentication.js +++ b/lib/routes/authentication.js @@ -3,11 +3,10 @@ var cookieParser = require('cookie-parser'), basicAuth = require('basic-auth'), utils = require('../utils'), - uuids = require('../uuids'), - Promise = require('bluebird'); + Promise = require('bluebird'), + Auth = require('pouchdb-auth'); var SECTION = 'couch_httpd_auth'; -var KEY = 'authentication_db'; module.exports = function (app) { var usersDBPromise, refreshUsersDBImpl; @@ -15,19 +14,28 @@ module.exports = function (app) { utils.requires(app, 'config-infrastructure'); utils.requires(app, 'logging-infrastructure'); - app.couchConfig.registerDefault(SECTION, KEY, '_users'); + app.couchConfig.registerDefault(SECTION, 'authentication_db', '_users'); + app.couchConfig.registerDefault(SECTION, 'timeout', 600); + app.couchConfig.registerDefault(SECTION, 'secret', Auth.generateSecret()); + app.couchConfig.registerDefault(SECTION, 'iterations', 10); // explain how to activate the auth db logic. app.dbWrapper.registerWrapper(function (name, db, next) { if (name === getUsersDBName()) { - return db.useAsAuthenticationDB(); + return db.useAsAuthenticationDB({ + isOnlineAuthDB: false, + timeout: app.couchConfig.get(SECTION, 'timeout'), + secret: app.couchConfig.get(SECTION, 'secret'), + iterations: app.couchConfig.get(SECTION, 'iterations'), + admins: app.couchConfig.getSection('admins') + }); } return next(); }); app.daemonManager.registerDaemon({ start: function (PouchDB) { - PouchDB.plugin(require('pouchdb-auth')); + PouchDB.plugin(Auth); refreshUsersDBImpl = function () { usersDBPromise = utils.getUsersDB(app, PouchDB); @@ -44,6 +52,7 @@ module.exports = function (app) { var getUsersDBName = utils.getUsersDBName.bind(null, app); function getUsersDB() { + // calls itself until usersDBPromise is a available if (!usersDBPromise) { return new Promise(function (resolve) { setImmediate(function () { @@ -66,7 +75,11 @@ module.exports = function (app) { } // ensure there's always a users db - app.couchConfig.on(SECTION + '.' + KEY, refreshUsersDB); + app.couchConfig.on(SECTION + '.authentication_db', refreshUsersDB); + app.couchConfig.on(SECTION + '.timeout', refreshUsersDB); + app.couchConfig.on(SECTION + '.secret', refreshUsersDB); + app.couchConfig.on(SECTION + '.iterations', refreshUsersDB); + app.couchConfig.on('admins', refreshUsersDB); // routing app.use(cookieParser()); @@ -74,7 +87,7 @@ module.exports = function (app) { app.use(function (req, res, next) { // TODO: TIMING ATTACK Promise.resolve().then(function () { - return buildCookieSession(req); + return buildCookieSession(req, res); }).catch(function (err) { return buildBasicAuthSession(req); }).then(function (result) { @@ -86,22 +99,21 @@ module.exports = function (app) { }); }); - function buildCookieSession(req) { - var opts = { - sessionID: (req.cookies || {}).AuthSession, - admins: app.couchConfig.getSection("admins") - }; - if (!opts.sessionID) { + function buildCookieSession(req, res) { + var sessionID = (req.cookies || {}).AuthSession; + if (!sessionID) { throw new Error("No cookie, so no cookie auth."); } return getUsersDB().then(function (db) { - return db.session(opts); - }).then(function (result) { - if (result.info.authenticated) { - result.info.authenticated = 'cookie'; - logSuccess('cookie', result); + return db.multiUserSession(sessionID); + }).then(function (session) { + if (session.info.authenticated) { + res.cookie('AuthSession', session.sessionID, {httpOnly: true}); + delete session.sessionID; + session.info.authenticated = 'cookie'; + logSuccess('cookie', session); } - return result; + return session; }); } @@ -112,33 +124,25 @@ module.exports = function (app) { function buildBasicAuthSession(req) { var userInfo = basicAuth(req); - var opts = { - sessionID: uuids(1)[0], - admins: app.couchConfig.getSection("admins") - }; var db; var initializingDone = getUsersDB().then(function (theDB) { db = theDB; }); if (userInfo) { initializingDone = initializingDone.then(function () { - return db.logIn(userInfo.name, userInfo.pass, opts); + return db.multiUserLogIn(userInfo.name, userInfo.pass); }); } - var result; - return initializingDone.then(function () { - return db.session(opts); - }).then(function (theSession) { - result = theSession; - - // Cleanup - return db.logOut(opts); - }).then(function () { - if (result.info.authenticated) { - logSuccess('http basic', result); - result.info.authenticated = 'default'; + return initializingDone.then(function (info) { + return db.multiUserSession((info || {}).sessionID); + }).then(function (session) { + delete session.sessionID; + + if (session.info.authenticated) { + session.info.authenticated = 'default'; + logSuccess('http basic', session); } - return result; + return session; }); } }; diff --git a/lib/routes/session.js b/lib/routes/session.js index e175a8c..9c8297f 100644 --- a/lib/routes/session.js +++ b/lib/routes/session.js @@ -1,7 +1,6 @@ "use strict"; -var utils = require('../utils'), - uuids = require('../uuids'); +var utils = require('../utils'); module.exports = function (app) { utils.requires(app, 'routes/authentication'); @@ -18,14 +17,11 @@ module.exports = function (app) { function postHandler(req, res, next) { var name = req.body.name; var password = req.body.password; - var opts = { - sessionID: uuids(1)[0], - admins: app.couchConfig.getSection("admins") - }; getUsersDB(req).then(function (db) { - return db.logIn(name, password, opts); + return db.multiUserLogIn(name, password); }).then(function (resp) { - res.cookie('AuthSession', opts.sessionID, {httpOnly: true}); + res.cookie('AuthSession', resp.sessionID, {httpOnly: true}); + delete resp.sessionID; if (req.query.next) { utils.setLocation(res, req.query.next); return res.status(302).end(); @@ -38,14 +34,7 @@ module.exports = function (app) { app.post('/_session', utils.jsonParser, utils.urlencodedParser, postHandler); app.delete('/_session', function (req, res, next) { - var sessionID = (req.cookies || {}).AuthSession; - - getUsersDB(req).then(function (db) { - //no error handler necessary for log out - return db.logOut({sessionID: sessionID}); - }).then(function (resp) { - res.clearCookie('AuthSession'); - utils.sendJSON(res, 200, resp); - }); + res.clearCookie('AuthSession'); + utils.sendJSON(res, 200, {ok: true}); }); }; diff --git a/package.json b/package.json index b14fda4..32e908c 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "node-uuid": "1.4.1", "on-finished": "^2.1.1", "pouchdb-all-dbs": "^1.0.0", - "pouchdb-auth": "^1.0.2", + "pouchdb-auth": "^2.0.0", "pouchdb-find": "^0.1.0", "pouchdb-list": "^1.1.0", "pouchdb-replicator": "^2.1.0",