Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Address Session Fixation Concerns #900

Merged
merged 28 commits into from May 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7e9b9cf
Regenerate session on login.
jaredhanson May 17, 2022
a7513c4
Fix tests.
jaredhanson May 17, 2022
a77271f
Regenerate session in logout.
jaredhanson May 18, 2022
9cde808
Save session on login before invoking callback.
jaredhanson May 18, 2022
c018dea
Clear user from old session on logout.
jaredhanson May 18, 2022
fa80b20
Fix tests.
jaredhanson May 18, 2022
fa70e2f
Error if session isn't available.
jaredhanson May 18, 2022
88c1f1b
Handle logout without session manager.
jaredhanson May 18, 2022
71c54f6
Add test.
jaredhanson May 19, 2022
cc7606c
Add tests.
jaredhanson May 19, 2022
ee0bf81
Add tests.
jaredhanson May 19, 2022
cfa8259
Add tests.
jaredhanson May 19, 2022
b395106
Clean up tests.
jaredhanson May 19, 2022
3001654
Add tests.
jaredhanson May 19, 2022
80cc4e3
Add tests.
jaredhanson May 19, 2022
294f22c
Better session detection and exceptions.
jaredhanson May 19, 2022
c1991cf
Add tests.
jaredhanson May 19, 2022
8825a9a
Add tests.
jaredhanson May 19, 2022
e69834e
Add optional options to login and logout.
jaredhanson May 19, 2022
a349c2b
Add option to keep session data.
jaredhanson May 19, 2022
17111d7
Add option to keep session data on logout.
jaredhanson May 19, 2022
bfba8a1
Add tests.
jaredhanson May 19, 2022
29a90d6
No need to guard callback existence.
jaredhanson May 19, 2022
f8a175f
Add tests.
jaredhanson May 19, 2022
987b191
Add tests.
jaredhanson May 19, 2022
46756e5
Silence verbose logging.
jaredhanson May 19, 2022
4f6bd5b
Change keepSessionData to keepSessionData.
jaredhanson May 19, 2022
8dd79fe
Use utils-merge rather than Object.assign for compatibility.
jaredhanson May 20, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 13 additions & 3 deletions lib/http/request.js
Expand Up @@ -36,7 +36,7 @@ req.logIn = function(user, options, done) {
if (typeof done != 'function') { throw new Error('req#login requires a callback function'); }

var self = this;
this._sessionManager.logIn(this, user, function(err) {
this._sessionManager.logIn(this, user, options, function(err) {
if (err) { self[property] = null; return done(err); }
done();
});
Expand All @@ -51,12 +51,22 @@ req.logIn = function(user, options, done) {
* @api public
*/
req.logout =
req.logOut = function() {
req.logOut = function(options, done) {
if (typeof options == 'function') {
done = options;
options = {};
}
options = options || {};

var property = this._userProperty || 'user';

this[property] = null;
if (this._sessionManager) {
this._sessionManager.logOut(this);
if (typeof done != 'function') { throw new Error('req#logout requires a callback function'); }

this._sessionManager.logOut(this, options, done);
} else {
done && done();
}
};

Expand Down
85 changes: 71 additions & 14 deletions lib/sessionmanager.js
@@ -1,3 +1,5 @@
var merge = require('utils-merge');

function SessionManager(options, serializeUser) {
if (typeof options == 'function') {
serializeUser = options;
Expand All @@ -9,30 +11,85 @@ function SessionManager(options, serializeUser) {
this._serializeUser = serializeUser;
}

SessionManager.prototype.logIn = function(req, user, cb) {
SessionManager.prototype.logIn = function(req, user, options, cb) {
if (typeof options == 'function') {
cb = options;
options = {};
}
options = options || {};

if (!req.session) { return cb(new Error('Login sessions require session support. Did you forget to use `express-session` middleware?')); }

var self = this;
this._serializeUser(user, req, function(err, obj) {
var prevSession = req.session;

// regenerate the session, which is good practice to help
// guard against forms of session fixation
req.session.regenerate(function(err) {
if (err) {
return cb(err);
}
// TODO: Error if session isn't available here.
if (!req.session) {
req.session = {};
}
if (!req.session[self._key]) {
req.session[self._key] = {};
}
req.session[self._key].user = obj;
cb();

self._serializeUser(user, req, function(err, obj) {
if (err) {
return cb(err);
}
if (options.keepSessionInfo) {
merge(req.session, prevSession);
}
if (!req.session[self._key]) {
req.session[self._key] = {};
}
// store user information in session, typically a user id
req.session[self._key].user = obj;
// save the session before redirection to ensure page
// load does not happen before session is saved
req.session.save(function(err) {
if (err) {
return cb(err);
}
cb();
});
});
});
}

SessionManager.prototype.logOut = function(req, cb) {
if (req.session && req.session[this._key]) {
SessionManager.prototype.logOut = function(req, options, cb) {
if (typeof options == 'function') {
cb = options;
options = {};
}
options = options || {};

if (!req.session) { return cb(new Error('Login sessions require session support. Did you forget to use `express-session` middleware?')); }

var self = this;

// clear the user from the session object and save.
// this will ensure that re-using the old session id
// does not have a logged in user
if (req.session[this._key]) {
delete req.session[this._key].user;
}
var prevSession = req.session;

cb && cb();
req.session.save(function(err) {
if (err) {
return cb(err)
}

// regenerate the session, which is good practice to help
// guard against forms of session fixation
req.session.regenerate(function(err) {
if (err) {
return cb(err);
}
if (options.keepSessionInfo) {
merge(req.session, prevSession);
}
cb();
});
});
}


Expand Down
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -36,7 +36,8 @@
"main": "./lib",
"dependencies": {
"passport-strategy": "1.x.x",
"pause": "0.0.1"
"pause": "0.0.1",
"utils-merge": "^1.0.1"
},
"devDependencies": {
"make-node": "0.3.x",
Expand Down