Showing preview only (310K chars total). Download the full file or copy to clipboard to get everything.
Repository: jaredhanson/passport
Branch: master
Commit: 217018dbc46d
Files: 50
Total size: 294.0 KB
Directory structure:
gitextract_85ox330z/
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ └── workflows/
│ └── node.yml
├── .gitignore
├── .jshintrc
├── .npmignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── SPONSORS.md
├── etc/
│ └── jsdoc.json
├── lib/
│ ├── authenticator.js
│ ├── errors/
│ │ └── authenticationerror.js
│ ├── framework/
│ │ └── connect.js
│ ├── http/
│ │ └── request.js
│ ├── index.js
│ ├── middleware/
│ │ ├── authenticate.js
│ │ └── initialize.js
│ ├── sessionmanager.js
│ └── strategies/
│ └── session.js
├── package.json
└── test/
├── authenticator.framework.test.js
├── authenticator.middleware.test.js
├── authenticator.test.js
├── bootstrap/
│ └── node.js
├── http/
│ └── request.test.js
├── middleware/
│ ├── authenticate.error.callback.test.js
│ ├── authenticate.error.test.js
│ ├── authenticate.fail.callback.test.js
│ ├── authenticate.fail.flash.test.js
│ ├── authenticate.fail.message.test.js
│ ├── authenticate.fail.multi.test.js
│ ├── authenticate.fail.test.js
│ ├── authenticate.pass.test.js
│ ├── authenticate.redirect.test.js
│ ├── authenticate.success.callback.test.js
│ ├── authenticate.success.flash.test.js
│ ├── authenticate.success.info.test.js
│ ├── authenticate.success.message.test.js
│ ├── authenticate.success.multi.test.js
│ ├── authenticate.success.test.js
│ ├── authenticate.test.js
│ └── initialize.test.js
├── package.test.js
└── strategies/
├── session.pause.test.js
└── session.test.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
github: jaredhanson
patreon: jaredhanson
ko_fi: jaredhanson
================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
** READ THIS FIRST! **
#### Are you looking for help?
Reminder: The issue tracker is not a support forum.
Issues should only be filed in this project once they are able to be reproduced
and confirmed as a flaw in the software or incorrect information in associated
documention.
If you are encountering problems integrating this module into your application,
please post a question on the [discussion forum](https://github.com/passport/discuss)
rather than filing an issue.
#### Is this a security issue?
Do not open issues that might have security implications. Potential security
vulnerabilities should be reported privately to jaredhanson@gmail.com. Once any
vulerabilities have been repaired, the details will be disclosed publicly in a
responsible manner. This also allows time for coordinating with affected parties
in order to mitigate negative consequences.
If neither of the above two scenarios apply to your situation, you should open
an issue. Delete this paragraph and the text above, and fill in the information
requested below.
<!-- Provide a brief summary of the issue in the title field above. -->
<!-- Provide a detailed description of your use case, including as much -->
<!-- detail as possible about what you are trying to accomplish and why. -->
### Expected behavior
<!-- Provide a detailed description of how you expected the software to -->
<!-- behave. -->
### Actual behavior
<!-- Provide a detailed description of how the software actually behaved, -->
<!-- including any rationale for why that behavior is incorrect. -->
### Steps to reproduce
<!-- Provide an unambiguous series of steps that can be used to reproduce -->
<!-- this issue, including any code if applicable. -->
```js
// Format code using Markdown code blocks
```
### Environment
* Operating System:
* Node version: <!-- $ node -v -->
* passport version: <!-- $ npm list passport -->
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
** READ THIS FIRST! **
#### Are you implementing a new feature?
Requests for new features should first be discussed on the [developer forum](https://github.com/passport/develop).
This allows the community to gather feedback and assess whether or not there is
an existing way to achieve the desired functionality.
If it is determined that a new feature needs to be implemented, include a link
to the relevant discussion along with the pull request.
#### Is this a security patch?
Do not open pull requests that might have security implications. Potential
security vulnerabilities should be reported privately to jaredhanson@gmail.com.
Once any vulerabilities have been repaired, the details will be disclosed
publicly in a responsible manner. This also allows time for coordinating with
affected parties in order to mitigate negative consequences.
If neither of the above two scenarios apply to your situation, you should open
a pull request. Delete this paragraph and the text above, and fill in the
information requested below.
<!-- Provide a brief summary of the request in the title field above. -->
<!-- Provide a detailed description of your use case, including as much -->
<!-- detail as possible about what you are trying to accomplish and why. -->
<!-- If this patch closes an open issue, include a reference to the issue -->
<!-- number. -->
### Checklist
<!-- Place an `x` in the boxes that apply. If you are unsure, please ask and -->
<!-- we will help. -->
- [ ] I have read the [CONTRIBUTING](https://github.com/jaredhanson/passport/blob/master/CONTRIBUTING.md) guidelines.
- [ ] I have added test cases which verify the correct operation of this feature or patch.
- [ ] I have added documentation pertaining to this feature or patch.
- [ ] The automated test suite (`$ make test`) executes successfully.
- [ ] The automated code linting (`$ make lint`) executes successfully.
================================================
FILE: .github/workflows/node.yml
================================================
# 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
================================================
FILE: .gitignore
================================================
docs/
reports/
# Mac OS X
.DS_Store
# Node.js
node_modules
npm-debug.log
================================================
FILE: .jshintrc
================================================
{
"node": true,
"bitwise": true,
"camelcase": true,
"curly": true,
"forin": true,
"immed": true,
"latedef": true,
"newcap": true,
"noarg": true,
"noempty": true,
"nonew": true,
"quotmark": "single",
"undef": true,
"unused": true,
"trailing": true,
"laxcomma": true
}
================================================
FILE: .npmignore
================================================
CONTRIBUTING.md
Makefile
SPONSORS.md
docs/
examples/
reports/
test/
.github/
.jshintrc
.travis.yml
================================================
FILE: .travis.yml
================================================
language: "node_js"
node_js:
- "13"
- "12"
- "11"
- "10"
- "9"
- "8"
- "7"
- "6"
- "5"
- "4"
- "3" # io.js
- "2" # io.js
- "1" # io.js
- "0.12"
- "0.10"
# - "0.8"
before_install:
- "npm install make-node@0.3.x -g"
- "preinstall-compat"
script:
- "make test-cov"
after_success:
- "make report-cov"
sudo: false
================================================
FILE: CHANGELOG.md
================================================
# 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.7.0] - 2023-11-27
### Changed
- Set `req.authInfo` by default when using the `assignProperty` option to
`authenticate()` middleware. This makes the behavior the same as when not using
the option, and can be disabled by setting `authInfo` option to `false`.
## [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
================================================
FILE: CONTRIBUTING.md
================================================
## Contributing
### Tests
The test suite is located in the `test/` directory. All new features are
expected to have corresponding test cases with complete code coverage. Patches
that increase test coverage are happily accepted.
Ensure that the test suite passes by executing:
```bash
$ make test
```
Coverage reports can be generated and viewed by executing:
```bash
$ make test-cov
$ make view-cov
```
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
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
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: Makefile
================================================
include node_modules/make-node/main.mk
SOURCES = lib/*.js lib/**/*.js
TESTS = test/*.test.js test/**/*.test.js
LCOVFILE = ./reports/coverage/lcov.info
MOCHAFLAGS = --require ./test/bootstrap/node
view-docs:
open ./docs/index.html
view-cov:
open ./reports/coverage/lcov-report/index.html
clean: clean-docs clean-cov
-rm -r $(REPORTSDIR)
clobber: clean
-rm -r node_modules
html:
jsdoc -c etc/jsdoc.json -d ./doc $(SOURCES)
.PHONY: clean clobber
================================================
FILE: README.md
================================================
[](http://passportjs.org)
# Passport
Passport is [Express](http://expressjs.com/)-compatible authentication
middleware for [Node.js](http://nodejs.org/).
Passport's sole purpose is to authenticate requests, which it does through an
extensible set of plugins known as _strategies_. Passport does not mount
routes or assume any particular database schema, which maximizes flexibility and
allows application-level decisions to be made by the developer. The API is
simple: you provide Passport a request to authenticate, and Passport provides
hooks for controlling what occurs when authentication succeeds or fails.
---
<div align="center">
<sup>Sponsors</sup>
<br>
<!-- Auth0 -->
<div>
<a href="https://auth0.com/">
<picture>
<source srcset="https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/auth0.png" media="(prefers-color-scheme: light)">
<source srcset="https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/auth0-dark.png" media="(prefers-color-scheme: dark)">
<img src="https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/auth0.svg" width="275">
</picture>
<p>
<b>Simple Authentication</b>
<br>
Make login our problem. Not yours.
</p>
</a>
<p>Auth0 by Okta provides a simple and customizable login page to authenticate your users. You can dynamically add new capabilities to it - including social login, multi-factor authentication, or passkeys - without making changes to your app’s code.</p>
<p>We help protect your app and your users from attacks - defending your application from bot attacks and detecting runtime anomalies based on suspicious IPs, breached credentials, user context, and more.</p>
</div>
<br>
<!-- WorkOS -->
<div>
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=passport_js&utm_source=github">
<img src="https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/workos.png">
<p>
<b>Your app, enterprise-ready.</b>
<br>
Start selling to enterprise customers with just a few lines of code. Add Single Sign-On (and more) in minutes instead of months.
</p>
</a>
</div>
<br>
<!-- Descope -->
<div>
<a href="https://www.descope.com/?utm_source=PassportJS&utm_medium=referral&utm_campaign=oss-sponsorship">
<picture>
<source srcset="https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/descope.svg" media="(prefers-color-scheme: light)">
<source srcset="https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/descope-dark.svg" media="(prefers-color-scheme: dark)">
<img src="https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/descope.svg" width="275">
</picture>
<p>
<b>Drag and drop your auth</b>
<br>
Add authentication and user management to your consumer and business apps with a few lines of code.
</p>
</a>
</div>
<br>
<!-- FusionAuth -->
<div>
<a href="https://fusionauth.io/?utm_source=passportjs&utm_medium=referral&utm_campaign=sponsorship">
<img src="https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/fusionauth.png" width="275">
<p>
<b>Auth. Built for Devs, by Devs</b>
<br>
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.
</p>
</a>
</div>
<br>
<!-- Stytch -->
<div>
<a href="https://stytch.com?utm_source=oss-sponsorship&utm_medium=paid_sponsorship&utm_campaign=passportjs">
<picture>
<source srcset="https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/stytch.png" media="(prefers-color-scheme: light)">
<source srcset="https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/stytch-dark.png" media="(prefers-color-scheme: dark)">
<img src="https://raw.githubusercontent.com/jaredhanson/passport/master/sponsors/stytch.png" width="275">
</picture>
<p>
<b>API-first AuthN, AuthZ, and Fraud Prevention</b>
<br>
The most powerful identity platform built for developers. Easily build and secure a modern auth flow with user & org management, multi-tenant SSO, MFA, RBAC, device fingerprinting, and more.
</p>
</a>
</div>
</div>
---
Status:
[](https://travis-ci.org/jaredhanson/passport)
[](https://coveralls.io/r/jaredhanson/passport)
[](https://david-dm.org/jaredhanson/passport)
## Install
```
$ npm install passport
```
## Usage
#### Strategies
Passport uses the concept of strategies to authenticate requests. Strategies
can range from verifying username and password credentials, delegated
authentication using [OAuth](http://oauth.net/) (for example, via [Facebook](http://www.facebook.com/)
or [Twitter](http://twitter.com/)), or federated authentication using [OpenID](http://openid.net/).
Before authenticating requests, the strategy (or strategies) used by an
application must be configured.
```javascript
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.verifyPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
```
There are 480+ strategies. Find the ones you want at: [passportjs.org](http://passportjs.org)
#### Sessions
Passport will maintain persistent login sessions. In order for persistent
sessions to work, the authenticated user must be serialized to the session, and
deserialized when subsequent requests are made.
Passport does not impose any restrictions on how your user records are stored.
Instead, you provide functions to Passport which implements the necessary
serialization and deserialization logic. In a typical application, this will be
as simple as serializing the user ID, and finding the user by ID when
deserializing.
```javascript
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
```
#### Middleware
To use Passport in an [Express](http://expressjs.com/) or
[Connect](http://senchalabs.github.com/connect/)-based application, configure it
with the required `passport.initialize()` middleware. If your application uses
persistent login sessions (recommended, but not required), `passport.session()`
middleware must also be used.
```javascript
var app = express();
app.use(require('serve-static')(__dirname + '/../../public'));
app.use(require('cookie-parser')());
app.use(require('body-parser').urlencoded({ extended: true }));
app.use(require('express-session')({ secret: 'keyboard cat', resave: true, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
```
#### Authenticate Requests
Passport provides an `authenticate()` function, which is used as route
middleware to authenticate requests.
```javascript
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
```
## Strategies
Passport has a comprehensive set of **over 480** authentication strategies
covering social networking, enterprise integration, API services, and more.
## Search all strategies
There is a **Strategy Search** at [passportjs.org](http://passportjs.org)
The following table lists commonly used strategies:
|Strategy | Protocol |Developer |
|---------------------------------------------------------------|--------------------------|------------------------------------------------|
|[Local](https://github.com/jaredhanson/passport-local) | HTML form |[Jared Hanson](https://github.com/jaredhanson) |
|[OpenID](https://github.com/jaredhanson/passport-openid) | OpenID |[Jared Hanson](https://github.com/jaredhanson) |
|[BrowserID](https://github.com/jaredhanson/passport-browserid) | BrowserID |[Jared Hanson](https://github.com/jaredhanson) |
|[Facebook](https://github.com/jaredhanson/passport-facebook) | OAuth 2.0 |[Jared Hanson](https://github.com/jaredhanson) |
|[Google](https://github.com/jaredhanson/passport-google) | OpenID |[Jared Hanson](https://github.com/jaredhanson) |
|[Google](https://github.com/jaredhanson/passport-google-oauth) | OAuth / OAuth 2.0 |[Jared Hanson](https://github.com/jaredhanson) |
|[Twitter](https://github.com/jaredhanson/passport-twitter) | OAuth |[Jared Hanson](https://github.com/jaredhanson) |
|[Azure Active Directory](https://github.com/AzureAD/passport-azure-ad) | OAuth 2.0 / OpenID / SAML |[Azure](https://github.com/azuread) |
## Examples
- For a complete, working example, refer to the [example](https://github.com/passport/express-4.x-local-example)
that uses [passport-local](https://github.com/jaredhanson/passport-local).
- **Local Strategy**: Refer to the following tutorials for setting up user authentication via LocalStrategy (`passport-local`):
- Mongo
- Express v3x - [Tutorial](http://mherman.org/blog/2016/09/25/node-passport-and-postgres/#.V-govpMrJE5) / [working example](https://github.com/mjhea0/passport-local-knex)
- Express v4x - [Tutorial](http://mherman.org/blog/2015/01/31/local-authentication-with-passport-and-express-4/) / [working example](https://github.com/mjhea0/passport-local-express4)
- Postgres
- [Tutorial](http://mherman.org/blog/2015/01/31/local-authentication-with-passport-and-express-4/) / [working example](https://github.com/mjhea0/passport-local-express4)
- **Social Authentication**: Refer to the following tutorials for setting up various social authentication strategies:
- Express v3x - [Tutorial](http://mherman.org/blog/2013/11/10/social-authentication-with-passport-dot-js/) / [working example](https://github.com/mjhea0/passport-examples)
- Express v4x - [Tutorial](http://mherman.org/blog/2015/09/26/social-authentication-in-node-dot-js-with-passport) / [working example](https://github.com/mjhea0/passport-social-auth)
## Related Modules
- [Locomotive](https://github.com/jaredhanson/locomotive) — Powerful MVC web framework
- [OAuthorize](https://github.com/jaredhanson/oauthorize) — OAuth service provider toolkit
- [OAuth2orize](https://github.com/jaredhanson/oauth2orize) — OAuth 2.0 authorization server toolkit
- [connect-ensure-login](https://github.com/jaredhanson/connect-ensure-login) — middleware to ensure login sessions
The [modules](https://github.com/jaredhanson/passport/wiki/Modules) page on the
[wiki](https://github.com/jaredhanson/passport/wiki) lists other useful modules
that build upon or integrate with Passport.
## License
[The MIT License](http://opensource.org/licenses/MIT)
Copyright (c) 2011-2021 Jared Hanson <[https://www.jaredhanson.me/](https://www.jaredhanson.me/)>
================================================
FILE: SPONSORS.md
================================================
## Gold Sponsors
[](https://workos.com/)
<br>
[](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/)
================================================
FILE: etc/jsdoc.json
================================================
{
"plugins": ["plugins/markdown"]
}
================================================
FILE: lib/authenticator.js
================================================
// Module dependencies.
var SessionStrategy = require('./strategies/session')
, SessionManager = require('./sessionmanager');
/**
* Create a new `Authenticator` object.
*
* @public
* @class
*/
function Authenticator() {
this._key = 'passport';
this._strategies = {};
this._serializers = [];
this._deserializers = [];
this._infoTransformers = [];
this._framework = null;
this.init();
}
/**
* Initialize authenticator.
*
* 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({ key: this._key }, this.deserializeUser.bind(this)));
this._sm = new SessionManager({ key: this._key }, this.serializeUser.bind(this));
};
/**
* 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 <caption>Register strategy.</caption>
* passport.use(new GoogleStrategy(...));
*
* @example <caption>Register strategy and override name.</caption>
* passport.use('password', new LocalStrategy(function(username, password, cb) {
* // ...
* }));
*/
Authenticator.prototype.use = function(name, strategy) {
if (!strategy) {
strategy = name;
name = strategy.name;
}
if (!name) { throw new Error('Authentication strategies must have a name'); }
this._strategies[name] = strategy;
return this;
};
/**
* Deregister a strategy that was previously registered with the given name.
*
* 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.
*
* @public
* @param {string} name - Name of the strategy.
* @returns {this}
*
* @example
* passport.unuse('acme');
*/
Authenticator.prototype.unuse = function(name) {
delete this._strategies[name];
return this;
};
/**
* Adapt this `Authenticator` to work with a specific framework.
*
* 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.
*
* @public
* @param {Object} fw
* @returns {this}
*/
Authenticator.prototype.framework = function(fw) {
this._framework = fw;
return this;
};
/**
* 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 || {};
return this._framework.initialize(this, options);
};
/**
* Create authentication middleware.
*
* Returns middleware that authenticates the request by applying the given
* strategy (or strategies).
*
* Examples:
*
* passport.authenticate('local', function(err, user) {
* if (!user) { return res.redirect('/login'); }
* res.end('Authenticated!');
* })(req, res);
*
* @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 <caption>Authenticate username and password submitted via HTML form.</caption>
* app.get('/login/password', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' }));
*
* @example <caption>Authenticate bearer token used to access an API resource.</caption>
* app.get('/api/resource', passport.authenticate('bearer', { session: false }));
*/
Authenticator.prototype.authenticate = function(strategy, options, callback) {
return this._framework.authenticate(this, strategy, options, callback);
};
/**
* Create third-party service authorization middleware.
*
* Returns middleware that will authorize a connection to a third-party service.
*
* 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.
*
* 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.
*
* All arguments to this function behave identically to those accepted by
* `{@link Authenticator#authenticate}`.
*
* @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 || {};
options.assignProperty = 'account';
var fn = this._framework.authorize || this._framework.authenticate;
return fn(this, strategy, options, callback);
};
/**
* Middleware that will restore login state from a session.
*
* Web applications typically use sessions to maintain login state between
* requests. For example, a user will authenticate by entering credentials into
* a form which is submitted to the server. If the credentials are valid, a
* login session is established by setting a cookie containing a session
* identifier in the user's web browser. The web browser will send this cookie
* in subsequent requests to the server, allowing a session to be maintained.
*
* If sessions are being utilized, and a login session has been established,
* this middleware will populate `req.user` with the current user.
*
* Note that sessions are not strictly required for Passport to operate.
* However, as a general rule, most web applications will make use of sessions.
* An exception to this rule would be an API server, which expects each HTTP
* request to provide credentials in an Authorization header.
*
* Examples:
*
* app.use(connect.cookieParser());
* app.use(connect.session({ secret: 'keyboard cat' }));
* app.use(passport.initialize());
* app.use(passport.session());
*
* Options:
* - `pauseStream` Pause the request stream before deserializing the user
* object from the session. Defaults to _false_. Should
* be set to true in cases where middleware consuming the
* request body is configured after passport and the
* deserializeUser method is asynchronous.
*
* @param {Object} options
* @return {Function} middleware
* @api public
*/
Authenticator.prototype.session = function(options) {
return this.authenticate('session', options);
};
// TODO: Make session manager pluggable
/*
Authenticator.prototype.sessionManager = function(mgr) {
this._sm = mgr;
return this;
}
*/
/**
* Registers a function used to serialize user objects into the session.
*
* Examples:
*
* passport.serializeUser(function(user, done) {
* done(null, user.id);
* });
*
* @api public
*/
Authenticator.prototype.serializeUser = function(fn, req, done) {
if (typeof fn === 'function') {
return this._serializers.push(fn);
}
// private implementation that traverses the chain of serializers, attempting
// to serialize a user
var user = fn;
// For backwards compatibility
if (typeof req === 'function') {
done = req;
req = undefined;
}
var stack = this._serializers;
(function pass(i, err, obj) {
// serializers use 'pass' as an error to skip processing
if ('pass' === err) {
err = undefined;
}
// an error or serialized object was obtained, done
if (err || obj || obj === 0) { return done(err, obj); }
var layer = stack[i];
if (!layer) {
return done(new Error('Failed to serialize user into session'));
}
function serialized(e, o) {
pass(i + 1, e, o);
}
try {
var arity = layer.length;
if (arity == 3) {
layer(req, user, serialized);
} else {
layer(user, serialized);
}
} catch(e) {
return done(e);
}
})(0);
};
/**
* Registers a function used to deserialize user objects out of the session.
*
* Examples:
*
* passport.deserializeUser(function(id, done) {
* User.findById(id, function (err, user) {
* done(err, user);
* });
* });
*
* @api public
*/
Authenticator.prototype.deserializeUser = function(fn, req, done) {
if (typeof fn === 'function') {
return this._deserializers.push(fn);
}
// private implementation that traverses the chain of deserializers,
// attempting to deserialize a user
var obj = fn;
// For backwards compatibility
if (typeof req === 'function') {
done = req;
req = undefined;
}
var stack = this._deserializers;
(function pass(i, err, user) {
// deserializers use 'pass' as an error to skip processing
if ('pass' === err) {
err = undefined;
}
// an error or deserialized user was obtained, done
if (err || user) { return done(err, user); }
// a valid user existed when establishing the session, but that user has
// since been removed
if (user === null || user === false) { return done(null, false); }
var layer = stack[i];
if (!layer) {
return done(new Error('Failed to deserialize user out of session'));
}
function deserialized(e, u) {
pass(i + 1, e, u);
}
try {
var arity = layer.length;
if (arity == 3) {
layer(req, obj, deserialized);
} else {
layer(obj, deserialized);
}
} catch(e) {
return done(e);
}
})(0);
};
/**
* Registers a function used to transform auth info.
*
* In some circumstances authorization details are contained in authentication
* credentials or loaded as part of verification.
*
* For example, when using bearer tokens for API authentication, the tokens may
* encode (either directly or indirectly in a database), details such as scope
* of access or the client to which the token was issued.
*
* Such authorization details should be enforced separately from authentication.
* Because Passport deals only with the latter, this is the responsiblity of
* middleware or routes further along the chain. However, it is not optimal to
* decode the same data or execute the same database query later. To avoid
* this, Passport accepts optional `info` along with the authenticated `user`
* in a strategy's `success()` action. This info is set at `req.authInfo`,
* where said later middlware or routes can access it.
*
* Optionally, applications can register transforms to proccess this info,
* which take effect prior to `req.authInfo` being set. This is useful, for
* example, when the info contains a client ID. The transform can load the
* client from the database and include the instance in the transformed info,
* allowing the full set of client properties to be convieniently accessed.
*
* If no transforms are registered, `info` supplied by the strategy will be left
* unmodified.
*
* Examples:
*
* passport.transformAuthInfo(function(info, done) {
* Client.findById(info.clientID, function (err, client) {
* info.client = client;
* done(err, info);
* });
* });
*
* @api public
*/
Authenticator.prototype.transformAuthInfo = function(fn, req, done) {
if (typeof fn === 'function') {
return this._infoTransformers.push(fn);
}
// private implementation that traverses the chain of transformers,
// attempting to transform auth info
var info = fn;
// For backwards compatibility
if (typeof req === 'function') {
done = req;
req = undefined;
}
var stack = this._infoTransformers;
(function pass(i, err, tinfo) {
// transformers use 'pass' as an error to skip processing
if ('pass' === err) {
err = undefined;
}
// an error or transformed info was obtained, done
if (err || tinfo) { return done(err, tinfo); }
var layer = stack[i];
if (!layer) {
// if no transformers are registered (or they all pass), the default
// behavior is to use the un-transformed info as-is
return done(null, info);
}
function transformed(e, t) {
pass(i + 1, e, t);
}
try {
var arity = layer.length;
if (arity == 1) {
// sync
var t = layer(info);
transformed(null, t);
} else if (arity == 3) {
layer(req, info, transformed);
} else {
layer(info, transformed);
}
} catch(e) {
return done(e);
}
})(0);
};
/**
* Return strategy with given `name`.
*
* @param {String} name
* @return {Strategy}
* @api private
*/
Authenticator.prototype._strategy = function(name) {
return this._strategies[name];
};
/**
* Expose `Authenticator`.
*/
module.exports = Authenticator;
================================================
FILE: lib/errors/authenticationerror.js
================================================
/**
* `AuthenticationError` error.
*
* @constructor
* @api private
*/
function AuthenticationError(message, status) {
Error.call(this);
Error.captureStackTrace(this, arguments.callee);
this.name = 'AuthenticationError';
this.message = message;
this.status = status || 401;
}
// Inherit from `Error`.
AuthenticationError.prototype.__proto__ = Error.prototype;
// Expose constructor.
module.exports = AuthenticationError;
================================================
FILE: lib/framework/connect.js
================================================
/**
* Module dependencies.
*/
var initialize = require('../middleware/initialize')
, authenticate = require('../middleware/authenticate');
/**
* 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.
*
* @return {Object}
* @api protected
*/
exports = module.exports = function() {
return {
initialize: initialize,
authenticate: authenticate
};
};
================================================
FILE: lib/http/request.js
================================================
var req = exports = module.exports = {};
/**
* Initiate a login session for `user`.
*
* Options:
* - `session` Save login state in session, defaults to _true_
*
* Examples:
*
* req.logIn(user, { session: false });
*
* req.logIn(user, function(err) {
* if (err) { throw err; }
* // session saved
* });
*
* @param {User} user
* @param {Object} options
* @param {Function} done
* @api public
*/
req.login =
req.logIn = function(user, options, done) {
if (typeof options == 'function') {
done = options;
options = {};
}
options = options || {};
var property = this._userProperty || 'user';
var session = (options.session === undefined) ? true : options.session;
this[property] = user;
if (session && this._sessionManager) {
if (typeof done != 'function') { throw new Error('req#login requires a callback function'); }
var self = this;
this._sessionManager.logIn(this, user, options, function(err) {
if (err) { self[property] = null; return done(err); }
done();
});
} else {
done && done();
}
};
/**
* Terminate an existing login session.
*
* @api public
*/
req.logout =
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) {
if (typeof done != 'function') { throw new Error('req#logout requires a callback function'); }
this._sessionManager.logOut(this, options, done);
} else {
done && done();
}
};
/**
* Test if request is authenticated.
*
* @return {Boolean}
* @api public
*/
req.isAuthenticated = function() {
var property = this._userProperty || 'user';
return (this[property]) ? true : false;
};
/**
* Test if request is unauthenticated.
*
* @return {Boolean}
* @api public
*/
req.isUnauthenticated = function() {
return !this.isAuthenticated();
};
================================================
FILE: lib/index.js
================================================
// Module dependencies.
var Passport = require('./authenticator')
, SessionStrategy = require('./strategies/session');
/**
* Export default singleton.
*
* @api public
*/
exports = module.exports = new Passport();
/**
* Expose constructors.
*/
exports.Passport =
exports.Authenticator = Passport;
exports.Strategy = require('passport-strategy');
/*
* Expose strategies.
*/
exports.strategies = {};
exports.strategies.SessionStrategy = SessionStrategy;
================================================
FILE: lib/middleware/authenticate.js
================================================
/**
* Module dependencies.
*/
var http = require('http')
, IncomingMessageExt = require('../http/request')
, AuthenticationError = require('../errors/authenticationerror');
/**
* Authenticates requests.
*
* Applies the `name`ed strategy (or strategies) to the incoming request, in
* order to authenticate the request. If authentication is successful, the user
* will be logged in and populated at `req.user` and a session will be
* established by default. If authentication fails, an unauthorized response
* will be sent.
*
* Options:
* - `session` Save login state in session, defaults to _true_
* - `successRedirect` After successful login, redirect to given URL
* - `successMessage` True to store success message in
* req.session.messages, or a string to use as override
* message for success.
* - `successFlash` True to flash success messages or a string to use as a flash
* message for success (overrides any from the strategy itself).
* - `failureRedirect` After failed login, redirect to given URL
* - `failureMessage` True to store failure message in
* req.session.messages, or a string to use as override
* message for failure.
* - `failureFlash` True to flash failure messages or a string to use as a flash
* message for failures (overrides any from the strategy itself).
* - `assignProperty` Assign the object provided by the verify callback to given property
*
* An optional `callback` can be supplied to allow the application to override
* the default manner in which authentication attempts are handled. The
* callback has the following signature, where `user` will be set to the
* authenticated user on a successful authentication attempt, or `false`
* otherwise. An optional `info` argument will be passed, containing additional
* details provided by the strategy's verify callback - this could be information about
* a successful authentication or a challenge message for a failed authentication.
* An optional `status` argument will be passed when authentication fails - this could
* be a HTTP response code for a remote authentication failure or similar.
*
* app.get('/protected', function(req, res, next) {
* passport.authenticate('local', function(err, user, info, status) {
* if (err) { return next(err) }
* if (!user) { return res.redirect('/signin') }
* res.redirect('/account');
* })(req, res, next);
* });
*
* Note that if a callback is supplied, it becomes the application's
* responsibility to log-in the user, establish a session, and otherwise perform
* the desired operations.
*
* Examples:
*
* passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' });
*
* passport.authenticate('basic', { session: false });
*
* passport.authenticate('twitter');
*
* @param {Strategy|String|Array} name
* @param {Object} options
* @param {Function} callback
* @return {Function}
* @api public
*/
module.exports = function authenticate(passport, name, options, callback) {
if (typeof options == 'function') {
callback = options;
options = {};
}
options = options || {};
var multi = true;
// Cast `name` to an array, allowing authentication to pass through a chain of
// strategies. The first strategy to succeed, redirect, or error will halt
// the chain. Authentication failures will proceed through each strategy in
// series, ultimately failing if all strategies fail.
//
// This is typically used on API endpoints to allow clients to authenticate
// using their preferred choice of Basic, Digest, token-based schemes, etc.
// It is not feasible to construct a chain of multiple strategies that involve
// redirection (for example both Facebook and Twitter), since the first one to
// redirect will halt the chain.
if (!Array.isArray(name)) {
name = [ name ];
multi = false;
}
return function authenticate(req, res, next) {
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 = [];
function allFailed() {
if (callback) {
if (!multi) {
return callback(null, false, failures[0].challenge, failures[0].status);
} else {
var challenges = failures.map(function(f) { return f.challenge; });
var statuses = failures.map(function(f) { return f.status; });
return callback(null, false, challenges, statuses);
}
}
// Strategies are ordered by priority. For the purpose of flashing a
// message, the first failure will be displayed.
var failure = failures[0] || {}
, challenge = failure.challenge || {}
, msg;
if (options.failureFlash) {
var flash = options.failureFlash;
if (typeof flash == 'string') {
flash = { type: 'error', message: flash };
}
flash.type = flash.type || 'error';
var type = flash.type || challenge.type || 'error';
msg = flash.message || challenge.message || challenge;
if (typeof msg == 'string') {
req.flash(type, msg);
}
}
if (options.failureMessage) {
msg = options.failureMessage;
if (typeof msg == 'boolean') {
msg = challenge.message || challenge;
}
if (typeof msg == 'string') {
req.session.messages = req.session.messages || [];
req.session.messages.push(msg);
}
}
if (options.failureRedirect) {
return res.redirect(options.failureRedirect);
}
// When failure handling is not delegated to the application, the default
// is to respond with 401 Unauthorized. Note that the WWW-Authenticate
// header will be set according to the strategies in use (see
// actions#fail). If multiple strategies failed, each of their challenges
// will be included in the response.
var rchallenge = []
, rstatus, status;
for (var j = 0, len = failures.length; j < len; j++) {
failure = failures[j];
challenge = failure.challenge;
status = failure.status;
rstatus = rstatus || status;
if (typeof challenge == 'string') {
rchallenge.push(challenge);
}
}
res.statusCode = rstatus || 401;
if (res.statusCode == 401 && rchallenge.length) {
res.setHeader('WWW-Authenticate', rchallenge);
}
if (options.failWithError) {
return next(new AuthenticationError(http.STATUS_CODES[res.statusCode], rstatus));
}
res.end(http.STATUS_CODES[res.statusCode]);
}
(function attempt(i) {
var layer = name[i];
// If no more strategies exist in the chain, authentication has failed.
if (!layer) { return allFailed(); }
// Get the strategy, which will be used as prototype from which to create
// a new instance. Action functions will then be bound to the strategy
// within the context of the HTTP request/response pair.
var strategy, prototype;
if (typeof layer.authenticate == 'function') {
strategy = layer;
} else {
prototype = passport._strategy(layer);
if (!prototype) { return next(new Error('Unknown authentication strategy "' + layer + '"')); }
strategy = Object.create(prototype);
}
// ----- BEGIN STRATEGY AUGMENTATION -----
// Augment the new strategy instance with action functions. These action
// functions are bound via closure the the request/response pair. The end
// goal of the strategy is to invoke *one* of these action methods, in
// order to indicate successful or failed authentication, redirect to a
// third-party identity provider, etc.
/**
* Authenticate `user`, with optional `info`.
*
* Strategies should call this function to successfully authenticate a
* user. `user` should be an object supplied by the application after it
* has been given an opportunity to verify credentials. `info` is an
* optional argument containing additional user information. This is
* useful for third-party authentication strategies to pass profile
* details.
*
* @param {Object} user
* @param {Object} info
* @api public
*/
strategy.success = function(user, info) {
if (callback) {
return callback(null, user, info);
}
info = info || {};
var msg;
if (options.successFlash) {
var flash = options.successFlash;
if (typeof flash == 'string') {
flash = { type: 'success', message: flash };
}
flash.type = flash.type || 'success';
var type = flash.type || info.type || 'success';
msg = flash.message || info.message || info;
if (typeof msg == 'string') {
req.flash(type, msg);
}
}
if (options.successMessage) {
msg = options.successMessage;
if (typeof msg == 'boolean') {
msg = info.message || info;
}
if (typeof msg == 'string') {
req.session.messages = req.session.messages || [];
req.session.messages.push(msg);
}
}
if (options.assignProperty) {
req[options.assignProperty] = user;
if (options.authInfo !== false) {
passport.transformAuthInfo(info, req, function(err, tinfo) {
if (err) { return next(err); }
req.authInfo = tinfo;
next();
});
} else {
next();
}
return;
}
req.logIn(user, options, function(err) {
if (err) { return next(err); }
function complete() {
if (options.successReturnToOrRedirect) {
var url = options.successReturnToOrRedirect;
if (req.session && req.session.returnTo) {
url = req.session.returnTo;
delete req.session.returnTo;
}
return res.redirect(url);
}
if (options.successRedirect) {
return res.redirect(options.successRedirect);
}
next();
}
if (options.authInfo !== false) {
passport.transformAuthInfo(info, req, function(err, tinfo) {
if (err) { return next(err); }
req.authInfo = tinfo;
complete();
});
} else {
complete();
}
});
};
/**
* Fail authentication, with optional `challenge` and `status`, defaulting
* to 401.
*
* Strategies should call this function to fail an authentication attempt.
*
* @param {String} challenge
* @param {Number} status
* @api public
*/
strategy.fail = function(challenge, status) {
if (typeof challenge == 'number') {
status = challenge;
challenge = undefined;
}
// push this failure into the accumulator and attempt authentication
// using the next strategy
failures.push({ challenge: challenge, status: status });
attempt(i + 1);
};
/**
* Redirect to `url` with optional `status`, defaulting to 302.
*
* Strategies should call this function to redirect the user (via their
* user agent) to a third-party website for authentication.
*
* @param {String} url
* @param {Number} status
* @api public
*/
strategy.redirect = function(url, status) {
// NOTE: Do not use `res.redirect` from Express, because it can't decide
// what it wants.
//
// Express 2.x: res.redirect(url, status)
// Express 3.x: res.redirect(status, url) -OR- res.redirect(url, status)
// - as of 3.14.0, deprecated warnings are issued if res.redirect(url, status)
// is used
// Express 4.x: res.redirect(status, url)
// - all versions (as of 4.8.7) continue to accept res.redirect(url, status)
// but issue deprecated versions
res.statusCode = status || 302;
res.setHeader('Location', url);
res.setHeader('Content-Length', '0');
res.end();
};
/**
* Pass without making a success or fail decision.
*
* Under most circumstances, Strategies should not need to call this
* function. It exists primarily to allow previous authentication state
* to be restored, for example from an HTTP session.
*
* @api public
*/
strategy.pass = function() {
next();
};
/**
* Internal error while performing authentication.
*
* Strategies should call this function when an internal error occurs
* during the process of performing authentication; for example, if the
* user directory is not available.
*
* @param {Error} err
* @api public
*/
strategy.error = function(err) {
if (callback) {
return callback(err);
}
next(err);
};
// ----- END STRATEGY AUGMENTATION -----
strategy.authenticate(req, options);
})(0); // attempt
};
};
================================================
FILE: lib/middleware/initialize.js
================================================
/**
* Module dependencies.
*/
var IncomingMessageExt = require('../http/request');
/**
* Passport initialization.
*
* Intializes Passport for incoming requests, allowing authentication strategies
* to be applied.
*
* If sessions are being utilized, applications must set up Passport with
* functions to serialize a user into and out of a session. For example, a
* common pattern is to serialize just the user ID into the session (due to the
* fact that it is desirable to store the minimum amount of data in a session).
* When a subsequent request arrives for the session, the full User object can
* be loaded from the database by ID.
*
* Note that additional middleware is required to persist login state, so we
* must use the `connect.session()` middleware _before_ `passport.initialize()`.
*
* If sessions are being used, this middleware must be in use by the
* Connect/Express application for Passport to operate. If the application is
* entirely stateless (not using sessions), this middleware is not necessary,
* but its use will not have any adverse impact.
*
* Examples:
*
* app.use(connect.cookieParser());
* app.use(connect.session({ secret: 'keyboard cat' }));
* app.use(passport.initialize());
* app.use(passport.session());
*
* passport.serializeUser(function(user, done) {
* done(null, user.id);
* });
*
* passport.deserializeUser(function(id, done) {
* User.findById(id, function (err, user) {
* done(err, user);
* });
* });
*
* @return {Function}
* @api public
*/
module.exports = function initialize(passport, options) {
options = options || {};
return function initialize(req, res, next) {
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();
};
};
================================================
FILE: lib/sessionmanager.js
================================================
var merge = require('utils-merge');
function SessionManager(options, serializeUser) {
if (typeof options == 'function') {
serializeUser = options;
options = undefined;
}
options = options || {};
this._key = options.key || 'passport';
this._serializeUser = serializeUser;
}
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;
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);
}
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, 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;
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();
});
});
}
module.exports = SessionManager;
================================================
FILE: lib/strategies/session.js
================================================
// Module dependencies.
var pause = require('pause')
, util = require('util')
, Strategy = require('passport-strategy');
/**
* 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.
*
* 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') {
deserializeUser = options;
options = undefined;
}
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 `passport.Strategy`.
util.inherits(SessionStrategy, Strategy);
/**
* 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.
*
* 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.
*
* @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.
*
* @example
* passport.authenticate('session');
*/
SessionStrategy.prototype.authenticate = function(req, options) {
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.session[this._key]) {
su = req.session[this._key].user;
}
if (su || su === 0) {
// NOTE: Stream pausing is desirable in the case where later middleware is
// listening for events emitted from request. For discussion on the
// matter, refer to: https://github.com/jaredhanson/passport/pull/106
var paused = options.pauseStream ? pause(req) : null;
this._deserializeUser(su, req, function(err, user) {
if (err) { return self.error(err); }
if (!user) {
delete req.session[self._key].user;
} else {
var property = req._userProperty || 'user';
req[property] = user;
}
self.pass();
if (paused) {
paused.resume();
}
});
} else {
self.pass();
}
};
// Export `SessionStrategy`.
module.exports = SessionStrategy;
================================================
FILE: package.json
================================================
{
"name": "passport",
"version": "0.7.0",
"description": "Simple, unobtrusive authentication for Node.js.",
"keywords": [
"express",
"connect",
"auth",
"authn",
"authentication"
],
"author": {
"name": "Jared Hanson",
"email": "jaredhanson@gmail.com",
"url": "https://www.jaredhanson.me/"
},
"homepage": "https://www.passportjs.org/",
"repository": {
"type": "git",
"url": "git://github.com/jaredhanson/passport.git"
},
"bugs": {
"url": "https://github.com/jaredhanson/passport/issues"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jaredhanson"
},
"license": "MIT",
"licenses": [
{
"type": "MIT",
"url": "https://opensource.org/licenses/MIT"
}
],
"main": "./lib",
"dependencies": {
"passport-strategy": "1.x.x",
"pause": "0.0.1",
"utils-merge": "^1.0.1"
},
"devDependencies": {
"make-node": "0.3.x",
"mocha": "2.x.x",
"chai": "2.x.x",
"chai-connect-middleware": "0.3.x",
"chai-passport-strategy": "0.2.x",
"proxyquire": "1.4.x"
},
"engines": {
"node": ">= 0.4.0"
},
"scripts": {
"test": "node_modules/.bin/mocha --reporter spec --require test/bootstrap/node test/*.test.js test/**/*.test.js"
}
}
================================================
FILE: test/authenticator.framework.test.js
================================================
/* global describe, it, expect */
var Authenticator = require('../lib/authenticator');
describe('Authenticator', function() {
describe('#framework', function() {
describe('with an authenticate function used for authorization', function() {
var passport = new Authenticator();
passport.framework({
initialize: function() {
return function() {};
},
authenticate: function(passport, name, options) {
return function() {
return 'authenticate(): ' + name + ' ' + options.assignProperty;
};
}
});
var rv = passport.authorize('foo')();
it('should call authenticate', function() {
expect(rv).to.equal('authenticate(): foo account');
});
});
describe('with an authorize function used for authorization', function() {
var passport = new Authenticator();
passport.framework({
initialize: function() {
return function() {};
},
authenticate: function(passport, name, options) {
return function() {
return 'authenticate(): ' + name + ' ' + options.assignProperty;
};
},
authorize: function(passport, name, options) {
return function() {
return 'authorize(): ' + name + ' ' + options.assignProperty;
};
}
});
var rv = passport.authorize('foo')();
it('should call authorize', function() {
expect(rv).to.equal('authorize(): foo account');
});
});
});
});
================================================
FILE: test/authenticator.middleware.test.js
================================================
/* global describe, it, expect, before */
/* jshint expr: true */
var chai = require('chai')
, Authenticator = require('../lib/authenticator');
describe('Authenticator', function() {
describe('#initialize', function() {
it('should have correct arity', function() {
var passport = new Authenticator();
expect(passport.initialize).to.have.length(1);
});
describe('handling a request', function() {
var passport = new Authenticator();
var request, error;
before(function(done) {
chai.connect.use(passport.initialize())
.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 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);
expect(request._passport.instance._sm).to.be.an('object');
expect(request._passport.instance._userProperty).to.equal('user');
});
});
describe('handling a request with custom user property', function() {
var passport = new Authenticator();
var request, error;
before(function(done) {
chai.connect.use(passport.initialize({ userProperty: 'currentUser' }))
.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 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);
expect(request._passport.instance._sm).to.be.an('object');
expect(request._passport.instance._userProperty).to.equal('currentUser');
});
});
});
describe('#authenticate', function() {
it('should have correct arity', function() {
var passport = new Authenticator();
expect(passport.authenticate).to.have.length(3);
});
describe('handling a request', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
var user = { id: '1', username: 'jaredhanson' };
this.success(user);
};
var passport = new Authenticator();
passport.use('success', new Strategy());
var request, error;
before(function(done) {
chai.connect.use(passport.authenticate('success'))
.req(function(req) {
request = req;
req.logIn = function(user, options, done) {
this.user = user;
done();
};
})
.next(function(err) {
error = err;
done();
})
.dispatch();
});
it('should not error', function() {
expect(error).to.be.undefined;
});
it('should set user', function() {
expect(request.user).to.be.an('object');
expect(request.user.id).to.equal('1');
expect(request.user.username).to.equal('jaredhanson');
});
it('should set authInfo', function() {
expect(request.authInfo).to.be.an('object');
expect(Object.keys(request.authInfo)).to.have.length(0);
});
});
describe('handling a request with instantiated strategy', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
var user = { id: '1', username: 'jaredhanson' };
this.success(user);
};
var passport = new Authenticator();
var request, error;
before(function(done) {
chai.connect.use(passport.authenticate(new Strategy()))
.req(function(req) {
request = req;
req.logIn = function(user, options, done) {
this.user = user;
done();
};
})
.next(function(err) {
error = err;
done();
})
.dispatch();
});
it('should not error', function() {
expect(error).to.be.undefined;
});
it('should set user', function() {
expect(request.user).to.be.an('object');
expect(request.user.id).to.equal('1');
expect(request.user.username).to.equal('jaredhanson');
});
it('should set authInfo', function() {
expect(request.authInfo).to.be.an('object');
expect(Object.keys(request.authInfo)).to.have.length(0);
});
});
});
describe('#authorize', function() {
it('should have correct arity', function() {
var passport = new Authenticator();
expect(passport.authorize).to.have.length(3);
});
describe('handling a request', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
var user = { id: '1', username: 'jaredhanson' };
this.success(user);
};
var passport = new Authenticator();
passport.use('success', new Strategy());
var request, error;
before(function(done) {
chai.connect.use(passport.authorize('success'))
.req(function(req) {
request = req;
req.logIn = function(user, options, done) {
this.user = user;
done();
};
})
.next(function(err) {
error = err;
done();
})
.dispatch();
});
it('should not error', function() {
expect(error).to.be.undefined;
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should set account', function() {
expect(request.account).to.be.an('object');
expect(request.account.id).to.equal('1');
expect(request.account.username).to.equal('jaredhanson');
});
it('should set authInfo to empty object', function() {
expect(request.authInfo).to.deep.equal({});
});
});
describe('handling a request with authInfo disabled', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
var user = { id: '1', username: 'jaredhanson' };
this.success(user);
};
var passport = new Authenticator();
passport.use('success', new Strategy());
var request, error;
before(function(done) {
chai.connect.use(passport.authorize('success', { authInfo: false }))
.req(function(req) {
request = req;
req.logIn = function(user, options, done) {
this.user = user;
done();
};
})
.next(function(err) {
error = err;
done();
})
.dispatch();
});
it('should not error', function() {
expect(error).to.be.undefined;
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should set account', function() {
expect(request.account).to.be.an('object');
expect(request.account.id).to.equal('1');
expect(request.account.username).to.equal('jaredhanson');
});
it('should not set authInfo', function() {
expect(request.authInfo).to.be.undefined;
});
});
});
describe('#session', function() {
it('should have correct arity', function() {
var passport = new Authenticator();
expect(passport.session).to.have.length(1);
});
describe('handling a request', function() {
var passport = new Authenticator();
passport.deserializeUser(function(user, done) {
done(null, { id: user });
});
var request, error;
before(function(done) {
chai.connect.use(passport.session())
.req(function(req) {
request = req;
req._passport = {};
req._passport.instance = {};
req.session = {};
req.session['passport'] = {};
req.session['passport'].user = '123456';
})
.next(function(err) {
error = err;
done();
})
.dispatch();
});
it('should not error', function() {
expect(error).to.be.undefined;
});
it('should set user', function() {
expect(request.user).to.be.an('object');
expect(request.user.id).to.equal('123456');
});
it('should maintain session', function() {
expect(request.session['passport']).to.be.an('object');
expect(request.session['passport'].user).to.equal('123456');
});
});
});
});
================================================
FILE: test/authenticator.test.js
================================================
/* global describe, it, expect, before */
/* jshint expr: true, sub: true */
var Authenticator = require('../lib/authenticator');
describe('Authenticator', function() {
describe('#use', function() {
describe('with instance name', function() {
function Strategy() {
this.name = 'default';
}
Strategy.prototype.authenticate = function(req) {
};
var authenticator = new Authenticator();
authenticator.use(new Strategy());
it('should register strategy', function() {
expect(authenticator._strategies['default']).to.be.an('object');
});
});
describe('with registered name', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
};
var authenticator = new Authenticator();
authenticator.use('foo', new Strategy());
it('should register strategy', function() {
expect(authenticator._strategies['foo']).to.be.an('object');
});
});
describe('with registered name overridding instance name', function() {
function Strategy() {
this.name = 'default';
}
Strategy.prototype.authenticate = function(req) {
};
var authenticator = new Authenticator();
authenticator.use('bar', new Strategy());
it('should register strategy', function() {
expect(authenticator._strategies['bar']).to.be.an('object');
expect(authenticator._strategies['default']).to.be.undefined;
});
});
it('should throw if lacking a name', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
};
expect(function() {
var authenticator = new Authenticator();
authenticator.use(new Strategy());
}).to.throw(Error, 'Authentication strategies must have a name');
});
});
describe('#unuse', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
};
var authenticator = new Authenticator();
authenticator.use('one', new Strategy());
authenticator.use('two', new Strategy());
expect(authenticator._strategies['one']).to.be.an('object');
expect(authenticator._strategies['two']).to.be.an('object');
authenticator.unuse('one');
it('should unregister strategy', function() {
expect(authenticator._strategies['one']).to.be.undefined;
expect(authenticator._strategies['two']).to.be.an('object');
});
});
describe('#serializeUser', function() {
describe('without serializers', function() {
var authenticator = new Authenticator();
var error, obj;
before(function(done) {
authenticator.serializeUser({ id: '1', username: 'jared' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('Failed to serialize user into session');
});
it('should not serialize user', function() {
expect(obj).to.be.undefined;
});
});
describe('with one serializer', function() {
var authenticator = new Authenticator();
authenticator.serializeUser(function(user, done) {
done(null, user.id);
});
var error, obj;
before(function(done) {
authenticator.serializeUser({ id: '1', username: 'jared' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should serialize user', function() {
expect(obj).to.equal('1');
});
});
describe('with one serializer that serializes to 0', function() {
var authenticator = new Authenticator();
authenticator.serializeUser(function(user, done) {
done(null, 0);
});
var error, obj;
before(function(done) {
authenticator.serializeUser({ id: '1', username: 'jared' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should serialize user', function() {
expect(obj).to.equal(0);
});
});
describe('with one serializer that serializes to false', function() {
var authenticator = new Authenticator();
authenticator.serializeUser(function(user, done) {
done(null, false);
});
var error, obj;
before(function(done) {
authenticator.serializeUser({ id: '1', username: 'jared' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('Failed to serialize user into session');
});
it('should not serialize user', function() {
expect(obj).to.be.undefined;
});
});
describe('with one serializer that serializes to null', function() {
var authenticator = new Authenticator();
authenticator.serializeUser(function(user, done) {
done(null, null);
});
var error, obj;
before(function(done) {
authenticator.serializeUser({ id: '1', username: 'jared' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('Failed to serialize user into session');
});
it('should not serialize user', function() {
expect(obj).to.be.undefined;
});
});
describe('with one serializer that serializes to undefined', function() {
var authenticator = new Authenticator();
authenticator.serializeUser(function(user, done) {
done(null, undefined);
});
var error, obj;
before(function(done) {
authenticator.serializeUser({ id: '1', username: 'jared' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('Failed to serialize user into session');
});
it('should not serialize user', function() {
expect(obj).to.be.undefined;
});
});
describe('with one serializer that encounters an error', function() {
var authenticator = new Authenticator();
authenticator.serializeUser(function(user, done) {
done(new Error('something went wrong'));
});
var error, obj;
before(function(done) {
authenticator.serializeUser({ id: '1', username: 'jared' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('something went wrong');
});
it('should not serialize user', function() {
expect(obj).to.be.undefined;
});
});
describe('with one serializer that throws an exception', function() {
var authenticator = new Authenticator();
authenticator.serializeUser(function(user, done) {
throw new Error('something went horribly wrong');
});
var error, obj;
before(function(done) {
authenticator.serializeUser({ id: '1', username: 'jared' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('something went horribly wrong');
});
it('should not serialize user', function() {
expect(obj).to.be.undefined;
});
});
describe('with three serializers, the first of which passes and the second of which serializes', function() {
var authenticator = new Authenticator();
authenticator.serializeUser(function(user, done) {
done('pass');
});
authenticator.serializeUser(function(user, done) {
done(null, 'two');
});
authenticator.serializeUser(function(user, done) {
done(null, 'three');
});
var error, obj;
before(function(done) {
authenticator.serializeUser({ id: '1', username: 'jared' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should serialize user', function() {
expect(obj).to.equal('two');
});
});
describe('with three serializers, the first of which passes and the second of which does not serialize by no argument', function() {
var authenticator = new Authenticator();
authenticator.serializeUser(function(user, done) {
done('pass');
});
authenticator.serializeUser(function(user, done) {
done(null);
});
authenticator.serializeUser(function(user, done) {
done(null, 'three');
});
var error, obj;
before(function(done) {
authenticator.serializeUser({ id: '1', username: 'jared' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should serialize user', function() {
expect(obj).to.equal('three');
});
});
describe('with three serializers, the first of which passes and the second of which does not serialize by undefined', function() {
var authenticator = new Authenticator();
authenticator.serializeUser(function(user, done) {
done('pass');
});
authenticator.serializeUser(function(user, done) {
done(null, undefined);
});
authenticator.serializeUser(function(user, done) {
done(null, 'three');
});
var error, obj;
before(function(done) {
authenticator.serializeUser({ id: '1', username: 'jared' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should serialize user', function() {
expect(obj).to.equal('three');
});
});
describe('with one serializer that takes request as argument', function() {
var authenticator = new Authenticator();
authenticator.serializeUser(function(req, user, done) {
if (req.url !== '/foo') { return done(new Error('incorrect req argument')); }
done(null, user.id);
});
var error, obj;
before(function(done) {
var req = { url: '/foo' };
authenticator.serializeUser({ id: '1', username: 'jared' }, req, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should serialize user', function() {
expect(obj).to.equal('1');
});
});
});
describe('#deserializeUser', function() {
describe('without deserializers', function() {
var authenticator = new Authenticator();
var error, user;
before(function(done) {
authenticator.deserializeUser({ id: '1', username: 'jared' }, function(err, u) {
error = err;
user = u;
done();
});
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('Failed to deserialize user out of session');
});
it('should not deserialize user', function() {
expect(user).to.be.undefined;
});
});
describe('with one deserializer', function() {
var authenticator = new Authenticator();
authenticator.deserializeUser(function(obj, done) {
done(null, obj.username);
});
var error, user;
before(function(done) {
authenticator.deserializeUser({ id: '1', username: 'jared' }, function(err, u) {
error = err;
user = u;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should deserialize user', function() {
expect(user).to.equal('jared');
});
});
describe('with one deserializer that deserializes to false', function() {
var authenticator = new Authenticator();
authenticator.deserializeUser(function(obj, done) {
done(null, false);
});
var error, user;
before(function(done) {
authenticator.deserializeUser({ id: '1', username: 'jared' }, function(err, u) {
error = err;
user = u;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should invalidate session', function() {
expect(user).to.be.false;
});
});
describe('with one deserializer that deserializes to null', function() {
var authenticator = new Authenticator();
authenticator.deserializeUser(function(obj, done) {
done(null, null);
});
var error, user;
before(function(done) {
authenticator.deserializeUser({ id: '1', username: 'jared' }, function(err, u) {
error = err;
user = u;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should invalidate session', function() {
expect(user).to.be.false;
});
});
describe('with one deserializer that deserializes to undefined', function() {
var authenticator = new Authenticator();
authenticator.deserializeUser(function(obj, done) {
done(null, undefined);
});
var error, user;
before(function(done) {
authenticator.deserializeUser({ id: '1', username: 'jared' }, function(err, u) {
error = err;
user = u;
done();
});
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('Failed to deserialize user out of session');
});
it('should not deserialize user', function() {
expect(user).to.be.undefined;
});
});
describe('with one deserializer that encounters an error', function() {
var authenticator = new Authenticator();
authenticator.deserializeUser(function(obj, done) {
done(new Error('something went wrong'));
});
var error, user;
before(function(done) {
authenticator.deserializeUser({ id: '1', username: 'jared' }, function(err, u) {
error = err;
user = u;
done();
});
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('something went wrong');
});
it('should invalidate session', function() {
expect(user).to.be.undefined;
});
});
describe('with one deserializer that throws an exception', function() {
var authenticator = new Authenticator();
authenticator.deserializeUser(function(obj, done) {
throw new Error('something went horribly wrong');
});
var error, user;
before(function(done) {
authenticator.deserializeUser({ id: '1', username: 'jared' }, function(err, u) {
error = err;
user = u;
done();
});
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('something went horribly wrong');
});
it('should invalidate session', function() {
expect(user).to.be.undefined;
});
});
describe('with three deserializers, the first of which passes and the second of which deserializes', function() {
var authenticator = new Authenticator();
authenticator.deserializeUser(function(obj, done) {
done('pass');
});
authenticator.deserializeUser(function(obj, done) {
done(null, 'two');
});
authenticator.deserializeUser(function(obj, done) {
done(null, 'three');
});
var error, user;
before(function(done) {
authenticator.deserializeUser({ id: '1', username: 'jared' }, function(err, u) {
error = err;
user = u;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should deserialize user', function() {
expect(user).to.equal('two');
});
});
describe('with three deserializers, the first of which passes and the second of which does not deserialize by no argument', function() {
var authenticator = new Authenticator();
authenticator.deserializeUser(function(obj, done) {
done('pass');
});
authenticator.deserializeUser(function(obj, done) {
done(null);
});
authenticator.deserializeUser(function(obj, done) {
done(null, 'three');
});
var error, user;
before(function(done) {
authenticator.deserializeUser({ id: '1', username: 'jared' }, function(err, u) {
error = err;
user = u;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should deserialize user', function() {
expect(user).to.equal('three');
});
});
describe('with three deserializers, the first of which passes and the second of which does not deserialize by undefined', function() {
var authenticator = new Authenticator();
authenticator.deserializeUser(function(obj, done) {
done('pass');
});
authenticator.deserializeUser(function(obj, done) {
done(null, undefined);
});
authenticator.deserializeUser(function(obj, done) {
done(null, 'three');
});
var error, user;
before(function(done) {
authenticator.deserializeUser({ id: '1', username: 'jared' }, function(err, u) {
error = err;
user = u;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should deserialize user', function() {
expect(user).to.equal('three');
});
});
describe('with three deserializers, the first of which passes and the second of which invalidates session by false', function() {
var authenticator = new Authenticator();
authenticator.deserializeUser(function(obj, done) {
done('pass');
});
authenticator.deserializeUser(function(obj, done) {
done(null, false);
});
authenticator.deserializeUser(function(obj, done) {
done(null, 'three');
});
var error, user;
before(function(done) {
authenticator.deserializeUser({ id: '1', username: 'jared' }, function(err, u) {
error = err;
user = u;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should invalidate session', function() {
expect(user).to.be.false;
});
});
describe('with three deserializers, the first of which passes and the second of which invalidates session by null', function() {
var authenticator = new Authenticator();
authenticator.deserializeUser(function(obj, done) {
done('pass');
});
authenticator.deserializeUser(function(obj, done) {
done(null, null);
});
authenticator.deserializeUser(function(obj, done) {
done(null, 'three');
});
var error, user;
before(function(done) {
authenticator.deserializeUser({ id: '1', username: 'jared' }, function(err, u) {
error = err;
user = u;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should invalidate session', function() {
expect(user).to.be.false;
});
});
describe('with one deserializer that takes request as argument', function() {
var authenticator = new Authenticator();
authenticator.deserializeUser(function(req, obj, done) {
if (req.url !== '/foo') { return done(new Error('incorrect req argument')); }
done(null, obj.username);
});
var error, user;
before(function(done) {
var req = { url: '/foo' };
authenticator.deserializeUser({ id: '1', username: 'jared' }, req, function(err, u) {
error = err;
user = u;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should deserialize user', function() {
expect(user).to.equal('jared');
});
});
});
describe('#transformAuthInfo', function() {
describe('without transforms', function() {
var authenticator = new Authenticator();
var error, obj;
before(function(done) {
authenticator.transformAuthInfo({ clientId: '1', scope: 'write' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should not transform info', function() {
expect(Object.keys(obj)).to.have.length(2);
expect(obj.clientId).to.equal('1');
expect(obj.scope).to.equal('write');
});
});
describe('with one transform', function() {
var authenticator = new Authenticator();
authenticator.transformAuthInfo(function(info, done) {
done(null, { clientId: info.clientId, client: { name: 'Foo' }});
});
var error, obj;
before(function(done) {
authenticator.transformAuthInfo({ clientId: '1', scope: 'write' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should not transform info', function() {
expect(Object.keys(obj)).to.have.length(2);
expect(obj.clientId).to.equal('1');
expect(obj.client.name).to.equal('Foo');
expect(obj.scope).to.be.undefined;
});
});
describe('with one transform that encounters an error', function() {
var authenticator = new Authenticator();
authenticator.transformAuthInfo(function(info, done) {
done(new Error('something went wrong'));
});
var error, obj;
before(function(done) {
authenticator.transformAuthInfo({ clientId: '1', scope: 'write' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('something went wrong');
});
it('should not transform info', function() {
expect(obj).to.be.undefined;
});
});
describe('with one transform that throws an exception', function() {
var authenticator = new Authenticator();
authenticator.transformAuthInfo(function(info, done) {
throw new Error('something went horribly wrong');
});
var error, obj;
before(function(done) {
authenticator.transformAuthInfo({ clientId: '1', scope: 'write' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('something went horribly wrong');
});
it('should not transform info', function() {
expect(obj).to.be.undefined;
});
});
describe('with one sync transform', function() {
var authenticator = new Authenticator();
authenticator.transformAuthInfo(function(info) {
return { clientId: info.clientId, client: { name: 'Foo' }};
});
var error, obj;
before(function(done) {
authenticator.transformAuthInfo({ clientId: '1', scope: 'write' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should not transform info', function() {
expect(Object.keys(obj)).to.have.length(2);
expect(obj.clientId).to.equal('1');
expect(obj.client.name).to.equal('Foo');
expect(obj.scope).to.be.undefined;
});
});
describe('with three transform, the first of which passes and the second of which transforms', function() {
var authenticator = new Authenticator();
authenticator.transformAuthInfo(function(info, done) {
done('pass');
});
authenticator.transformAuthInfo(function(info, done) {
done(null, { clientId: info.clientId, client: { name: 'Two' }});
});
authenticator.transformAuthInfo(function(info, done) {
done(null, { clientId: info.clientId, client: { name: 'Three' }});
});
var error, obj;
before(function(done) {
authenticator.transformAuthInfo({ clientId: '1', scope: 'write' }, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should not transform info', function() {
expect(Object.keys(obj)).to.have.length(2);
expect(obj.clientId).to.equal('1');
expect(obj.client.name).to.equal('Two');
expect(obj.scope).to.be.undefined;
});
});
describe('with one transform that takes request as argument', function() {
var authenticator = new Authenticator();
authenticator.transformAuthInfo(function(req, info, done) {
if (req.url !== '/foo') { return done(new Error('incorrect req argument')); }
done(null, { clientId: info.clientId, client: { name: 'Foo' }});
});
var error, obj;
before(function(done) {
var req = { url: '/foo' };
authenticator.transformAuthInfo({ clientId: '1', scope: 'write' }, req, function(err, o) {
error = err;
obj = o;
done();
});
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should not transform info', function() {
expect(Object.keys(obj)).to.have.length(2);
expect(obj.clientId).to.equal('1');
expect(obj.client.name).to.equal('Foo');
expect(obj.scope).to.be.undefined;
});
});
});
});
================================================
FILE: test/bootstrap/node.js
================================================
var chai = require('chai');
chai.use(require('chai-connect-middleware'));
chai.use(require('chai-passport-strategy'));
global.$require = require('proxyquire');
global.expect = chai.expect;
================================================
FILE: test/http/request.test.js
================================================
/* global describe, it, expect, before */
/* jshint expr: true */
var request = require('../../lib/http/request')
, Passport = require('../..').Passport;
describe('http.ServerRequest', function() {
// TODO: Test that these are extended by initialize/authenticate
/*
describe('prototoype', function() {
var req = new http.IncomingMessage();
it('should be extended with login', function() {
expect(req.login).to.be.an('function');
expect(req.login).to.equal(req.logIn);
});
it('should be extended with logout', function() {
expect(req.logout).to.be.an('function');
expect(req.logout).to.equal(req.logOut);
});
it('should be extended with isAuthenticated', function() {
expect(req.isAuthenticated).to.be.an('function');
});
it('should be extended with isUnauthenticated', function() {
expect(req.isUnauthenticated).to.be.an('function');
});
});
*/
describe('#login', function() {
describe('not establishing a session', function() {
var passport = new Passport();
var req = new Object();
req.login = request.login;
req.isAuthenticated = request.isAuthenticated;
req.isUnauthenticated = request.isUnauthenticated;
req._passport = {};
req._passport.instance = passport;
req.session = {};
req.session['passport'] = {};
var error;
before(function(done) {
var user = { id: '1', username: 'root' };
req.login(user, { session: false }, 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 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 not serialize user', function() {
expect(req.session['passport'].user).to.be.undefined;
});
});
describe('not establishing a session and setting custom user property', function() {
var passport = new Passport();
var req = new Object();
req.login = request.login;
req.isAuthenticated = request.isAuthenticated;
req.isUnauthenticated = request.isUnauthenticated;
req._passport = {};
req._passport.instance = passport;
req.session = {};
req.session['passport'] = {};
req._userProperty = 'currentUser';
var error;
before(function(done) {
var user = { id: '1', username: 'root' };
req.login(user, { session: false }, 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 not set user', function() {
expect(req.user).to.be.undefined;
});
it('should set custom user', function() {
expect(req.currentUser).to.be.an('object');
expect(req.currentUser.id).to.equal('1');
expect(req.currentUser.username).to.equal('root');
});
it('should not serialize user', function() {
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 Object();
req.login = request.login;
req.isAuthenticated = request.isAuthenticated;
req.isUnauthenticated = request.isUnauthenticated;
req._passport = {};
req._passport.instance = passport;
req.session = {};
req.session['passport'] = {};
var user = { id: '1', username: 'root' };
req.login(user, { session: false });
it('should be authenticated', function() {
expect(req.isAuthenticated()).to.be.true;
expect(req.isUnauthenticated()).to.be.false;
});
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 not serialize user', function() {
expect(req.session['passport'].user).to.be.undefined;
});
});
describe('not establishing a session, without passport.initialize() middleware', function() {
var req = new Object();
req.login = request.login;
req.isAuthenticated = request.isAuthenticated;
req.isUnauthenticated = request.isUnauthenticated;
var error;
before(function(done) {
var user = { id: '1', username: 'root' };
req.login(user, { session: false }, 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 set user', function() {
expect(req.user).to.be.an('object');
expect(req.user.id).to.equal('1');
expect(req.user.username).to.equal('root');
});
});
describe('establishing a 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.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 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');
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 setting custom user property', 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.regenerate = function(cb) {
req.session = { id: '2' };
req.session.save = function(cb) {
process.nextTick(cb);
};
process.nextTick(cb);
}
req._userProperty = 'currentUser';
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 set user', function() {
expect(req.user).to.be.undefined;
});
it('should set custom user', function() {
expect(req.currentUser).to.be.an('object');
expect(req.currentUser.id).to.equal('1');
expect(req.currentUser.username).to.equal('root');
});
it('should serialize user', function() {
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;
});
});
describe('encountering an error when serializing to session', function() {
var passport = new Passport();
passport.serializeUser(function(user, done) {
done(new Error('something went wrong'));
});
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' };
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 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']).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 Object();
req.login = request.login;
var user = { id: '1', username: 'root' };
it('should throw an exception', function() {
expect(function() {
req.login(user, function(err) {});
}).to.throw(Error, 'passport.initialize() middleware not in use');
});
});
*/
describe('establishing a 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.login = request.login;
req._passport = {};
req._passport.instance = passport;
req._sessionManager = passport._sm;
req.session = {};
req.session['passport'] = {};
var user = { id: '1', username: 'root' };
it('should throw an exception', function() {
expect(function() {
req.login(user);
}).to.throw(Error, 'req#login requires a callback 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?');
});
});
});
describe('#logout', function() {
describe('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(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;
});
});
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;
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;
});
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 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._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);
};
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.currentUser).to.be.null;
});
it('should clear serialized user', function() {
expect(req.session['passport']).to.be.undefined;
});
});
describe('existing session, without passport.initialize() middleware', function() {
var req = new Object();
req.logout = request.logout;
req.isAuthenticated = request.isAuthenticated;
req.isUnauthenticated = request.isUnauthenticated;
req.user = { id: '1', username: 'root' };
req.logout();
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('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 Object();
req.isAuthenticated = request.isAuthenticated;
req.isUnauthenticated = request.isUnauthenticated;
req.user = { id: '1', username: 'root' };
it('should be authenticated', function() {
expect(req.isAuthenticated()).to.be.true;
expect(req.isUnauthenticated()).to.be.false;
});
});
describe('with a user set on custom property', function() {
var req = new Object();
req.isAuthenticated = request.isAuthenticated;
req.isUnauthenticated = request.isUnauthenticated;
req.currentUser = { id: '1', username: 'root' };
req._passport = {};
req._passport.instance = {};
req._userProperty = 'currentUser';
it('should be authenticated', function() {
expect(req.isAuthenticated()).to.be.true;
expect(req.isUnauthenticated()).to.be.false;
});
});
describe('without a user', function() {
var req = new Object();
req.isAuthenticated = request.isAuthenticated;
req.isUnauthenticated = request.isUnauthenticated;
it('should not be authenticated', function() {
expect(req.isAuthenticated()).to.be.false;
expect(req.isUnauthenticated()).to.be.true;
});
});
describe('with a null user', function() {
var req = new Object();
req.isAuthenticated = request.isAuthenticated;
req.isUnauthenticated = request.isUnauthenticated;
req.user = null;
it('should not be authenticated', function() {
expect(req.isAuthenticated()).to.be.false;
expect(req.isUnauthenticated()).to.be.true;
});
});
});
});
================================================
FILE: test/middleware/authenticate.error.callback.test.js
================================================
/* global describe, it, expect, before */
/* jshint expr: true */
var chai = require('chai')
, authenticate = require('../../lib/middleware/authenticate')
, Passport = require('../..').Passport;
describe('middleware/authenticate', function() {
describe('error with callback', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.error(new Error('something is wrong'));
};
var passport = new Passport();
passport.use('error', new Strategy());
var request, error, user;
before(function(done) {
function callback(e, u) {
error = e;
user = u;
done();
}
chai.connect.use(authenticate(passport, 'error', callback))
.req(function(req) {
request = req;
})
.dispatch();
});
it('should pass error to callback', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('something is wrong');
});
it('should pass user as undefined to callback', function() {
expect(request.user).to.be.undefined;
});
it('should not set user on request', function() {
expect(request.user).to.be.undefined;
});
});
describe('error with callback and options passed to middleware', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.error(new Error('something is wrong'));
};
var passport = new Passport();
passport.use('error', new Strategy());
var request, error, user;
before(function(done) {
function callback(e, u) {
error = e;
user = u;
done();
}
chai.connect.use(authenticate(passport, 'error', { foo: 'bar' }, callback))
.req(function(req) {
request = req;
})
.dispatch();
});
it('should pass error to callback', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('something is wrong');
});
it('should pass user as undefined to callback', function() {
expect(request.user).to.be.undefined;
});
it('should not set user on request', function() {
expect(request.user).to.be.undefined;
});
});
});
================================================
FILE: test/middleware/authenticate.error.test.js
================================================
/* global describe, it, expect, before */
/* jshint expr: true */
var chai = require('chai')
, authenticate = require('../../lib/middleware/authenticate')
, Passport = require('../..').Passport;
describe('middleware/authenticate', function() {
describe('error', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.error(new Error('something is wrong'));
};
var passport = new Passport();
passport.use('error', new Strategy());
var request, error;
before(function(done) {
chai.connect.use(authenticate(passport, 'error'))
.req(function(req) {
request = req;
})
.next(function(err) {
error = err;
done();
})
.dispatch();
});
it('should error', function() {
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('something is wrong');
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
});
});
================================================
FILE: test/middleware/authenticate.fail.callback.test.js
================================================
/* global describe, it, expect, before */
/* jshint expr: true */
var chai = require('chai')
, authenticate = require('../../lib/middleware/authenticate')
, Passport = require('../..').Passport;
describe('middleware/authenticate', function() {
describe('fail with callback', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail();
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, error, user;
before(function(done) {
function callback(e, u) {
error = e;
user = u;
done();
}
chai.connect.use(authenticate(passport, 'fail', callback))
.req(function(req) {
request = req;
})
.dispatch();
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should pass false to callback', function() {
expect(user).to.equal(false);
});
it('should not set user on request', function() {
expect(request.user).to.be.undefined;
});
});
describe('fail with callback, passing info', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ message: 'Invalid password' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, error, user, info, status;
before(function(done) {
function callback(e, u, i, s) {
error = e;
user = u;
info = i;
status = s;
done();
}
chai.connect.use(authenticate(passport, 'fail', callback))
.req(function(req) {
request = req;
})
.dispatch();
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should pass false to callback', function() {
expect(user).to.equal(false);
});
it('should pass info to callback', function() {
expect(info).to.be.an('object');
expect(info.message).to.equal('Invalid password');
});
it('should pass status to callback', function() {
expect(status).to.be.undefined;
});
it('should not set user on request', function() {
expect(request.user).to.be.undefined;
});
});
describe('fail with callback, passing info and status', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ message: 'Invalid password' }, 403);
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, error, user, info, status;
before(function(done) {
function callback(e, u, i, s) {
error = e;
user = u;
info = i;
status = s;
done();
}
chai.connect.use(authenticate(passport, 'fail', callback))
.req(function(req) {
request = req;
})
.dispatch();
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should pass false to callback', function() {
expect(user).to.equal(false);
});
it('should pass info to callback', function() {
expect(info).to.be.an('object');
expect(info.message).to.equal('Invalid password');
});
it('should pass status to callback', function() {
expect(status).to.equal(403);
});
it('should not set user on request', function() {
expect(request.user).to.be.undefined;
});
});
describe('fail with callback, passing challenge', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail('Bearer challenge');
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, error, user, challenge, status;
before(function(done) {
function callback(e, u, c, s) {
error = e;
user = u;
challenge = c;
status = s;
done();
}
chai.connect.use(authenticate(passport, 'fail', callback))
.req(function(req) {
request = req;
})
.dispatch();
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should pass false to callback', function() {
expect(user).to.equal(false);
});
it('should pass challenge to callback', function() {
expect(challenge).to.equal('Bearer challenge');
});
it('should pass status to callback', function() {
expect(status).to.be.undefined;
});
it('should not set user on request', function() {
expect(request.user).to.be.undefined;
});
});
describe('fail with callback, passing challenge and status', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail('Bearer challenge', 403);
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, error, user, challenge, status;
before(function(done) {
function callback(e, u, c, s) {
error = e;
user = u;
challenge = c;
status = s;
done();
}
chai.connect.use(authenticate(passport, 'fail', callback))
.req(function(req) {
request = req;
})
.dispatch();
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should pass false to callback', function() {
expect(user).to.equal(false);
});
it('should pass challenge to callback', function() {
expect(challenge).to.equal('Bearer challenge');
});
it('should pass status to callback', function() {
expect(status).to.equal(403);
});
it('should not set user on request', function() {
expect(request.user).to.be.undefined;
});
});
describe('fail with callback, passing status', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail(402);
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, error, user, challenge, status;
before(function(done) {
function callback(e, u, c, s) {
error = e;
user = u;
challenge = c;
status = s;
done();
}
chai.connect.use(authenticate(passport, 'fail', callback))
.req(function(req) {
request = req;
})
.dispatch();
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should pass false to callback', function() {
expect(user).to.equal(false);
});
it('should pass challenge to callback', function() {
expect(challenge).to.be.undefined;
});
it('should pass status to callback', function() {
expect(status).to.equal(402);
});
it('should not set user on request', function() {
expect(request.user).to.be.undefined;
});
});
describe('fail with callback and options passed to middleware', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail();
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, error, user;
before(function(done) {
function callback(e, u) {
error = e;
user = u;
done();
}
chai.connect.use(authenticate(passport, 'fail', { foo: 'bar' }, callback))
.req(function(req) {
request = req;
})
.dispatch();
});
it('should not error', function() {
expect(error).to.be.null;
});
it('should pass false to callback', function() {
expect(user).to.equal(false);
});
it('should not set user on request', function() {
expect(request.user).to.be.undefined;
});
});
});
================================================
FILE: test/middleware/authenticate.fail.flash.test.js
================================================
/* global describe, it, expect, before */
/* jshint expr: true */
var chai = require('chai')
, authenticate = require('../../lib/middleware/authenticate')
, Passport = require('../..').Passport;
describe('middleware/authenticate', function() {
describe('using strategy that specifies message', function() {
describe('fail with flash message', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ message: 'Invalid password' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: true,
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('error');
expect(request.message.msg).to.equal('Invalid password');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message using type set by route', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ message: 'Invalid password' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: { type: 'info' },
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('info');
expect(request.message.msg).to.equal('Invalid password');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message overridden by route as string', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ message: 'Invalid password' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: 'Wrong credentials',
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('error');
expect(request.message.msg).to.equal('Wrong credentials');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message overridden by route using options', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ message: 'Invalid password' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: { message: 'Try again' },
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('error');
expect(request.message.msg).to.equal('Try again');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message overridden by route using options with type', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ message: 'Invalid password' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: { type: 'notice', message: 'Try again' },
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('notice');
expect(request.message.msg).to.equal('Try again');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
});
describe('using strategy that specifies message and type', function() {
describe('fail with flash message', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ type: 'notice', message: 'Invite required' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: true,
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('notice');
expect(request.message.msg).to.equal('Invite required');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message using type set by route', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ type: 'notice', message: 'Invite required' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: { type: 'info' },
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('info');
expect(request.message.msg).to.equal('Invite required');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message overridden by route as string', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ type: 'notice', message: 'Invite required' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: 'Wrong credentials',
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('error');
expect(request.message.msg).to.equal('Wrong credentials');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message overridden by route using options', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ type: 'notice', message: 'Invite required' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: { message: 'Try again' },
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('error');
expect(request.message.msg).to.equal('Try again');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message overridden by route using options with type', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ type: 'notice', message: 'Invite required' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: { type: 'info', message: 'Try again' },
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('info');
expect(request.message.msg).to.equal('Try again');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
});
describe('using strategy that specifies message as string', function() {
describe('fail with flash message', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail('Access denied');
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: true,
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('error');
expect(request.message.msg).to.equal('Access denied');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message using type set by route', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail('Access denied');
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: { type: 'info' },
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('info');
expect(request.message.msg).to.equal('Access denied');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message overridden by route as string', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail('Access denied');
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: 'Wrong credentials',
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('error');
expect(request.message.msg).to.equal('Wrong credentials');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message overridden by route using options', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail('Access denied');
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: { message: 'Try again' },
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('error');
expect(request.message.msg).to.equal('Try again');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message overridden by route using options with type', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail('Access denied');
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: { type: 'notice', message: 'Try again' },
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('notice');
expect(request.message.msg).to.equal('Try again');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
});
describe('using strategy that does not specify message', function() {
describe('fail with flash message left up to strategy', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail();
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: true,
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should not flash message', function() {
expect(request.message).to.be.undefined;
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message left up to strategy using type set by route', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail();
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: { type: 'info' },
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should not flash message', function() {
expect(request.message).to.be.undefined;
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message specified by route as string', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail();
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: 'Wrong credentials',
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('error');
expect(request.message.msg).to.equal('Wrong credentials');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message specified by route using options', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail();
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: { message: 'Try again' },
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('error');
expect(request.message.msg).to.equal('Try again');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with flash message specified by route using options with type', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail();
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureFlash: { type: 'notice', message: 'Try again' },
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('notice');
expect(request.message.msg).to.equal('Try again');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
});
});
================================================
FILE: test/middleware/authenticate.fail.message.test.js
================================================
/* global describe, it, expect, before */
/* jshint expr: true */
var chai = require('chai')
, authenticate = require('../../lib/middleware/authenticate')
, Passport = require('../..').Passport;
describe('middleware/authenticate', function() {
describe('fail with message set by route', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ message: 'Invalid password' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureMessage: 'Wrong credentials',
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should add message to session', function() {
expect(request.session.messages).to.have.length(1);
expect(request.session.messages[0]).to.equal('Wrong credentials');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with message set by route that is added to messages', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ message: 'Invalid password' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureMessage: 'Wrong credentials',
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
req.session.messages = [ 'I exist!' ];
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should add message to session', function() {
expect(request.session.messages).to.have.length(2);
expect(request.session.messages[0]).to.equal('I exist!');
expect(request.session.messages[1]).to.equal('Wrong credentials');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with message set by strategy', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ message: 'Invalid password' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureMessage: true,
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should add message to session', function() {
expect(request.session.messages).to.have.length(1);
expect(request.session.messages[0]).to.equal('Invalid password');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('fail with message set by strategy with extra info', function() {
function Strategy() {
}
Strategy.prototype.authenticate = function(req) {
this.fail({ message: 'Invalid password', scope: 'read' });
};
var passport = new Passport();
passport.use('fail', new Strategy());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, 'fail', { failureMessage: true,
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.session = {};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should add message to session', function() {
expect(request.session.messages).to.have.length(1);
expect(request.session.messages[0]).to.equal('Invalid password');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
});
================================================
FILE: test/middleware/authenticate.fail.multi.test.js
================================================
/* global describe, it, expect, before */
/* jshint expr: true */
var chai = require('chai')
, authenticate = require('../../lib/middleware/authenticate')
, Passport = require('../..').Passport;
describe('middleware/authenticate', function() {
describe('with multiple strategies, all of which fail, and responding with unauthorized status', function() {
function BasicStrategy() {
}
BasicStrategy.prototype.authenticate = function(req) {
this.fail('BASIC challenge');
};
function DigestStrategy() {
}
DigestStrategy.prototype.authenticate = function(req) {
this.fail('DIGEST challenge');
};
function NoChallengeStrategy() {
}
NoChallengeStrategy.prototype.authenticate = function(req) {
this.fail();
};
var passport = new Passport();
passport.use('basic', new BasicStrategy());
passport.use('digest', new DigestStrategy());
passport.use('no-challenge', new NoChallengeStrategy());
var request, response;
before(function(done) {
chai.connect.use(authenticate(passport, ['basic', 'no-challenge', 'digest']))
.req(function(req) {
request = req;
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should respond', function() {
expect(response.statusCode).to.equal(401);
expect(response.body).to.equal('Unauthorized');
});
it('should set authenticate header on response', function() {
var val = response.getHeader('WWW-Authenticate');
expect(val).to.be.an('array');
expect(val).to.have.length(2);
expect(val[0]).to.equal('BASIC challenge');
expect(val[1]).to.equal('DIGEST challenge');
});
});
describe('with multiple strategies, all of which fail, and responding with specified status', function() {
function BasicStrategy() {
}
BasicStrategy.prototype.authenticate = function(req) {
this.fail('BASIC challenge', 400);
};
function BearerStrategy() {
}
BearerStrategy.prototype.authenticate = function(req) {
this.fail('BEARER challenge', 403);
};
function NoChallengeStrategy() {
}
NoChallengeStrategy.prototype.authenticate = function(req) {
this.fail(402);
};
var passport = new Passport();
passport.use('basic', new BasicStrategy());
passport.use('bearer', new BearerStrategy());
passport.use('no-challenge', new NoChallengeStrategy());
var request, response;
before(function(done) {
chai.connect.use(authenticate(passport, ['basic', 'no-challenge', 'bearer']))
.req(function(req) {
request = req;
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should respond', function() {
expect(response.statusCode).to.equal(400);
expect(response.getHeader('WWW-Authenticate')).to.be.undefined;
expect(response.body).to.equal('Bad Request');
});
});
describe('with multiple strategies, all of which fail, and flashing message', function() {
function StrategyA() {
}
StrategyA.prototype.authenticate = function(req) {
this.fail('A message');
};
function StrategyB() {
}
StrategyB.prototype.authenticate = function(req) {
this.fail('B message');
};
var passport = new Passport();
passport.use('a', new StrategyA());
passport.use('b', new StrategyB());
var request, response;
before(function(done) {
chai.connect.use('express', authenticate(passport, ['a', 'b'], { failureFlash: true,
failureRedirect: 'http://www.example.com/login' }))
.req(function(req) {
request = req;
req.flash = function(type, msg) {
this.message = { type: type, msg: msg };
};
})
.end(function(res) {
response = res;
done();
})
.dispatch();
});
it('should not set user', function() {
expect(request.user).to.be.undefined;
});
it('should flash message', function() {
expect(request.message.type).to.equal('error');
expect(request.message.msg).to.equal('A message');
});
it('should redirect', function() {
expect(response.statusCode).to.equal(302);
expect(response.getHeader('Location')).to.equal('http://www.example.com/login');
});
});
describe('with multiple strategies, all of which fail with unauthorized status, and invoking callback', function() {
function BasicStrategy() {
}
BasicStrategy.prototype.authenticate = function(req) {
this.fail('BASIC challenge');
};
function DigestStrategy() {
}
DigestStrategy.prototype.authenticate = function(req) {
this.fail('DIGEST challenge');
};
function NoChallengeStrategy() {
}
NoChallengeStrategy.prototype.authenticate = function(req) {
this.fail();
};
var passport = new Passport();
passport.use('basic', new BasicStrategy());
passport.use('digest', new DigestStrategy());
passport.use('no-challenge', new NoChallengeStrategy());
var request, error, user, challenge, status;
before(function(done) {
function callback(e, u, c, s) {
error = e;
user = u;
chal
gitextract_85ox330z/
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ └── workflows/
│ └── node.yml
├── .gitignore
├── .jshintrc
├── .npmignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── SPONSORS.md
├── etc/
│ └── jsdoc.json
├── lib/
│ ├── authenticator.js
│ ├── errors/
│ │ └── authenticationerror.js
│ ├── framework/
│ │ └── connect.js
│ ├── http/
│ │ └── request.js
│ ├── index.js
│ ├── middleware/
│ │ ├── authenticate.js
│ │ └── initialize.js
│ ├── sessionmanager.js
│ └── strategies/
│ └── session.js
├── package.json
└── test/
├── authenticator.framework.test.js
├── authenticator.middleware.test.js
├── authenticator.test.js
├── bootstrap/
│ └── node.js
├── http/
│ └── request.test.js
├── middleware/
│ ├── authenticate.error.callback.test.js
│ ├── authenticate.error.test.js
│ ├── authenticate.fail.callback.test.js
│ ├── authenticate.fail.flash.test.js
│ ├── authenticate.fail.message.test.js
│ ├── authenticate.fail.multi.test.js
│ ├── authenticate.fail.test.js
│ ├── authenticate.pass.test.js
│ ├── authenticate.redirect.test.js
│ ├── authenticate.success.callback.test.js
│ ├── authenticate.success.flash.test.js
│ ├── authenticate.success.info.test.js
│ ├── authenticate.success.message.test.js
│ ├── authenticate.success.multi.test.js
│ ├── authenticate.success.test.js
│ ├── authenticate.test.js
│ └── initialize.test.js
├── package.test.js
└── strategies/
├── session.pause.test.js
└── session.test.js
SYMBOL INDEX (139 symbols across 22 files)
FILE: lib/authenticator.js
function Authenticator (line 12) | function Authenticator() {
function serialized (line 300) | function serialized(e, o) {
function deserialized (line 363) | function deserialized(e, u) {
function transformed (line 450) | function transformed(e, t) {
FILE: lib/errors/authenticationerror.js
function AuthenticationError (line 7) | function AuthenticationError(message, status) {
FILE: lib/middleware/authenticate.js
function allFailed (line 107) | function allFailed() {
function complete (line 268) | function complete() {
FILE: lib/sessionmanager.js
function SessionManager (line 3) | function SessionManager(options, serializeUser) {
FILE: lib/strategies/session.js
function SessionStrategy (line 42) | function SessionStrategy(options, deserializeUser) {
FILE: test/authenticator.middleware.test.js
function Strategy (line 104) | function Strategy() {
function Strategy (line 150) | function Strategy() {
function Strategy (line 205) | function Strategy() {
function Strategy (line 254) | function Strategy() {
FILE: test/authenticator.test.js
function Strategy (line 12) | function Strategy() {
function Strategy (line 27) | function Strategy() {
function Strategy (line 41) | function Strategy() {
function Strategy (line 57) | function Strategy() {
function Strategy (line 71) | function Strategy() {
FILE: test/middleware/authenticate.error.callback.test.js
function Strategy (line 12) | function Strategy() {
function callback (line 24) | function callback(e, u) {
function Strategy (line 52) | function Strategy() {
function callback (line 64) | function callback(e, u) {
FILE: test/middleware/authenticate.error.test.js
function Strategy (line 12) | function Strategy() {
FILE: test/middleware/authenticate.fail.callback.test.js
function Strategy (line 12) | function Strategy() {
function callback (line 24) | function callback(e, u) {
function Strategy (line 51) | function Strategy() {
function callback (line 63) | function callback(e, u, i, s) {
function Strategy (line 101) | function Strategy() {
function callback (line 113) | function callback(e, u, i, s) {
function Strategy (line 151) | function Strategy() {
function callback (line 163) | function callback(e, u, c, s) {
function Strategy (line 200) | function Strategy() {
function callback (line 212) | function callback(e, u, c, s) {
function Strategy (line 249) | function Strategy() {
function callback (line 261) | function callback(e, u, c, s) {
function Strategy (line 298) | function Strategy() {
function callback (line 310) | function callback(e, u) {
FILE: test/middleware/authenticate.fail.flash.test.js
function Strategy (line 14) | function Strategy() {
function Strategy (line 59) | function Strategy() {
function Strategy (line 104) | function Strategy() {
function Strategy (line 149) | function Strategy() {
function Strategy (line 194) | function Strategy() {
function Strategy (line 244) | function Strategy() {
function Strategy (line 289) | function Strategy() {
function Strategy (line 334) | function Strategy() {
function Strategy (line 379) | function Strategy() {
function Strategy (line 424) | function Strategy() {
function Strategy (line 474) | function Strategy() {
function Strategy (line 519) | function Strategy() {
function Strategy (line 564) | function Strategy() {
function Strategy (line 609) | function Strategy() {
function Strategy (line 654) | function Strategy() {
function Strategy (line 704) | function Strategy() {
function Strategy (line 748) | function Strategy() {
function Strategy (line 792) | function Strategy() {
function Strategy (line 837) | function Strategy() {
function Strategy (line 882) | function Strategy() {
FILE: test/middleware/authenticate.fail.message.test.js
function Strategy (line 12) | function Strategy() {
function Strategy (line 53) | function Strategy() {
function Strategy (line 96) | function Strategy() {
function Strategy (line 137) | function Strategy() {
FILE: test/middleware/authenticate.fail.multi.test.js
function BasicStrategy (line 12) | function BasicStrategy() {
function DigestStrategy (line 18) | function DigestStrategy() {
function NoChallengeStrategy (line 24) | function NoChallengeStrategy() {
function BasicStrategy (line 73) | function BasicStrategy() {
function BearerStrategy (line 79) | function BearerStrategy() {
function NoChallengeStrategy (line 85) | function NoChallengeStrategy() {
function StrategyA (line 126) | function StrategyA() {
function StrategyB (line 132) | function StrategyB() {
function BasicStrategy (line 177) | function BasicStrategy() {
function DigestStrategy (line 183) | function DigestStrategy() {
function NoChallengeStrategy (line 189) | function NoChallengeStrategy() {
function callback (line 203) | function callback(e, u, c, s) {
function BasicStrategy (line 248) | function BasicStrategy() {
function BearerStrategy (line 254) | function BearerStrategy() {
function NoChallengeStrategy (line 260) | function NoChallengeStrategy() {
function callback (line 274) | function callback(e, u, c, s) {
function BasicStrategy (line 319) | function BasicStrategy() {
function callback (line 331) | function callback(e, u, c, s) {
FILE: test/middleware/authenticate.fail.test.js
function Strategy (line 12) | function Strategy() {
function Strategy (line 47) | function Strategy() {
function Strategy (line 81) | function Strategy() {
function Strategy (line 123) | function Strategy() {
function Strategy (line 158) | function Strategy() {
function Strategy (line 193) | function Strategy() {
function Strategy (line 238) | function Strategy() {
function Strategy (line 283) | function Strategy() {
function Strategy (line 328) | function Strategy() {
function Strategy (line 380) | function Strategy() {
function Strategy (line 425) | function Strategy() {
FILE: test/middleware/authenticate.pass.test.js
function Strategy (line 12) | function Strategy() {
FILE: test/middleware/authenticate.redirect.test.js
function Strategy (line 12) | function Strategy() {
function Strategy (line 47) | function Strategy() {
function Strategy (line 82) | function Strategy() {
function Strategy (line 116) | function Strategy() {
FILE: test/middleware/authenticate.success.callback.test.js
function Strategy (line 12) | function Strategy() {
function callback (line 25) | function callback(e, u, i) {
function Strategy (line 64) | function Strategy() {
function callback (line 77) | function callback(e, u, i) {
FILE: test/middleware/authenticate.success.flash.test.js
function Strategy (line 14) | function Strategy() {
function Strategy (line 66) | function Strategy() {
function Strategy (line 118) | function Strategy() {
function Strategy (line 170) | function Strategy() {
function Strategy (line 222) | function Strategy() {
function Strategy (line 279) | function Strategy() {
function Strategy (line 331) | function Strategy() {
function Strategy (line 383) | function Strategy() {
function Strategy (line 435) | function Strategy() {
function Strategy (line 487) | function Strategy() {
function Strategy (line 544) | function Strategy() {
function Strategy (line 596) | function Strategy() {
function Strategy (line 648) | function Strategy() {
function Strategy (line 700) | function Strategy() {
function Strategy (line 752) | function Strategy() {
function Strategy (line 809) | function Strategy() {
function Strategy (line 860) | function Strategy() {
function Strategy (line 911) | function Strategy() {
function Strategy (line 963) | function Strategy() {
function Strategy (line 1015) | function Strategy() {
FILE: test/middleware/authenticate.success.info.test.js
function Strategy (line 12) | function Strategy() {
function Strategy (line 60) | function Strategy() {
function Strategy (line 112) | function Strategy() {
function Strategy (line 161) | function Strategy() {
FILE: test/middleware/authenticate.success.message.test.js
function Strategy (line 11) | function Strategy() {
function Strategy (line 60) | function Strategy() {
function Strategy (line 111) | function Strategy() {
function Strategy (line 160) | function Strategy() {
FILE: test/middleware/authenticate.success.multi.test.js
function StrategyA (line 12) | function StrategyA() {
function StrategyB (line 18) | function StrategyB() {
function StrategyA (line 58) | function StrategyA() {
function StrategyB (line 64) | function StrategyB() {
FILE: test/middleware/authenticate.success.test.js
function Strategy (line 12) | function Strategy() {
function Strategy (line 58) | function Strategy() {
function Strategy (line 107) | function Strategy() {
function Strategy (line 156) | function Strategy() {
function Strategy (line 207) | function Strategy() {
function Strategy (line 254) | function Strategy() {
function Strategy (line 306) | function Strategy() {
function Strategy (line 353) | function Strategy() {
Condensed preview — 50 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (314K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 60,
"preview": "github: jaredhanson\npatreon: jaredhanson\nko_fi: jaredhanson\n"
},
{
"path": ".github/ISSUE_TEMPLATE.md",
"chars": 1897,
"preview": "** READ THIS FIRST! **\n\n#### Are you looking for help?\n\nReminder: The issue tracker is not a support forum.\n\nIssues shou"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 1906,
"preview": "** READ THIS FIRST! **\n\n#### Are you implementing a new feature?\n\nRequests for new features should first be discussed on"
},
{
"path": ".github/workflows/node.yml",
"chars": 969,
"preview": "# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests ac"
},
{
"path": ".gitignore",
"chars": 75,
"preview": "docs/\nreports/\n\n# Mac OS X\n.DS_Store\n\n# Node.js\nnode_modules\nnpm-debug.log\n"
},
{
"path": ".jshintrc",
"chars": 299,
"preview": "{\n \"node\": true,\n \"bitwise\": true,\n \"camelcase\": true,\n \"curly\": true,\n \"forin\": true,\n \"immed\": true,\n \"latedef\""
},
{
"path": ".npmignore",
"chars": 100,
"preview": "CONTRIBUTING.md\nMakefile\nSPONSORS.md\ndocs/\nexamples/\nreports/\ntest/\n\n.github/\n.jshintrc\n.travis.yml\n"
},
{
"path": ".travis.yml",
"chars": 353,
"preview": "language: \"node_js\"\nnode_js:\n - \"13\"\n - \"12\"\n - \"11\"\n - \"10\"\n - \"9\"\n - \"8\"\n - \"7\"\n - \"6\"\n - \"5\"\n - \"4\"\n - \"3\""
},
{
"path": "CHANGELOG.md",
"chars": 2990,
"preview": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changel"
},
{
"path": "CONTRIBUTING.md",
"chars": 411,
"preview": "## Contributing\n\n### Tests\n\nThe test suite is located in the `test/` directory. All new features are\nexpected to have c"
},
{
"path": "LICENSE",
"chars": 1084,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2011-2021 Jared Hanson\n\nPermission is hereby granted, free of charge, to any person"
},
{
"path": "Makefile",
"chars": 460,
"preview": "include node_modules/make-node/main.mk\n\n\nSOURCES = lib/*.js lib/**/*.js\nTESTS = test/*.test.js test/**/*.test.js\n\nLCOVFI"
},
{
"path": "README.md",
"chars": 11590,
"preview": "[](http://passportjs.org)\n\n# Passport\n\nPassport i"
},
{
"path": "SPONSORS.md",
"chars": 495,
"preview": "## Gold Sponsors\n\n[](https:/"
},
{
"path": "etc/jsdoc.json",
"chars": 38,
"preview": "{\n \"plugins\": [\"plugins/markdown\"]\n}\n"
},
{
"path": "lib/authenticator.js",
"chars": 15334,
"preview": "// Module dependencies.\nvar SessionStrategy = require('./strategies/session')\n , SessionManager = require('./sessionman"
},
{
"path": "lib/errors/authenticationerror.js",
"chars": 438,
"preview": "/**\n * `AuthenticationError` error.\n *\n * @constructor\n * @api private\n */\nfunction AuthenticationError(message, status)"
},
{
"path": "lib/framework/connect.js",
"chars": 504,
"preview": "/**\n * Module dependencies.\n */\nvar initialize = require('../middleware/initialize')\n , authenticate = require('../midd"
},
{
"path": "lib/http/request.js",
"chars": 2010,
"preview": "var req = exports = module.exports = {};\n\n/**\n * Initiate a login session for `user`.\n *\n * Options:\n * - `session` S"
},
{
"path": "lib/index.js",
"chars": 465,
"preview": "// Module dependencies.\nvar Passport = require('./authenticator')\n , SessionStrategy = require('./strategies/session');"
},
{
"path": "lib/middleware/authenticate.js",
"chars": 14126,
"preview": "/**\n * Module dependencies.\n */\nvar http = require('http')\n , IncomingMessageExt = require('../http/request')\n , Authe"
},
{
"path": "lib/middleware/initialize.js",
"chars": 4133,
"preview": "/**\n * Module dependencies.\n */\nvar IncomingMessageExt = require('../http/request');\n\n\n/**\n * Passport initialization.\n "
},
{
"path": "lib/sessionmanager.js",
"chars": 2516,
"preview": "var merge = require('utils-merge');\n\nfunction SessionManager(options, serializeUser) {\n if (typeof options == 'function"
},
{
"path": "lib/strategies/session.js",
"chars": 4950,
"preview": "// Module dependencies.\nvar pause = require('pause')\n , util = require('util')\n , Strategy = require('passport-strateg"
},
{
"path": "package.json",
"chars": 1287,
"preview": "{\n \"name\": \"passport\",\n \"version\": \"0.7.0\",\n \"description\": \"Simple, unobtrusive authentication for Node.js.\",\n \"key"
},
{
"path": "test/authenticator.framework.test.js",
"chars": 1580,
"preview": "/* global describe, it, expect */\n\nvar Authenticator = require('../lib/authenticator');\n\n\ndescribe('Authenticator', func"
},
{
"path": "test/authenticator.middleware.test.js",
"chars": 10009,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , Authenticator = requir"
},
{
"path": "test/authenticator.test.js",
"chars": 28215,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true, sub: true */\n\nvar Authenticator = require('../lib/authen"
},
{
"path": "test/bootstrap/node.js",
"chars": 191,
"preview": "var chai = require('chai');\n\nchai.use(require('chai-connect-middleware'));\nchai.use(require('chai-passport-strategy'));\n"
},
{
"path": "test/http/request.test.js",
"chars": 34538,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar request = require('../../lib/http/request')\n , P"
},
{
"path": "test/middleware/authenticate.error.callback.test.js",
"chars": 2335,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.error.test.js",
"chars": 1074,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.fail.callback.test.js",
"chars": 8132,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.fail.flash.test.js",
"chars": 29346,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.fail.message.test.js",
"chars": 5426,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.fail.multi.test.js",
"chars": 10594,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.fail.test.js",
"chars": 12760,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.pass.test.js",
"chars": 972,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.redirect.test.js",
"chars": 3932,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.success.callback.test.js",
"chars": 3009,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.success.flash.test.js",
"chars": 35678,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.success.info.test.js",
"chars": 5797,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.success.message.test.js",
"chars": 6634,
"preview": "/* global describe, it, expect, before */\n\nvar chai = require('chai')\n , authenticate = require('../../lib/middleware/a"
},
{
"path": "test/middleware/authenticate.success.multi.test.js",
"chars": 2560,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.success.test.js",
"chars": 11134,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/authenticate.test.js",
"chars": 1268,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , authenticate = require"
},
{
"path": "test/middleware/initialize.test.js",
"chars": 5813,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , initialize = require('"
},
{
"path": "test/package.test.js",
"chars": 634,
"preview": "/* global describe, it, expect */\n\nvar passport = require('..');\n\ndescribe('passport', function() {\n \n it('should expo"
},
{
"path": "test/strategies/session.pause.test.js",
"chars": 3728,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai');\n\n\ndescribe('SessionStrate"
},
{
"path": "test/strategies/session.test.js",
"chars": 7204,
"preview": "/* global describe, it, expect, before */\n/* jshint expr: true */\n\nvar chai = require('chai')\n , SessionStrategy = requ"
}
]
About this extraction
This page contains the full source code of the jaredhanson/passport GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 50 files (294.0 KB), approximately 66.7k tokens, and a symbol index with 139 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.