diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml
new file mode 100644
index 00000000..a273f65a
--- /dev/null
+++ b/.github/workflows/node.yml
@@ -0,0 +1,42 @@
+# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
+# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
+
+name: Node.js CI
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ node-version:
+ - '17'
+ - '16'
+ - '14'
+ - '12'
+ - '10'
+ - '8'
+ - '6'
+ - '4'
+ # - '3' # io.js
+ # - '2' # io.js
+ # - '1' # io.js
+ - '0.12'
+ - '0.10'
+ # - '0.8'
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v2
+ with:
+ node-version: ${{ matrix.node-version }}
+ - run: npm install
+ - run: npm test
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 00000000..d3662771
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,76 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## [0.6.0] - 2022-05-20
+### Added
+- `authenticate()`, `req#login`, and `req#logout` accept a
+`keepSessionInfo: true` option to keep session information after regenerating
+the session.
+
+### Changed
+
+- `req#login()` and `req#logout()` regenerate the the session and clear session
+information by default.
+- `req#logout()` is now an asynchronous function and requires a callback
+function as the last argument.
+
+### Security
+
+- Improved robustness against session fixation attacks in cases where there is
+physical access to the same system or the application is susceptible to
+cross-site scripting (XSS).
+
+## [0.5.3] - 2022-05-16
+### Fixed
+
+- `initialize()` middleware extends request with `login()`, `logIn()`,
+`logout()`, `logOut()`, `isAuthenticated()`, and `isUnauthenticated()` functions
+again, reverting change from 0.5.1.
+
+## [0.5.2] - 2021-12-16
+### Fixed
+- Introduced a compatibility layer for strategies that depend directly on
+`passport@0.4.x` or earlier (such as `passport-azure-ad`), which were
+broken by the removal of private variables in `passport@0.5.1`.
+
+## [0.5.1] - 2021-12-15
+### Added
+- Informative error message in session strategy if session support is not
+available.
+
+### Changed
+
+- `authenticate()` middleware, rather than `initialize()` middleware, extends
+request with `login()`, `logIn()`, `logout()`, `logOut()`, `isAuthenticated()`,
+and `isUnauthenticated()` functions.
+
+## [0.5.0] - 2021-09-23
+### Changed
+
+- `initialize()` middleware extends request with `login()`, `logIn()`,
+`logout()`, `logOut()`, `isAuthenticated()`, and `isUnauthenticated()`
+functions.
+
+### Removed
+
+- `login()`, `logIn()`, `logout()`, `logOut()`, `isAuthenticated()`, and
+`isUnauthenticated()` functions no longer added to `http.IncomingMessage.prototype`.
+
+### Fixed
+
+- `userProperty` option to `initialize()` middleware only affects the current
+request, rather than all requests processed via singleton Passport instance,
+eliminating a race condition in situations where `initialize()` middleware is
+used multiple times in an application with `userProperty` set to different
+values.
+
+[Unreleased]: https://github.com/jaredhanson/passport/compare/v0.6.0...HEAD
+[0.6.0]: https://github.com/jaredhanson/passport/compare/v0.5.3...v0.6.0
+[0.5.3]: https://github.com/jaredhanson/passport/compare/v0.5.2...v0.5.3
+[0.5.2]: https://github.com/jaredhanson/passport/compare/v0.5.1...v0.5.2
+[0.5.1]: https://github.com/jaredhanson/passport/compare/v0.5.0...v0.5.1
diff --git a/LICENSE b/LICENSE
index ba9eb282..2a3ab4d5 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2011-2019 Jared Hanson
+Copyright (c) 2011-2021 Jared Hanson
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff --git a/Makefile b/Makefile
index d148666d..85ff65a6 100644
--- a/Makefile
+++ b/Makefile
@@ -21,5 +21,8 @@ clean: clean-docs clean-cov
clobber: clean
-rm -r node_modules
+html:
+ jsdoc -c etc/jsdoc.json -d ./doc $(SOURCES)
+
.PHONY: clean clobber
diff --git a/README.md b/README.md
index ffd80c08..e8b3bc87 100644
--- a/README.md
+++ b/README.md
@@ -17,11 +17,22 @@ hooks for controlling what occurs when authentication succeeds or fails.
Sponsors
-
- LoginRadius is built for the developer community to integrate robust Authentication and Single Sign-On in just a few lines of code.FREE Signup
-
Your app, enterprise-ready. Start selling to enterprise customers with just a few lines of code. Add Single Sign-On (and more) in minutes instead of months.
+
+
+
+
+
+
+
+
+
+ Drag and drop your auth Add authentication and user management to your consumer and business apps with a few lines of code.
+
+
+
+ Auth. Built for Devs, by Devs Add login, registration, SSO, MFA, and a bazillion other features to your app in minutes. Integrates with any codebase and installs on any server, anywhere in the world.
---
@@ -171,4 +182,4 @@ that build upon or integrate with Passport.
[The MIT License](http://opensource.org/licenses/MIT)
-Copyright (c) 2011-2019 Jared Hanson <[http://jaredhanson.net/](http://jaredhanson.net/)>
+Copyright (c) 2011-2021 Jared Hanson <[https://www.jaredhanson.me/](https://www.jaredhanson.me/)>
diff --git a/SPONSORS.md b/SPONSORS.md
index b4df8e6b..be45816a 100644
--- a/SPONSORS.md
+++ b/SPONSORS.md
@@ -1,11 +1,17 @@
## Gold Sponsors
-[![LoginRadius](https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/loginradius.png)](https://www.loginradius.com/)
-
[![WorkOS](https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/workos.png)](https://workos.com/)
+
+[![Snyk](https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/snyk.png)](https://snyk.io/)
## Sponsors
- [CodePilot.ai](https://codepilot.ai/)
+- [Jeremy Combs](https://github.com/jmcombs)
+- [Gadget](https://gadget.dev/)
- Kelly Burke
- [Matt Miller](https://mmiller.me/)
+
+## Past Sponsors
+
+- [LoginRadius](https://www.loginradius.com/)
diff --git a/etc/jsdoc.json b/etc/jsdoc.json
new file mode 100644
index 00000000..df0756c6
--- /dev/null
+++ b/etc/jsdoc.json
@@ -0,0 +1,3 @@
+{
+ "plugins": ["plugins/markdown"]
+}
diff --git a/lib/authenticator.js b/lib/authenticator.js
index 01605469..98e663c7 100644
--- a/lib/authenticator.js
+++ b/lib/authenticator.js
@@ -1,14 +1,13 @@
-/**
- * Module dependencies.
- */
+// Module dependencies.
var SessionStrategy = require('./strategies/session')
, SessionManager = require('./sessionmanager');
/**
- * `Authenticator` constructor.
+ * Create a new `Authenticator` object.
*
- * @api public
+ * @public
+ * @class
*/
function Authenticator() {
this._key = 'passport';
@@ -17,7 +16,6 @@ function Authenticator() {
this._deserializers = [];
this._infoTransformers = [];
this._framework = null;
- this._userProperty = 'user';
this.init();
}
@@ -25,28 +23,36 @@ function Authenticator() {
/**
* Initialize authenticator.
*
- * @api protected
+ * Initializes the `Authenticator` instance by creating the default `{@link SessionManager}`,
+ * {@link Authenticator#use `use()`}'ing the default `{@link SessionStrategy}`, and
+ * adapting it to work as {@link https://github.com/senchalabs/connect#readme Connect}-style
+ * middleware, which is also compatible with {@link https://expressjs.com/ Express}.
+ *
+ * @private
*/
Authenticator.prototype.init = function() {
this.framework(require('./framework/connect')());
- this.use(new SessionStrategy(this.deserializeUser.bind(this)));
+ this.use(new SessionStrategy({ key: this._key }, this.deserializeUser.bind(this)));
this._sm = new SessionManager({ key: this._key }, this.serializeUser.bind(this));
};
/**
- * Utilize the given `strategy` with optional `name`, overridding the strategy's
- * default name.
- *
- * Examples:
- *
- * passport.use(new TwitterStrategy(...));
- *
- * passport.use('api', new http.BasicStrategy(...));
- *
- * @param {String|Strategy} name
- * @param {Strategy} strategy
- * @return {Authenticator} for chaining
- * @api public
+ * Register a strategy for later use when authenticating requests. The name
+ * with which the strategy is registered is passed to {@link Authenticator#authenticate `authenticate()`}.
+ *
+ * @public
+ * @param {string} [name=strategy.name] - Name of the strategy. When specified,
+ * this value overrides the strategy's name.
+ * @param {Strategy} strategy - Authentication strategy.
+ * @returns {this}
+ *
+ * @example Register strategy.
+ * passport.use(new GoogleStrategy(...));
+ *
+ * @example Register strategy and override name.
+ * passport.use('password', new LocalStrategy(function(username, password, cb) {
+ * // ...
+ * }));
*/
Authenticator.prototype.use = function(name, strategy) {
if (!strategy) {
@@ -60,23 +66,18 @@ Authenticator.prototype.use = function(name, strategy) {
};
/**
- * Un-utilize the `strategy` with given `name`.
- *
- * In typical applications, the necessary authentication strategies are static,
- * configured once and always available. As such, there is often no need to
- * invoke this function.
- *
- * However, in certain situations, applications may need dynamically configure
- * and de-configure authentication strategies. The `use()`/`unuse()`
- * combination satisfies these scenarios.
+ * Deregister a strategy that was previously registered with the given name.
*
- * Examples:
+ * In a typical application, the necessary authentication strategies are
+ * registered when initializing the app and, once registered, are always
+ * available. As such, it is typically not necessary to call this function.
*
- * passport.unuse('legacy-api');
+ * @public
+ * @param {string} name - Name of the strategy.
+ * @returns {this}
*
- * @param {String} name
- * @return {Authenticator} for chaining
- * @api public
+ * @example
+ * passport.unuse('acme');
*/
Authenticator.prototype.unuse = function(name) {
delete this._strategies[name];
@@ -84,23 +85,15 @@ Authenticator.prototype.unuse = function(name) {
};
/**
- * Setup Passport to be used under framework.
- *
- * By default, Passport exposes middleware that operate using Connect-style
- * middleware using a `fn(req, res, next)` signature. Other popular frameworks
- * have different expectations, and this function allows Passport to be adapted
- * to operate within such environments.
- *
- * If you are using a Connect-compatible framework, including Express, there is
- * no need to invoke this function.
- *
- * Examples:
+ * Adapt this `Authenticator` to work with a specific framework.
*
- * passport.framework(require('hapi-passport')());
+ * By default, Passport works as {@link https://github.com/senchalabs/connect#readme Connect}-style
+ * middleware, which makes it compatible with {@link https://expressjs.com/ Express}.
+ * For any app built using Express, there is no need to call this function.
*
- * @param {Object} name
- * @return {Authenticator} for chaining
- * @api public
+ * @public
+ * @param {Object} fw
+ * @returns {this}
*/
Authenticator.prototype.framework = function(fw) {
this._framework = fw;
@@ -108,82 +101,104 @@ Authenticator.prototype.framework = function(fw) {
};
/**
- * Passport's primary initialization middleware.
- *
- * This middleware must be in use by the Connect/Express application for
- * Passport to operate.
- *
- * Options:
- * - `userProperty` Property to set on `req` upon login, defaults to _user_
- *
- * Examples:
- *
- * app.use(passport.initialize());
- *
- * app.use(passport.initialize({ userProperty: 'currentUser' }));
- *
- * @param {Object} options
- * @return {Function} middleware
- * @api public
+ * Create initialization middleware.
+ *
+ * Returns middleware that initializes Passport to authenticate requests.
+ *
+ * As of v0.6.x, it is typically no longer necessary to use this middleware. It
+ * exists for compatiblity with apps built using previous versions of Passport,
+ * in which this middleware was necessary.
+ *
+ * The primary exception to the above guidance is when using strategies that
+ * depend directly on `passport@0.4.x` or earlier. These earlier versions of
+ * Passport monkeypatch Node.js `http.IncomingMessage` in a way that expects
+ * certain Passport-specific properties to be available. This middleware
+ * provides a compatibility layer for this situation.
+ *
+ * @public
+ * @param {Object} [options]
+ * @param {string} [options.userProperty='user'] - Determines what property on
+ * `req` will be set to the authenticated user object.
+ * @param {boolean} [options.compat=true] - When `true`, enables a compatibility
+ * layer for packages that depend on `passport@0.4.x` or earlier.
+ * @returns {function}
+ *
+ * @example
+ * app.use(passport.initialize());
*/
Authenticator.prototype.initialize = function(options) {
options = options || {};
- this._userProperty = options.userProperty || 'user';
-
return this._framework.initialize(this, options);
};
/**
- * Middleware that will authenticate a request using the given `strategy` name,
- * with optional `options` and `callback`.
+ * Create authentication middleware.
*
- * Examples:
+ * Returns middleware that authenticates the request by applying the given
+ * strategy (or strategies).
*
- * passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' })(req, res);
+ * Examples:
*
* passport.authenticate('local', function(err, user) {
* if (!user) { return res.redirect('/login'); }
* res.end('Authenticated!');
* })(req, res);
*
- * passport.authenticate('basic', { session: false })(req, res);
- *
- * app.get('/auth/twitter', passport.authenticate('twitter'), function(req, res) {
- * // request will be redirected to Twitter
- * });
- * app.get('/auth/twitter/callback', passport.authenticate('twitter'), function(req, res) {
- * res.json(req.user);
- * });
- *
- * @param {String} strategy
- * @param {Object} options
- * @param {Function} callback
- * @return {Function} middleware
- * @api public
+ * @public
+ * @param {string|string[]|Strategy} strategy
+ * @param {Object} [options]
+ * @param {boolean} [options.session=true]
+ * @param {boolean} [options.keepSessionInfo=false]
+ * @param {string} [options.failureRedirect]
+ * @param {boolean|string|Object} [options.failureFlash=false]
+ * @param {boolean|string} [options.failureMessage=false]
+ * @param {boolean|string|Object} [options.successFlash=false]
+ * @param {string} [options.successReturnToOrRedirect]
+ * @param {string} [options.successRedirect]
+ * @param {boolean|string} [options.successMessage=false]
+ * @param {boolean} [options.failWithError=false]
+ * @param {string} [options.assignProperty]
+ * @param {boolean} [options.authInfo=true]
+ * @param {function} [callback]
+ * @returns {function}
+ *
+ * @example Authenticate username and password submitted via HTML form.
+ * app.get('/login/password', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' }));
+ *
+ * @example Authenticate bearer token used to access an API resource.
+ * app.get('/api/resource', passport.authenticate('bearer', { session: false }));
*/
Authenticator.prototype.authenticate = function(strategy, options, callback) {
return this._framework.authenticate(this, strategy, options, callback);
};
/**
- * Middleware that will authorize a third-party account using the given
- * `strategy` name, with optional `options`.
+ * Create third-party service authorization middleware.
*
- * If authorization is successful, the result provided by the strategy's verify
- * callback will be assigned to `req.account`. The existing login session and
- * `req.user` will be unaffected.
+ * Returns middleware that will authorize a connection to a third-party service.
*
- * This function is particularly useful when connecting third-party accounts
- * to the local account of a user that is currently authenticated.
+ * This middleware is identical to using {@link Authenticator#authenticate `authenticate()`}
+ * middleware with the `assignProperty` option set to `'account'`. This is
+ * useful when a user is already authenticated (for example, using a username
+ * and password) and they want to connect their account with a third-party
+ * service.
*
- * Examples:
+ * In this scenario, the user's third-party account will be set at
+ * `req.account`, and the existing `req.user` and login session data will be
+ * be left unmodified. A route handler can then link the third-party account to
+ * the existing local account.
*
- * passport.authorize('twitter-authz', { failureRedirect: '/account' });
+ * All arguments to this function behave identically to those accepted by
+ * `{@link Authenticator#authenticate}`.
*
- * @param {String} strategy
- * @param {Object} options
- * @return {Function} middleware
- * @api public
+ * @public
+ * @param {string|string[]|Strategy} strategy
+ * @param {Object} [options]
+ * @param {function} [callback]
+ * @returns {function}
+ *
+ * @example
+ * app.get('/oauth/callback/twitter', passport.authorize('twitter'));
*/
Authenticator.prototype.authorize = function(strategy, options, callback) {
options = options || {};
diff --git a/lib/framework/connect.js b/lib/framework/connect.js
index 5c5beb09..7d2db6e1 100644
--- a/lib/framework/connect.js
+++ b/lib/framework/connect.js
@@ -8,32 +8,15 @@ var initialize = require('../middleware/initialize')
* Framework support for Connect/Express.
*
* This module provides support for using Passport with Express. It exposes
- * middleware that conform to the `fn(req, res, next)` signature and extends
- * Node's built-in HTTP request object with useful authentication-related
- * functions.
+ * middleware that conform to the `fn(req, res, next)` signature.
*
* @return {Object}
* @api protected
*/
exports = module.exports = function() {
- // HTTP extensions.
- exports.__monkeypatchNode();
-
return {
initialize: initialize,
authenticate: authenticate
};
};
-
-exports.__monkeypatchNode = function() {
- var http = require('http');
- var IncomingMessageExt = require('../http/request');
-
- http.IncomingMessage.prototype.login =
- http.IncomingMessage.prototype.logIn = IncomingMessageExt.logIn;
- http.IncomingMessage.prototype.logout =
- http.IncomingMessage.prototype.logOut = IncomingMessageExt.logOut;
- http.IncomingMessage.prototype.isAuthenticated = IncomingMessageExt.isAuthenticated;
- http.IncomingMessage.prototype.isUnauthenticated = IncomingMessageExt.isUnauthenticated;
-};
diff --git a/lib/http/request.js b/lib/http/request.js
index 0206abb8..cdb5432f 100644
--- a/lib/http/request.js
+++ b/lib/http/request.js
@@ -1,10 +1,3 @@
-/**
- * Module dependencies.
- */
-//var http = require('http')
-// , req = http.IncomingMessage.prototype;
-
-
var req = exports = module.exports = {};
/**
@@ -35,19 +28,15 @@ req.logIn = function(user, options, done) {
}
options = options || {};
- var property = 'user';
- if (this._passport && this._passport.instance) {
- property = this._passport.instance._userProperty || 'user';
- }
+ var property = this._userProperty || 'user';
var session = (options.session === undefined) ? true : options.session;
this[property] = user;
- if (session) {
- if (!this._passport) { throw new Error('passport.initialize() middleware not in use'); }
+ if (session && this._sessionManager) {
if (typeof done != 'function') { throw new Error('req#login requires a callback function'); }
var self = this;
- this._passport.instance._sm.logIn(this, user, function(err) {
+ this._sessionManager.logIn(this, user, options, function(err) {
if (err) { self[property] = null; return done(err); }
done();
});
@@ -62,15 +51,22 @@ req.logIn = function(user, options, done) {
* @api public
*/
req.logout =
-req.logOut = function() {
- var property = 'user';
- if (this._passport && this._passport.instance) {
- property = this._passport.instance._userProperty || 'user';
+req.logOut = function(options, done) {
+ if (typeof options == 'function') {
+ done = options;
+ options = {};
}
+ options = options || {};
+
+ var property = this._userProperty || 'user';
this[property] = null;
- if (this._passport) {
- this._passport.instance._sm.logOut(this);
+ if (this._sessionManager) {
+ if (typeof done != 'function') { throw new Error('req#logout requires a callback function'); }
+
+ this._sessionManager.logOut(this, options, done);
+ } else {
+ done && done();
}
};
@@ -81,11 +77,7 @@ req.logOut = function() {
* @api public
*/
req.isAuthenticated = function() {
- var property = 'user';
- if (this._passport && this._passport.instance) {
- property = this._passport.instance._userProperty || 'user';
- }
-
+ var property = this._userProperty || 'user';
return (this[property]) ? true : false;
};
diff --git a/lib/index.js b/lib/index.js
index ab174691..dcfa770c 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -1,6 +1,4 @@
-/**
- * Module dependencies.
- */
+// Module dependencies.
var Passport = require('./authenticator')
, SessionStrategy = require('./strategies/session');
@@ -19,7 +17,7 @@ exports.Passport =
exports.Authenticator = Passport;
exports.Strategy = require('passport-strategy');
-/**
+/*
* Expose strategies.
*/
exports.strategies = {};
diff --git a/lib/middleware/authenticate.js b/lib/middleware/authenticate.js
index 841d2821..accdc0ae 100644
--- a/lib/middleware/authenticate.js
+++ b/lib/middleware/authenticate.js
@@ -92,11 +92,14 @@ module.exports = function authenticate(passport, name, options, callback) {
}
return function authenticate(req, res, next) {
- if (http.IncomingMessage.prototype.logIn
- && http.IncomingMessage.prototype.logIn !== IncomingMessageExt.logIn) {
- require('../framework/connect').__monkeypatchNode();
- }
+ req.login =
+ req.logIn = req.logIn || IncomingMessageExt.logIn;
+ req.logout =
+ req.logOut = req.logOut || IncomingMessageExt.logOut;
+ req.isAuthenticated = req.isAuthenticated || IncomingMessageExt.isAuthenticated;
+ req.isUnauthenticated = req.isUnauthenticated || IncomingMessageExt.isUnauthenticated;
+ req._sessionManager = passport._sm;
// accumulator for failures from each strategy in the chain
var failures = [];
diff --git a/lib/middleware/initialize.js b/lib/middleware/initialize.js
index 53ce3d86..0b6306df 100644
--- a/lib/middleware/initialize.js
+++ b/lib/middleware/initialize.js
@@ -1,3 +1,9 @@
+/**
+ * Module dependencies.
+ */
+var IncomingMessageExt = require('../http/request');
+
+
/**
* Passport initialization.
*
@@ -39,17 +45,56 @@
* @return {Function}
* @api public
*/
-module.exports = function initialize(passport) {
+module.exports = function initialize(passport, options) {
+ options = options || {};
return function initialize(req, res, next) {
- req._passport = {};
- req._passport.instance = passport;
-
- if (req.session && req.session[passport._key]) {
- // load data from existing session
- req._passport.session = req.session[passport._key];
+ req.login =
+ req.logIn = req.logIn || IncomingMessageExt.logIn;
+ req.logout =
+ req.logOut = req.logOut || IncomingMessageExt.logOut;
+ req.isAuthenticated = req.isAuthenticated || IncomingMessageExt.isAuthenticated;
+ req.isUnauthenticated = req.isUnauthenticated || IncomingMessageExt.isUnauthenticated;
+
+ req._sessionManager = passport._sm;
+
+ if (options.userProperty) {
+ req._userProperty = options.userProperty;
}
-
+
+ var compat = (options.compat === undefined) ? true : options.compat;
+ if (compat) {
+ // `passport@0.5.1` [removed][1] all internal use of `req._passport`.
+ // From the standpoint of this package, this should have been a
+ // non-breaking change. However, some strategies (such as `passport-azure-ad`)
+ // depend directly on `passport@0.4.x` or earlier. `require`-ing earlier
+ // versions of `passport` has the effect of monkeypatching `http.IncomingMessage`
+ // with `logIn`, `logOut`, `isAuthenticated` and `isUnauthenticated`
+ // functions that [expect][2] the `req._passport` property to exist.
+ // Since pre-existing functions on `req` are given [preference][3], this
+ // results in [issues][4].
+ //
+ // The changes here restore the expected properties needed when earlier
+ // versions of `passport` are `require`-ed. This compatibility mode is
+ // enabled by default, and can be disabld by simply not `use`-ing `passport.initialize()`
+ // middleware or setting `compat: false` as an option to the middleware.
+ //
+ // An alternative approach to addressing this issue would be to not
+ // preferentially use pre-existing functions on `req`, but rather always
+ // overwrite `req.logIn`, etc. with the versions of those functions shiped
+ // with `authenticate()` middleware. This option should be reconsidered
+ // in a future major version release.
+ //
+ // [1]: https://github.com/jaredhanson/passport/pull/875
+ // [2]: https://github.com/jaredhanson/passport/blob/v0.4.1/lib/http/request.js
+ // [3]: https://github.com/jaredhanson/passport/blob/v0.5.1/lib/middleware/authenticate.js#L96
+ // [4]: https://github.com/jaredhanson/passport/issues/877
+ passport._userProperty = options.userProperty || 'user';
+
+ req._passport = {};
+ req._passport.instance = passport;
+ }
+
next();
};
};
diff --git a/lib/sessionmanager.js b/lib/sessionmanager.js
index 0fdbd8bd..81b59b1d 100644
--- a/lib/sessionmanager.js
+++ b/lib/sessionmanager.js
@@ -1,3 +1,5 @@
+var merge = require('utils-merge');
+
function SessionManager(options, serializeUser) {
if (typeof options == 'function') {
serializeUser = options;
@@ -9,29 +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);
}
- if (!req._passport.session) {
- req._passport.session = {};
- }
- req._passport.session.user = obj;
- if (!req.session) {
- req.session = {};
- }
- req.session[self._key] = req._passport.session;
- 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._passport && req._passport.session) {
- delete req._passport.session.user;
+SessionManager.prototype.logOut = function(req, options, cb) {
+ if (typeof options == 'function') {
+ cb = options;
+ options = {};
}
- cb && cb();
+ 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;
+
+ 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();
+ });
+ });
}
diff --git a/lib/strategies/session.js b/lib/strategies/session.js
index 92b57923..af8cc07c 100644
--- a/lib/strategies/session.js
+++ b/lib/strategies/session.js
@@ -1,15 +1,43 @@
-/**
- * Module dependencies.
- */
+// Module dependencies.
var pause = require('pause')
, util = require('util')
, Strategy = require('passport-strategy');
/**
- * `SessionStrategy` constructor.
+ * Create a new `SessionStrategy` object.
+ *
+ * An instance of this strategy is automatically used when creating an
+ * `{@link Authenticator}`. As such, it is typically unnecessary to create an
+ * instance using this constructor.
+ *
+ * @classdesc This `Strategy` authenticates HTTP requests based on the contents
+ * of session data.
*
- * @api public
+ * The login session must have been previously initiated, typically upon the
+ * user interactively logging in using a HTML form. During session initiation,
+ * the logged-in user's information is persisted to the session so that it can
+ * be restored on subsequent requests.
+ *
+ * Note that this strategy merely restores the authentication state from the
+ * session, it does not authenticate the session itself. Authenticating the
+ * underlying session is assumed to have been done by the middleware
+ * implementing session support. This is typically accomplished by setting a
+ * signed cookie, and verifying the signature of that cookie on incoming
+ * requests.
+ *
+ * In {@link https://expressjs.com/ Express}-based apps, session support is
+ * commonly provided by {@link https://github.com/expressjs/session `express-session`}
+ * or {@link https://github.com/expressjs/cookie-session `cookie-session`}.
+ *
+ * @public
+ * @class
+ * @augments base.Strategy
+ * @param {Object} [options]
+ * @param {string} [options.key='passport'] - Determines what property ("key") on
+ * the session data where login session data is located. The login
+ * session is stored and read from `req.session[key]`.
+ * @param {function} deserializeUser - Function which deserializes user.
*/
function SessionStrategy(options, deserializeUser) {
if (typeof options == 'function') {
@@ -19,36 +47,60 @@ function SessionStrategy(options, deserializeUser) {
options = options || {};
Strategy.call(this);
+
+ /** The name of the strategy, set to `'session'`.
+ *
+ * @type {string}
+ * @readonly
+ */
this.name = 'session';
+ this._key = options.key || 'passport';
this._deserializeUser = deserializeUser;
}
-/**
- * Inherit from `Strategy`.
- */
+// Inherit from `passport.Strategy`.
util.inherits(SessionStrategy, Strategy);
/**
- * Authenticate request based on the current session state.
+ * Authenticate request based on current session data.
+ *
+ * When login session data is present in the session, that data will be used to
+ * restore login state across across requests by calling the deserialize user
+ * function.
+ *
+ * If login session data is not present, the request will be passed to the next
+ * middleware, rather than failing authentication - which is the behavior of
+ * most other strategies. This deviation allows session authentication to be
+ * performed at the application-level, rather than the individual route level,
+ * while allowing both authenticated and unauthenticated requests and rendering
+ * responses accordingly. Routes that require authentication will need to guard
+ * that condition.
*
- * The session authentication strategy uses the session to restore any login
- * state across requests. If a login session has been established, `req.user`
- * will be populated with the current user.
+ * This function is protected, and should not be called directly. Instead,
+ * use `passport.authenticate()` middleware and specify the {@link SessionStrategy#name `name`}
+ * of this strategy and any options.
*
- * This strategy is registered automatically by Passport.
+ * @protected
+ * @param {http.IncomingMessage} req - The Node.js {@link https://nodejs.org/api/http.html#class-httpincomingmessage `IncomingMessage`}
+ * object.
+ * @param {Object} [options]
+ * @param {boolean} [options.pauseStream=false] - When `true`, data events on
+ * the request will be paused, and then resumed after the asynchronous
+ * `deserializeUser` function has completed. This is only necessary in
+ * cases where later middleware in the stack are listening for events,
+ * and ensures that those events are not missed.
*
- * @param {Object} req
- * @param {Object} options
- * @api protected
+ * @example
+ * passport.authenticate('session');
*/
SessionStrategy.prototype.authenticate = function(req, options) {
- if (!req._passport) { return this.error(new Error('passport.initialize() middleware not in use')); }
+ if (!req.session) { return this.error(new Error('Login sessions require session support. Did you forget to use `express-session` middleware?')); }
options = options || {};
var self = this,
su;
- if (req._passport.session) {
- su = req._passport.session.user;
+ if (req.session[this._key]) {
+ su = req.session[this._key].user;
}
if (su || su === 0) {
@@ -60,10 +112,9 @@ SessionStrategy.prototype.authenticate = function(req, options) {
this._deserializeUser(su, req, function(err, user) {
if (err) { return self.error(err); }
if (!user) {
- delete req._passport.session.user;
+ delete req.session[self._key].user;
} else {
- // TODO: Remove instance access
- var property = req._passport.instance._userProperty || 'user';
+ var property = req._userProperty || 'user';
req[property] = user;
}
self.pass();
@@ -76,8 +127,5 @@ SessionStrategy.prototype.authenticate = function(req, options) {
}
};
-
-/**
- * Expose `SessionStrategy`.
- */
+// Export `SessionStrategy`.
module.exports = SessionStrategy;
diff --git a/package.json b/package.json
index e6d8b926..3bef6d3d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "passport",
- "version": "0.4.1",
+ "version": "0.6.0",
"description": "Simple, unobtrusive authentication for Node.js.",
"keywords": [
"express",
@@ -12,27 +12,32 @@
"author": {
"name": "Jared Hanson",
"email": "jaredhanson@gmail.com",
- "url": "http://www.jaredhanson.net/"
+ "url": "https://www.jaredhanson.me/"
},
- "homepage": "http://passportjs.org/",
+ "homepage": "https://www.passportjs.org/",
"repository": {
"type": "git",
"url": "git://github.com/jaredhanson/passport.git"
},
"bugs": {
- "url": "http://github.com/jaredhanson/passport/issues"
+ "url": "https://github.com/jaredhanson/passport/issues"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/jaredhanson"
},
"license": "MIT",
"licenses": [
{
"type": "MIT",
- "url": "http://opensource.org/licenses/MIT"
+ "url": "https://opensource.org/licenses/MIT"
}
],
"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",
diff --git a/sponsors/descope-dark.svg b/sponsors/descope-dark.svg
new file mode 100644
index 00000000..fe58596d
--- /dev/null
+++ b/sponsors/descope-dark.svg
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sponsors/descope.svg b/sponsors/descope.svg
new file mode 100644
index 00000000..c21f203d
--- /dev/null
+++ b/sponsors/descope.svg
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sponsors/fusionauth.png b/sponsors/fusionauth.png
new file mode 100644
index 00000000..da471b83
Binary files /dev/null and b/sponsors/fusionauth.png differ
diff --git a/sponsors/fusionauth.svg b/sponsors/fusionauth.svg
new file mode 100644
index 00000000..da4b8f77
--- /dev/null
+++ b/sponsors/fusionauth.svg
@@ -0,0 +1,171 @@
+
+
+
+image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sponsors/snyk.png b/sponsors/snyk.png
new file mode 100644
index 00000000..b14de59b
Binary files /dev/null and b/sponsors/snyk.png differ
diff --git a/sponsors/workos.png b/sponsors/workos.png
index 3afdfbae..514b691e 100644
Binary files a/sponsors/workos.png and b/sponsors/workos.png differ
diff --git a/test/authenticator.middleware.test.js b/test/authenticator.middleware.test.js
index 580759f4..a6d77ef0 100644
--- a/test/authenticator.middleware.test.js
+++ b/test/authenticator.middleware.test.js
@@ -35,22 +35,20 @@ describe('Authenticator', function() {
expect(error).to.be.undefined;
});
- it('should set user property on authenticator', function() {
- expect(passport._userProperty).to.equal('user');
+ it('should not set user property on request', function() {
+ expect(request._userProperty).to.be.undefined;
});
it('should not initialize namespace within session', function() {
expect(request.session.passport).to.be.undefined;
});
-
+
it('should expose authenticator on internal request property', function() {
expect(request._passport).to.be.an('object');
expect(request._passport.instance).to.be.an.instanceOf(Authenticator);
expect(request._passport.instance).to.equal(passport);
- });
-
- it('should not expose session storage on internal request property', function() {
- expect(request._passport.session).to.be.undefined;
+ expect(request._passport.instance._sm).to.be.an('object');
+ expect(request._passport.instance._userProperty).to.equal('user');
});
});
@@ -75,22 +73,20 @@ describe('Authenticator', function() {
expect(error).to.be.undefined;
});
- it('should set user property on authenticator', function() {
- expect(passport._userProperty).to.equal('currentUser');
+ it('should set user property on request', function() {
+ expect(request._userProperty).to.equal('currentUser');
});
it('should not initialize namespace within session', function() {
expect(request.session.passport).to.be.undefined;
});
-
+
it('should expose authenticator on internal request property', function() {
expect(request._passport).to.be.an('object');
expect(request._passport.instance).to.be.an.instanceOf(Authenticator);
expect(request._passport.instance).to.equal(passport);
- });
-
- it('should not expose session storage on internal request property', function() {
- expect(request._passport.session).to.be.undefined;
+ expect(request._passport.instance._sm).to.be.an('object');
+ expect(request._passport.instance._userProperty).to.equal('currentUser');
});
});
@@ -278,8 +274,9 @@ describe('Authenticator', function() {
req._passport = {};
req._passport.instance = {};
- req._passport.session = {};
- req._passport.session.user = '123456';
+ req.session = {};
+ req.session['passport'] = {};
+ req.session['passport'].user = '123456';
})
.next(function(err) {
error = err;
@@ -298,8 +295,8 @@ describe('Authenticator', function() {
});
it('should maintain session', function() {
- expect(request._passport.session).to.be.an('object');
- expect(request._passport.session.user).to.equal('123456');
+ expect(request.session['passport']).to.be.an('object');
+ expect(request.session['passport'].user).to.equal('123456');
});
});
diff --git a/test/http/request.test.js b/test/http/request.test.js
index f268ee5e..d94dc9f2 100644
--- a/test/http/request.test.js
+++ b/test/http/request.test.js
@@ -1,14 +1,14 @@
/* global describe, it, expect, before */
/* jshint expr: true */
-var http = require('http')
+var request = require('../../lib/http/request')
, Passport = require('../..').Passport;
-require('../../lib/framework/connect').__monkeypatchNode();
-
describe('http.ServerRequest', function() {
+ // TODO: Test that these are extended by initialize/authenticate
+ /*
describe('prototoype', function() {
var req = new http.IncomingMessage();
@@ -30,16 +30,21 @@ describe('http.ServerRequest', function() {
expect(req.isUnauthenticated).to.be.an('function');
});
});
+ */
describe('#login', function() {
describe('not establishing a session', function() {
var passport = new Passport();
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.login = request.login;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
req._passport = {};
req._passport.instance = passport;
- req._passport.session = {};
+ req.session = {};
+ req.session['passport'] = {};
var error;
@@ -68,18 +73,22 @@ describe('http.ServerRequest', function() {
});
it('should not serialize user', function() {
- expect(req._passport.session.user).to.be.undefined;
+ expect(req.session['passport'].user).to.be.undefined;
});
});
describe('not establishing a session and setting custom user property', function() {
var passport = new Passport();
- passport._userProperty = 'currentUser';
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.login = request.login;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
req._passport = {};
req._passport.instance = passport;
- req._passport.session = {};
+ req.session = {};
+ req.session['passport'] = {};
+ req._userProperty = 'currentUser';
var error;
@@ -112,17 +121,21 @@ describe('http.ServerRequest', function() {
});
it('should not serialize user', function() {
- expect(req._passport.session.user).to.be.undefined;
+ expect(req.session['passport'].user).to.be.undefined;
});
});
describe('not establishing a session and invoked without a callback', function() {
var passport = new Passport();
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.login = request.login;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
req._passport = {};
req._passport.instance = passport;
- req._passport.session = {};
+ req.session = {};
+ req.session['passport'] = {};
var user = { id: '1', username: 'root' };
req.login(user, { session: false });
@@ -139,12 +152,15 @@ describe('http.ServerRequest', function() {
});
it('should not serialize user', function() {
- expect(req._passport.session.user).to.be.undefined;
+ expect(req.session['passport'].user).to.be.undefined;
});
});
describe('not establishing a session, without passport.initialize() middleware', function() {
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.login = request.login;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
var error;
@@ -179,10 +195,21 @@ describe('http.ServerRequest', function() {
done(null, user.id);
});
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.login = request.login;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
req._passport = {};
req._passport.instance = passport;
- req._passport.session = {};
+ req._sessionManager = passport._sm;
+ req.session = { id: '1' };
+ req.session.regenerate = function(cb) {
+ req.session = { id: '2' };
+ req.session.save = function(cb) {
+ process.nextTick(cb);
+ };
+ process.nextTick(cb);
+ };
var error;
@@ -204,6 +231,134 @@ describe('http.ServerRequest', function() {
expect(req.isUnauthenticated()).to.be.false;
});
+ it('should regenerate session', function() {
+ expect(req.session.id).to.equal('2');
+ });
+
+ it('should set user', function() {
+ expect(req.user).to.be.an('object');
+ expect(req.user.id).to.equal('1');
+ expect(req.user.username).to.equal('root');
+ });
+
+ it('should serialize user', function() {
+ expect(req.session['passport'].user).to.equal('1');
+ });
+ });
+
+ describe('establishing a session and not keeping previous session data', function() {
+ var passport = new Passport();
+ passport.serializeUser(function(user, done) {
+ done(null, user.id);
+ });
+
+ var req = new Object();
+ req.login = request.login;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
+ req._passport = {};
+ req._passport.instance = passport;
+ req._sessionManager = passport._sm;
+ req.session = { cart: [ '1', '2', ] };
+ Object.defineProperty(req.session, 'id', { value: '1' });
+ req.session.regenerate = function(cb) {
+ req.session = { id: '2' };
+ req.session.save = function(cb) {
+ process.nextTick(cb);
+ };
+ process.nextTick(cb);
+ };
+
+ var error;
+
+ before(function(done) {
+ var user = { id: '1', username: 'root' };
+
+ req.login(user, function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should not error', function() {
+ expect(error).to.be.undefined;
+ });
+
+ it('should be authenticated', function() {
+ expect(req.isAuthenticated()).to.be.true;
+ expect(req.isUnauthenticated()).to.be.false;
+ });
+
+ it('should regenerate session', function() {
+ expect(req.session.id).to.equal('2');
+ });
+
+ it('should not keep session data', function() {
+ expect(req.session.cart).to.be.undefined;
+ });
+
+ it('should set user', function() {
+ expect(req.user).to.be.an('object');
+ expect(req.user.id).to.equal('1');
+ expect(req.user.username).to.equal('root');
+ });
+
+ it('should serialize user', function() {
+ expect(req.session['passport'].user).to.equal('1');
+ });
+ });
+
+ describe('establishing a session and keeping previous session data', function() {
+ var passport = new Passport();
+ passport.serializeUser(function(user, done) {
+ done(null, user.id);
+ });
+
+ var req = new Object();
+ req.login = request.login;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
+ req._passport = {};
+ req._passport.instance = passport;
+ req._sessionManager = passport._sm;
+ req.session = { cart: [ '1', '2', ] };
+ Object.defineProperty(req.session, 'id', { value: '1' });
+ req.session.regenerate = function(cb) {
+ req.session = { id: '2' };
+ req.session.save = function(cb) {
+ process.nextTick(cb);
+ };
+ process.nextTick(cb);
+ };
+
+ var error;
+
+ before(function(done) {
+ var user = { id: '1', username: 'root' };
+
+ req.login(user, { keepSessionInfo: true }, function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should not error', function() {
+ expect(error).to.be.undefined;
+ });
+
+ it('should be authenticated', function() {
+ expect(req.isAuthenticated()).to.be.true;
+ expect(req.isUnauthenticated()).to.be.false;
+ });
+
+ it('should regenerate session', function() {
+ expect(req.session.id).to.equal('2');
+ });
+
+ it('should keep session data', function() {
+ expect(req.session.cart).to.deep.equal([ '1', '2' ]);
+ });
+
it('should set user', function() {
expect(req.user).to.be.an('object');
expect(req.user.id).to.equal('1');
@@ -211,7 +366,7 @@ describe('http.ServerRequest', function() {
});
it('should serialize user', function() {
- expect(req._passport.session.user).to.equal('1');
+ expect(req.session['passport'].user).to.equal('1');
});
});
@@ -220,12 +375,23 @@ describe('http.ServerRequest', function() {
passport.serializeUser(function(user, done) {
done(null, user.id);
});
- passport._userProperty = 'currentUser';
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.login = request.login;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
req._passport = {};
req._passport.instance = passport;
- req._passport.session = {};
+ req._sessionManager = passport._sm;
+ req.session = { id: '1' };
+ req.session.regenerate = function(cb) {
+ req.session = { id: '2' };
+ req.session.save = function(cb) {
+ process.nextTick(cb);
+ };
+ process.nextTick(cb);
+ }
+ req._userProperty = 'currentUser';
var error;
@@ -247,6 +413,10 @@ describe('http.ServerRequest', function() {
expect(req.isUnauthenticated()).to.be.false;
});
+ it('should regenerate session', function() {
+ expect(req.session.id).to.equal('2');
+ });
+
it('should not set user', function() {
expect(req.user).to.be.undefined;
});
@@ -258,7 +428,62 @@ describe('http.ServerRequest', function() {
});
it('should serialize user', function() {
- expect(req._passport.session.user).to.equal('1');
+ expect(req.session['passport'].user).to.equal('1');
+ });
+ });
+
+ describe('encountering an error when regenerating session', function() {
+ var passport = new Passport();
+ passport.serializeUser(function(user, done) {
+ done(null, user.id);
+ });
+
+ var req = new Object();
+ req.login = request.login;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
+ req._passport = {};
+ req._passport.instance = passport;
+ req._sessionManager = passport._sm;
+ req.session = { id: '1' };
+ req.session['passport'] = {};
+ req.session.regenerate = function(cb) {
+ process.nextTick(function(){
+ cb(new Error('something went wrong'));
+ })
+ }
+
+ var error;
+
+ before(function(done) {
+ var user = { id: '1', username: 'root' };
+
+ req.login(user, function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should error', function() {
+ expect(error).to.be.an.instanceOf(Error);
+ expect(error.message).to.equal('something went wrong');
+ });
+
+ it('should not be authenticated', function() {
+ expect(req.isAuthenticated()).to.be.false;
+ expect(req.isUnauthenticated()).to.be.true;
+ });
+
+ it('should not regenerate session', function() {
+ expect(req.session.id).to.equal('1');
+ });
+
+ it('should not set user', function() {
+ expect(req.user).to.be.null;
+ });
+
+ it('should not serialize user', function() {
+ expect(req.session['passport'].user).to.be.undefined;
});
});
@@ -268,10 +493,19 @@ describe('http.ServerRequest', function() {
done(new Error('something went wrong'));
});
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.login = request.login;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
req._passport = {};
req._passport.instance = passport;
- req._passport.session = {};
+ req._sessionManager = passport._sm;
+ req.session = { id: '1' };
+ req.session['passport'] = {};
+ req.session.regenerate = function(cb) {
+ req.session = { id: '2' };
+ process.nextTick(cb);
+ }
var error;
@@ -294,17 +528,82 @@ describe('http.ServerRequest', function() {
expect(req.isUnauthenticated()).to.be.true;
});
+ it('should regenerate session', function() {
+ expect(req.session.id).to.equal('2');
+ });
+
it('should not set user', function() {
expect(req.user).to.be.null;
});
it('should not serialize user', function() {
- expect(req._passport.session.user).to.be.undefined;
+ expect(req.session['passport']).to.be.undefined;
});
});
+ describe('encountering an error when saving session', function() {
+ var passport = new Passport();
+ passport.serializeUser(function(user, done) {
+ done(null, user.id);
+ });
+
+ var req = new Object();
+ req.login = request.login;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
+ req._passport = {};
+ req._passport.instance = passport;
+ req._sessionManager = passport._sm;
+ req.session = { id: '1' };
+ req.session['passport'] = {};
+ req.session.regenerate = function(cb) {
+ req.session = { id: '2' };
+ req.session.save = function(cb) {
+ process.nextTick(function(){
+ cb(new Error('something went wrong'));
+ });
+ };
+ process.nextTick(cb);
+ }
+
+ var error;
+
+ before(function(done) {
+ var user = { id: '1', username: 'root' };
+
+ req.login(user, function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should error', function() {
+ expect(error).to.be.an.instanceOf(Error);
+ expect(error.message).to.equal('something went wrong');
+ });
+
+ it('should not be authenticated', function() {
+ expect(req.isAuthenticated()).to.be.false;
+ expect(req.isUnauthenticated()).to.be.true;
+ });
+
+ it('should not regenerate session', function() {
+ expect(req.session.id).to.equal('2');
+ });
+
+ it('should not set user', function() {
+ expect(req.user).to.be.null;
+ });
+
+ it('should not serialize user', function() {
+ expect(req.session['passport'].user).to.equal('1');
+ });
+ });
+
+ /*
describe('establishing a session, without passport.initialize() middleware', function() {
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.login = request.login;
var user = { id: '1', username: 'root' };
it('should throw an exception', function() {
@@ -313,6 +612,7 @@ describe('http.ServerRequest', function() {
}).to.throw(Error, 'passport.initialize() middleware not in use');
});
});
+ */
describe('establishing a session, but not passing a callback argument', function() {
var passport = new Passport();
@@ -320,10 +620,13 @@ describe('http.ServerRequest', function() {
done(null, user.id);
});
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.login = request.login;
req._passport = {};
req._passport.instance = passport;
- req._passport.session = {};
+ req._sessionManager = passport._sm;
+ req.session = {};
+ req.session['passport'] = {};
var user = { id: '1', username: 'root' };
@@ -334,6 +637,35 @@ describe('http.ServerRequest', function() {
});
});
+ describe('establishing a session without session support', function() {
+ var passport = new Passport();
+ passport.serializeUser(function(user, done) {
+ done(null, user.id);
+ });
+
+ var req = new Object();
+ req.login = request.login;
+ req._passport = {};
+ req._passport.instance = passport;
+ req._sessionManager = passport._sm;
+
+ var error;
+
+ before(function(done) {
+ var user = { id: '1', username: 'root' };
+
+ req.login(user, function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should error', function() {
+ expect(error).to.be.an.instanceOf(Error);
+ expect(error.message).to.equal('Login sessions require session support. Did you forget to use `express-session` middleware?');
+ });
+ });
+
});
@@ -342,14 +674,144 @@ describe('http.ServerRequest', function() {
describe('existing session', function() {
var passport = new Passport();
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.logout = request.logout;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
req.user = { id: '1', username: 'root' };
req._passport = {};
req._passport.instance = passport;
- req._passport.session = {};
- req._passport.session.user = '1';
+ req._sessionManager = passport._sm;
+ req.session = { id: '1' };
+ req.session['passport'] = {};
+ req.session['passport'].user = '1';
+ req.session.save = function(cb) {
+ expect(req.session['passport'].user).to.be.undefined;
+ process.nextTick(cb);
+ };
+ req.session.regenerate = function(cb) {
+ req.session = { id: '2' };
+ process.nextTick(cb);
+ };
- req.logout();
+ var error;
+
+ before(function(done) {
+ req.logout(function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should not error', function() {
+ expect(error).to.be.undefined;
+ });
+
+ it('should not be authenticated', function() {
+ expect(req.isAuthenticated()).to.be.false;
+ expect(req.isUnauthenticated()).to.be.true;
+ });
+
+ it('should clear user', function() {
+ expect(req.user).to.be.null;
+ });
+
+ it('should clear serialized user', function() {
+ expect(req.session['passport']).to.be.undefined;
+ });
+ });
+
+ describe('existing session and not keeping session data', function() {
+ var passport = new Passport();
+
+ var req = new Object();
+ req.logout = request.logout;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
+ req.user = { id: '1', username: 'root' };
+ req._passport = {};
+ req._passport.instance = passport;
+ req._sessionManager = passport._sm;
+ req.session = { cart: [ '1', '2', ] };
+ Object.defineProperty(req.session, 'id', { value: '1' });
+ req.session['passport'] = {};
+ req.session['passport'].user = '1';
+ req.session.save = function(cb) {
+ expect(req.session['passport'].user).to.be.undefined;
+ process.nextTick(cb);
+ };
+ req.session.regenerate = function(cb) {
+ req.session = { id: '2' };
+ process.nextTick(cb);
+ };
+
+ var error;
+
+ before(function(done) {
+ req.logout(function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should not error', function() {
+ expect(error).to.be.undefined;
+ });
+
+ it('should not be authenticated', function() {
+ expect(req.isAuthenticated()).to.be.false;
+ expect(req.isUnauthenticated()).to.be.true;
+ });
+
+ it('should clear user', function() {
+ expect(req.user).to.be.null;
+ });
+
+ it('should clear serialized user', function() {
+ expect(req.session['passport']).to.be.undefined;
+ });
+
+ it('should keep session data', function() {
+ expect(req.session.cart).to.be.undefined;
+ });
+ });
+
+ describe('existing session and keeping session data', function() {
+ var passport = new Passport();
+
+ var req = new Object();
+ req.logout = request.logout;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
+ req.user = { id: '1', username: 'root' };
+ req._passport = {};
+ req._passport.instance = passport;
+ req._sessionManager = passport._sm;
+ req.session = { cart: [ '1', '2', ] };
+ Object.defineProperty(req.session, 'id', { value: '1' });
+ req.session['passport'] = {};
+ req.session['passport'].user = '1';
+ req.session.save = function(cb) {
+ expect(req.session['passport'].user).to.be.undefined;
+ process.nextTick(cb);
+ };
+ req.session.regenerate = function(cb) {
+ req.session = { id: '2' };
+ process.nextTick(cb);
+ };
+
+ var error;
+
+ before(function(done) {
+ req.logout({ keepSessionInfo: true }, function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should not error', function() {
+ expect(error).to.be.undefined;
+ });
it('should not be authenticated', function() {
expect(req.isAuthenticated()).to.be.false;
@@ -361,22 +823,50 @@ describe('http.ServerRequest', function() {
});
it('should clear serialized user', function() {
- expect(req._passport.session.user).to.be.undefined;
+ expect(req.session['passport'].user).to.be.undefined;
+ });
+
+ it('should keep session data', function() {
+ expect(req.session.cart).to.deep.equal([ '1', '2' ]);
});
});
describe('existing session and clearing custom user property', function() {
var passport = new Passport();
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.logout = request.logout;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
req.currentUser = { id: '1', username: 'root' };
req._passport = {};
req._passport.instance = passport;
- req._passport.instance._userProperty = 'currentUser';
- req._passport.session = {};
- req._passport.session.user = '1';
+ req._userProperty = 'currentUser';
+ req._sessionManager = passport._sm;
+ req.session = { id: '1' };
+ req.session['passport'] = {};
+ req.session['passport'].user = '1';
+ req.session.save = function(cb) {
+ expect(req.session['passport'].user).to.be.undefined;
+ process.nextTick(cb);
+ };
+ req.session.regenerate = function(cb) {
+ req.session = { id: '2' };
+ process.nextTick(cb);
+ };
- req.logout();
+ var error;
+
+ before(function(done) {
+ req.logout(function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should not error', function() {
+ expect(error).to.be.undefined;
+ });
it('should not be authenticated', function() {
expect(req.isAuthenticated()).to.be.false;
@@ -388,12 +878,15 @@ describe('http.ServerRequest', function() {
});
it('should clear serialized user', function() {
- expect(req._passport.session.user).to.be.undefined;
+ expect(req.session['passport']).to.be.undefined;
});
});
describe('existing session, without passport.initialize() middleware', function() {
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.logout = request.logout;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
req.user = { id: '1', username: 'root' };
req.logout();
@@ -408,13 +901,199 @@ describe('http.ServerRequest', function() {
});
});
+ describe('existing session, without passport.initialize() middleware, and invoked with a callback', function() {
+ var req = new Object();
+ req.logout = request.logout;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
+ req.user = { id: '1', username: 'root' };
+
+ var error;
+
+ before(function(done) {
+ req.logout(function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should not error', function() {
+ expect(error).to.be.undefined;
+ });
+
+ it('should not be authenticated', function() {
+ expect(req.isAuthenticated()).to.be.false;
+ expect(req.isUnauthenticated()).to.be.true;
+ });
+
+ it('should clear user', function() {
+ expect(req.user).to.be.null;
+ });
+ });
+
+ describe('encountering an error saving existing session', function() {
+ var passport = new Passport();
+
+ var req = new Object();
+ req.logout = request.logout;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
+ req.user = { id: '1', username: 'root' };
+ req._passport = {};
+ req._passport.instance = passport;
+ req._sessionManager = passport._sm;
+ req.session = { id: '1' };
+ req.session['passport'] = {};
+ req.session['passport'].user = '1';
+ req.session.save = function(cb) {
+ expect(req.session['passport'].user).to.be.undefined;
+ process.nextTick(function() {
+ cb(new Error('something went wrong'));
+ });
+ };
+ req.session.regenerate = function(cb) {
+ req.session = { id: '2' };
+ process.nextTick(cb);
+ };
+
+ var error;
+
+ before(function(done) {
+ req.logout(function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should error', function() {
+ expect(error).to.be.an.instanceOf(Error);
+ expect(error.message).to.equal('something went wrong');
+ });
+
+ it('should not be authenticated', function() {
+ expect(req.isAuthenticated()).to.be.false;
+ expect(req.isUnauthenticated()).to.be.true;
+ });
+
+ it('should clear user', function() {
+ expect(req.user).to.be.null;
+ });
+
+ it('should clear serialized user', function() {
+ expect(req.session['passport'].user).to.be.undefined;
+ });
+ });
+
+ describe('encountering an error regenerating session', function() {
+ var passport = new Passport();
+
+ var req = new Object();
+ req.logout = request.logout;
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
+ req.user = { id: '1', username: 'root' };
+ req._passport = {};
+ req._passport.instance = passport;
+ req._sessionManager = passport._sm;
+ req.session = { id: '1' };
+ req.session['passport'] = {};
+ req.session['passport'].user = '1';
+ req.session.save = function(cb) {
+ expect(req.session['passport'].user).to.be.undefined;
+ process.nextTick(cb);
+ };
+ req.session.regenerate = function(cb) {
+ process.nextTick(function() {
+ cb(new Error('something went wrong'));
+ });
+ };
+
+ var error;
+
+ before(function(done) {
+ req.logout(function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should error', function() {
+ expect(error).to.be.an.instanceOf(Error);
+ expect(error.message).to.equal('something went wrong');
+ });
+
+ it('should not be authenticated', function() {
+ expect(req.isAuthenticated()).to.be.false;
+ expect(req.isUnauthenticated()).to.be.true;
+ });
+
+ it('should clear user', function() {
+ expect(req.user).to.be.null;
+ });
+
+ it('should clear serialized user', function() {
+ expect(req.session['passport'].user).to.be.undefined;
+ });
+ });
+
+ describe('existing session, but not passing a callback argument', function() {
+ var passport = new Passport();
+ passport.serializeUser(function(user, done) {
+ done(null, user.id);
+ });
+
+ var req = new Object();
+ req.logout = request.logout;
+ req._passport = {};
+ req._passport.instance = passport;
+ req._sessionManager = passport._sm;
+ req.session = {};
+ req.session['passport'] = {};
+ req.session['passport'].user = '1';
+
+ it('should throw an exception', function() {
+ expect(function() {
+ req.logout();
+ }).to.throw(Error, 'req#logout requires a callback function');
+ });
+ });
+
+ describe('without session support', function() {
+ var passport = new Passport();
+ passport.serializeUser(function(user, done) {
+ done(null, user.id);
+ });
+
+ var req = new Object();
+ req.logout = request.logout;
+ req._passport = {};
+ req._passport.instance = passport;
+ req._sessionManager = passport._sm;
+
+ var error;
+
+ before(function(done) {
+ req.logout(function(err) {
+ error = err;
+ done();
+ });
+ });
+
+ it('should error', function() {
+ expect(error).to.be.an.instanceOf(Error);
+ expect(error.message).to.equal('Login sessions require session support. Did you forget to use `express-session` middleware?');
+ });
+ });
+
});
describe('#isAuthenticated', function() {
describe('with a user', function() {
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
req.user = { id: '1', username: 'root' };
it('should be authenticated', function() {
@@ -424,11 +1103,13 @@ describe('http.ServerRequest', function() {
});
describe('with a user set on custom property', function() {
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
req.currentUser = { id: '1', username: 'root' };
req._passport = {};
req._passport.instance = {};
- req._passport.instance._userProperty = 'currentUser';
+ req._userProperty = 'currentUser';
it('should be authenticated', function() {
expect(req.isAuthenticated()).to.be.true;
@@ -437,7 +1118,9 @@ describe('http.ServerRequest', function() {
});
describe('without a user', function() {
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
it('should not be authenticated', function() {
expect(req.isAuthenticated()).to.be.false;
@@ -446,7 +1129,9 @@ describe('http.ServerRequest', function() {
});
describe('with a null user', function() {
- var req = new http.IncomingMessage();
+ var req = new Object();
+ req.isAuthenticated = request.isAuthenticated;
+ req.isUnauthenticated = request.isUnauthenticated;
req.user = null;
it('should not be authenticated', function() {
diff --git a/test/middleware/initialize.test.js b/test/middleware/initialize.test.js
index 073c4d0e..b572f93b 100644
--- a/test/middleware/initialize.test.js
+++ b/test/middleware/initialize.test.js
@@ -36,10 +36,8 @@ describe('middleware/initialize', function() {
expect(request._passport).to.be.an('object');
expect(request._passport.instance).to.be.an.instanceOf(Passport);
expect(request._passport.instance).to.equal(passport);
- });
-
- it('should not expose empty object as session storage on internal request property', function() {
- expect(request._passport.session).to.be.undefined;
+ expect(request._passport.instance._sm).to.be.an('object');
+ expect(request._passport.instance._userProperty).to.equal('user');
});
});
@@ -73,10 +71,8 @@ describe('middleware/initialize', function() {
expect(request._passport).to.be.an('object');
expect(request._passport.instance).to.be.an.instanceOf(Passport);
expect(request._passport.instance).to.equal(passport);
- });
-
- it('should not expose session storage on internal request property', function() {
- expect(request._passport.session).to.be.undefined;
+ expect(request._passport.instance._sm).to.be.an('object');
+ expect(request._passport.instance._userProperty).to.equal('user');
});
});
@@ -114,12 +110,8 @@ describe('middleware/initialize', function() {
expect(request._passport).to.be.an('object');
expect(request._passport.instance).to.be.an.instanceOf(Passport);
expect(request._passport.instance).to.equal(passport);
- });
-
- it('should expose session storage on internal request property', function() {
- expect(request._passport.session).to.be.an('object');
- expect(Object.keys(request._passport.session)).to.have.length(1);
- expect(request._passport.session.user).to.equal('123456');
+ expect(request._passport.instance._sm).to.be.an('object');
+ expect(request._passport.instance._userProperty).to.equal('user');
});
});
@@ -158,12 +150,39 @@ describe('middleware/initialize', function() {
expect(request._passport).to.be.an('object');
expect(request._passport.instance).to.be.an.instanceOf(Passport);
expect(request._passport.instance).to.equal(passport);
+ expect(request._passport.instance._sm).to.be.an('object');
+ expect(request._passport.instance._userProperty).to.equal('user');
+ });
+ });
+
+ describe('handling a request with a new session without compat mode', function() {
+ var passport = new Passport();
+ var request, error;
+
+ before(function(done) {
+ chai.connect.use(initialize(passport, { compat: false }))
+ .req(function(req) {
+ request = req;
+
+ req.session = {};
+ })
+ .next(function(err) {
+ error = err;
+ done();
+ })
+ .dispatch();
+ });
+
+ it('should not error', function() {
+ expect(error).to.be.undefined;
+ });
+
+ it('should not initialize namespace within session', function() {
+ expect(request.session.passport).to.be.undefined;
});
- it('should expose session storage on internal request property', function() {
- expect(request._passport.session).to.be.an('object');
- expect(Object.keys(request._passport.session)).to.have.length(1);
- expect(request._passport.session.user).to.equal('123456');
+ it('should expose authenticator on internal request property', function() {
+ expect(request._passport).to.be.undefined;
});
});
diff --git a/test/strategies/session.pause.test.js b/test/strategies/session.pause.test.js
index 60f80d60..20b6e07b 100644
--- a/test/strategies/session.pause.test.js
+++ b/test/strategies/session.pause.test.js
@@ -33,8 +33,9 @@ describe('SessionStrategy', function() {
req._passport = {};
req._passport.instance = {};
- req._passport.session = {};
- req._passport.session.user = '123456';
+ req.session = {};
+ req.session['passport'] = {};
+ req.session['passport'].user = '123456';
})
.authenticate({ pauseStream: true });
});
@@ -53,8 +54,8 @@ describe('SessionStrategy', function() {
});
it('should maintain session', function() {
- expect(request._passport.session).to.be.an('object');
- expect(request._passport.session.user).to.equal('123456');
+ expect(request.session['passport']).to.be.an('object');
+ expect(request.session['passport'].user).to.equal('123456');
});
it('should pause request', function() {
@@ -95,8 +96,9 @@ describe('SessionStrategy', function() {
req._passport = {};
req._passport.instance = {};
- req._passport.session = {};
- req._passport.session.user = '123456';
+ req.session = {};
+ req.session['passport'] = {};
+ req.session['passport'].user = '123456';
})
.authenticate({ pauseStream: true });
});
@@ -114,8 +116,8 @@ describe('SessionStrategy', function() {
});
it('should remove user from session', function() {
- expect(request._passport.session).to.be.an('object');
- expect(request._passport.session.user).to.be.undefined;
+ expect(request.session['passport']).to.be.an('object');
+ expect(request.session['passport'].user).to.be.undefined;
});
it('should pause request', function() {
diff --git a/test/strategies/session.test.js b/test/strategies/session.test.js
index 366a2b80..15b174ab 100644
--- a/test/strategies/session.test.js
+++ b/test/strategies/session.test.js
@@ -26,7 +26,8 @@ describe('SessionStrategy', function() {
request = req;
req._passport = {};
- req._passport.session = {};
+ req.session = {};
+ req.session['passport'] = {};
})
.authenticate();
});
@@ -58,8 +59,9 @@ describe('SessionStrategy', function() {
req._passport = {};
req._passport.instance = {};
- req._passport.session = {};
- req._passport.session.user = '123456';
+ req.session = {};
+ req.session['passport'] = {};
+ req.session['passport'].user = '123456';
})
.authenticate();
});
@@ -74,8 +76,8 @@ describe('SessionStrategy', function() {
});
it('should maintain session', function() {
- expect(request._passport.session).to.be.an('object');
- expect(request._passport.session.user).to.equal('123456');
+ expect(request.session['passport']).to.be.an('object');
+ expect(request.session['passport'].user).to.equal('123456');
});
});
@@ -97,8 +99,9 @@ describe('SessionStrategy', function() {
req._passport = {};
req._passport.instance = {};
- req._passport.session = {};
- req._passport.session.user = 0;
+ req.session = {};
+ req.session['passport'] = {};
+ req.session['passport'].user = 0;
})
.authenticate();
});
@@ -113,8 +116,8 @@ describe('SessionStrategy', function() {
});
it('should maintain session', function() {
- expect(request._passport.session).to.be.an('object');
- expect(request._passport.session.user).to.equal(0);
+ expect(request.session['passport']).to.be.an('object');
+ expect(request.session['passport'].user).to.equal(0);
});
});
@@ -136,8 +139,9 @@ describe('SessionStrategy', function() {
req._passport = {};
req._passport.instance = {};
- req._passport.session = {};
- req._passport.session.user = '123456';
+ req.session = {};
+ req.session['passport'] = {};
+ req.session['passport'].user = '123456';
})
.authenticate();
});
@@ -151,8 +155,8 @@ describe('SessionStrategy', function() {
});
it('should remove user from session', function() {
- expect(request._passport.session).to.be.an('object');
- expect(request._passport.session.user).to.be.undefined;
+ expect(request.session['passport']).to.be.an('object');
+ expect(request.session['passport'].user).to.be.undefined;
});
});
@@ -174,9 +178,10 @@ describe('SessionStrategy', function() {
req._passport = {};
req._passport.instance = {};
- req._passport.instance._userProperty = 'currentUser';
- req._passport.session = {};
- req._passport.session.user = '123456';
+ req._userProperty = 'currentUser';
+ req.session = {};
+ req.session['passport'] = {};
+ req.session['passport'].user = '123456';
})
.authenticate();
});
@@ -213,8 +218,9 @@ describe('SessionStrategy', function() {
req._passport = {};
req._passport.instance = {};
- req._passport.session = {};
- req._passport.session.user = '123456';
+ req.session = {};
+ req.session['passport'] = {};
+ req.session['passport'].user = '123456';
})
.authenticate();
});
@@ -229,8 +235,8 @@ describe('SessionStrategy', function() {
});
it('should maintain session', function() {
- expect(request._passport.session).to.be.an('object');
- expect(request._passport.session.user).to.equal('123456');
+ expect(request.session['passport']).to.be.an('object');
+ expect(request.session['passport'].user).to.equal('123456');
});
});
@@ -251,7 +257,7 @@ describe('SessionStrategy', function() {
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
- expect(error.message).to.equal('passport.initialize() middleware not in use');
+ expect(error.message).to.equal('Login sessions require session support. Did you forget to use `express-session` middleware?');
});
it('should not set user on request', function() {